How to handle Android LiveData(ViewModel) with ProgressBar on screen rotate? - android

onChanged I am updating the UI and cancelling the progressDialog but each time I am rotating the screen the progress dialog shows up and ProgressDialog doesn't dismiss.
How to handle the progressdialog if the data is not changed?
final ProgressDialog pd;
pd=new ProgressDialog(mContext);
pd.setMessage(mContext.getString(R.string.updating));
pd.show();MutableLiveData<BillGetResponse> DisplayByIdLiveData=viewModelForBillDisplay.getBillGetResponseDisplayById(txnRequest);
if (display_by_id) {
DisplayByIdLiveData.observe(BillDisplayFragment.this, new Observer<BillGetResponse>() {
#Override
public void onChanged(#Nullable BillGetResponse billGetResponse) {
if (btnRecordDisableEnabled != null)
btnRecordDisableEnabled.enable();
pd.dismiss(); }
but everytime the onChanged is not trigerred and the progressdialog doesnot stop !!

You need other observer to handle the value of the boolean that indicates if you have to show the ProgressDialog or not. This is the code:
viewModel.getIsLoading().observe(this, new Observer<Boolean>() {
#Override
public void onChanged(#Nullable Boolean aBoolean) {
if(aBoolean){
pd.show();
}else{
pd.dismiss();
}
}
});
In your viewModel add getIsLoading method:
public LiveData<Boolean> getIsLoading(){
LiveData<Boolean> isLoading=yourRepository.getIsLoading();
return isLoading;
}
And in your repository add:
private final MutableLiveData<Boolean> isLoading=new MutableLiveData<>();
and set value to isLoading when start and finish the data upload.
I hope it helps you.

onChanged() not getting called is perfectly normal, it means there are no more changes in data.
I guess you want to show ProgressDialog while data is being fetched or loaded. You can do something like this
In onCreate() Check data is present or not before displaying, below in Pseudo code for displaying ProgressDialog
if (!hasData())
displayProgressDialog()
EDIT:
It seems you want to inform user that data has changed by means of showing ProgressDialog, You can achieve this by showing this for small moment and dismiss it after a while, Something like this in onChanged()
#Override
public void onChanged(#Nullable BillGetResponse billGetResponse) {
if (btnRecordDisableEnabled != null)
btnRecordDisableEnabled.enable();
displayProgressDialog(); //Show progress dialog here
new Handler().postDelayed(new Runnable(){
#Override
public void run() {
pd.dismiss();
}
},500);
}

Related

Error while trying to restore a savedInstance - Android

I'm having the following problem while trying to restore a ProgressDialog from a configuration change. This is my code:
server is a class that does some networking in a thread and after it finishes, it calls the callback on the handler that made the initial call.
public class MainActivity extends FragmentActivity {
private boolean hasAuthDialog = false;
ProgressDialog progressDialog;
// login fragment
public void doLogin(View b) {
boolean ok = true;
if(ok) {
progressDialog = new ProgressDialog(this);
progressDialog.setIndeterminate(true);
progressDialog.setMessage("Autenticando");
progressDialog.setCancelable(false);
progressDialog.show();
hasAuthDialog = true;
try {
server.doLogin(cedula.getText().toString(), pass.getText().toString(), new ServerBridgeResponse_CallBack() {
#Override
public void run(Boolean success, Object... args) {
// login finalizado
if(success) {
Toast.makeText(me, "Login success", Toast.LENGTH_LONG).show();
}else{
Toast.makeText(me, "Login error", Toast.LENGTH_LONG).show();
}
progressDialog.dismiss();
hasAuthDialog = false;
}
});
} catch (ServerBridgeNotReadyException e) {
}
}
}
}
#Override
protected void onSaveInstanceState(Bundle outState) {
outState.putBoolean("hasAuthDialog", hasAuthDialog);
}
#Override
protected void onRestoreInstanceState(Bundle savedInstanceState) {
hasAuthDialog = savedInstanceState.getBoolean("hasAuthDialog");
if(hasAuthDialog) {
progressDialog = new ProgressDialog(this);
progressDialog.setIndeterminate(true);
progressDialog.setMessage("Autenticando restored");
progressDialog.setCancelable(false);
progressDialog.show();
hasAuthDialog = true;
}
}
The thing is that after an orientation change, when debugging, progressDialog in the doLogin method still refers to the old dialog and not the new one that I created in onRestoreInstance (I know this because of the message. It still says 'Autenticando' instead of 'Autenticando Restored'). What am I doing wrong?
Thanks in advance!
Have you tried making progressDialog static? That way the set variable will be dismissed by the run method, and not the reference to the old progressDialog.
I get it now. The thing is that when there's an orientation change, Android creates an entirely new instance of the activity. Because of this behavior, the keyword this in the callback refers to the previous instance.
One way we could fix this problem is by making the progressDialog static as suggested by Bassiuz, but one different (and IMO more flexible) solution would be to create an static MainActivity me variable and assigning it this at the end of onCreate. After that, in doLogin callback, use me.progressDialog and it should have the reference to the new dialog.
Thanks to Bassiuz!

How to display a dialog to wait for user to continue in an AsyncTask?

I have an AsyncTask that does a bunch of stuff in the doInBackground() portion, and in between that bunch of stuff, I need to wait for the user to physically do something before I can continue. How do I popup some dialog for the user to click OK before continuing?
Thanks!
in between that bunch of stuff, I need to wait for the user to
physically do something before I can continue.
You aren't supposed to do that in doInBackground method, You need to do that in onPostExecute(); Interaction with the user should be done in onPostExecute.
What you can do here?
Divide your code in 2 parts, perform the code that has to be done until users Interaction in the background in doInBackground, make user Interact do that in onPostExecute, after that for rest of remaining code you can use another AsyncTask.
class LoadData extends AsyncTask<Object, Object, Object>
{
#Override
protected Object doInBackground(Object... p_params)
{
// Your background code
return null;
}
#Override
protected void onPreExecute()
{
// Display Progress dialog with cancelable false
super.onPreExecute();
}
#Override
protected void onPostExecute(Object p_result)
{
// Dismiss Progress dialog
super.onPostExecute(p_result);
}
}
If you want to put wait dialog in between doInBackground section then you can try following code:
#Override
protected Void doInBackground(Void... params) {
activity.runOnUiThread(new Runnable() {
#Override
public void run() {
final Dialog dialog = new Dialog(activity);
dialog.setTitle("Demo");
Button button = new Button(activity);
button.setText("Press For Process..");
dialog.setContentView(button);
button.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
Toast.makeText(activity, "Perform Task",
Toast.LENGTH_LONG).show();
// You can perform task whatever want to do after
// on user press the button
dialog.dismiss();
}
});
dialog.show();
}
});
return null;
}

How to make asynctask work properly

I have a button on my app, if the user click it, it will refresh the current page by calling onResume(), and there are lots of database operations in onResume(). Instead of keeping the button stay pressed for a while, I would like to use asynctask to make a progressdialog while loading the data. But the problem is that the button will still be in pressed state and the progressdialog only show at the end of the operation for a very short duration.
RefreshButton.setOnClickListener(new OnClickListener()
{
public void onClick(View v)
{
onResume();
}
});
protected void onResume()
{
doneloading = false;
monResumeloading = new onResumeloading();
monResumeloading.execute();
....loading...
doneloading = true;
}
private class onResumeloading extends AsyncTask<Integer, Integer, String>
{
private ProgressDialog progressDialog;
#Override
protected void onPostExecute(String result)
{
progressDialog.dismiss();
}
#Override
protected void onPreExecute()
{
progressDialog = new ProgressDialog(StatisticsActivity.this);
progressDialog.setMessage("Loading...");
progressDialog.setCancelable(true);
progressDialog.show();
Log.i(TAG, " doneloading=false");
}
#Override
protected void onProgressUpdate(Integer... values)
{
}
#Override
protected String doInBackground(Integer... params)
{
while(!doneloading)
{
publishProgress(0); //dummy
log.i(TAG, "loading");
}
return null;
}
}
I observed that the "loading" log is showing right after the asynctask execution and stop right after the boolean doneloading becomes false. But the progressdialog is not working properly. Please help me :(
First thing, I don't think you should be calling your AsyncTask in the onResume() function. You can simply call it from your ClickListener.
Right now, you are doing your '....loading...' code before you even execute your AsyncTask. That's why the button stays pressed while it's executing '....loading...' and then when it's done, it executes your AsyncTask which really isn't doing anything - that's why it just shows up for a short duration.
Move your '....loading...' code into your doInBackground() of your AsyncTask and it should work ok.
Summary:
Click: Execute AsyncTask
AsyncTask: opens ProgressDialog
AsyncTask: Executes your '...loading...' code
AsyncTask: Wait for '...loading...' code to complete while still displaying dialog.
AsyncTask: Dismiss ProgressDialog

Android: Problems with ProgressDialog

Dear Android hackers,
I am trying to do the following in my Android App: When the User clicks on a list item in a ListActivity, a ProgressDialog should show up, some preloading should happen and after it's done, another Activity should be called using an intent.
I tried different approaches. What didn't work at all was using an Async Task. Apparently I cannot show, dismiss or edit my ProgressDialog out of the Async Task, if that Class is not a Member of my original Activity.
I switched to a simple Thread then, this is how I'm trying to do it:
dialog = ProgressDialog.show(BookmarkActivity.this, "", "Loading...",true);
new Thread() {
public void run() {
// do something
dialog.setMessage("Change Message...");
// do more
dialog.dismiss();
// ...
Intent intent = new Intent(BookmarkActivity.this, ThreadActivity.class);
BookmarkActivity.this.startActivity(intent);
}
}.start();
This works almost, but the changing of the dialog message does not. I'm getting errors saying something about "leaked windows". (I can post the complete log if it is needed).
My questions:
How can I use an Async Task for this, where the Class has it's own file?
How can I change the ProgressDialog out of my Thread or AsyncTask without causing an error for changing the UI in another thread?
Thanks in advance, Jan Oliver
Ok, with the help of Jason, I put together this Async Task. That works!
public class ThreadPreLoader extends AsyncTask<Object, String, Void> {
private Activity mActivity;
private ProgressDialog mDialog;
public ThreadPreLoader(Activity activity) {
mActivity = activity;
}
protected void onPreExecute() {
mDialog = new ProgressDialog(mActivity);
mDialog.setMessage("Loading...");
mDialog.show();
}
protected Void doInBackground(Object... args) {
publishProgress("Loading something else..");
return null;
}
protected void onProgressUpdate(String... msg) {
mDialog.setMessage(msg[0]);
}
protected void onPostExecute(Void result) {
mDialog.dismiss();
}
}
Thanks again, Jason.
You should use an Async Task, Define a custom Async Task which receives the context (this) of the original activity.
Then keep that context for later Dismissing the dialog.
From your doInBackground() method you can call postProgress( int progress) which will cause onProgressUpdate() to be called in the async task , this method is on the UI thread so it will not cause cross thread errors.
Once doInBackground() is complete the method onComplete() will also be called on the UI thread, this is where you can use your saved context and dissmiss the dialog (context.dissmissDialog()
Take a look at Android's Handler class. If you create the Handler in the onCreate method of your activity, Runnables that are sent to the post method of the handler are then run on the UI thread of your activity:
Handler h;
protected void onCreate(Bundle bundle) {
h = new Handler;
new Thread() {
public void run() {
// your run code
h.post(new Runnable() { /* change dialog here */ });
}
}.start();
}
I'm not sure that's the best option, but worth a try.
In AsyncTask
You should do you work which need time in doInBackground and calling intent like things, that you need to do after this task should be in onPostExecute
public class ThreadPreLoader extends AsyncTask<Object, String, Void> {
private Activity mActivity;
private ProgressDialog mDialog;
public ThreadPreLoader(Activity activity) {
mActivity = activity;
}
protected void onPreExecute() {
mDialog = new ProgressDialog(mActivity);
mDialog.setMessage("Loading...");
mDialog.show();
}
protected Void doInBackground(Object... args) {
//do more
publishProgress("Loading something and reached somewhere..");
//do more
publishProgress("Loading something and reached somewhere..");
//do more
return null;
}
protected void onProgressUpdate(String msg) {
mDialog.setMessage(msg);
}
protected void onPostExecute() {
Intent intent = new Intent(BookmarkActivity.this, ThreadActivity.class);
BookmarkActivity.this.startActivity(intent);
mDialog.dismiss();
}
}

Android - Fetching XML Data from web(Using AsyncTask) and Progressbar related problem

I am fetching an XML data from the web using HTTP GET/POST.
Right now i have done it in simple way (i.e. without threaed).
According to the below link, i tried to implement it with Progress bar dialog with Thread
http://www.ceveni.com/2009/09/sample-progress-bar-dialog-in-android.html
But how do i come to know about the finish time of fetching XML from the web.(i.e. what should be the sleep time and also when to dismiss the progress bar dialog box)
Let me clear more about my problem => In activity,when the user click on "Fetch data" button,
the "Progress bar" dialog box should be appeared and it should be disappear only when the fetching is completed
successfully.
I think this can be done with "AsyncTask" but dont know how to use that concept for this problem.
So how do i do it ?
public void onClick() {
new FetchTask(context).execute(null);
}
public class FetchTask extends AsyncTask<Object, Object, Object > {
private ProgressDialog dlg;
private Context ctx;
public FetchTask(Context context) {
ctx = context;
}
#Override
protected void onPreExecute() {
dlg = new ProgressDialog(ctx);
dlg.setMessage("Loading....");
super.onPreExecute();
}
#Override
protected void onPostExecute(Object result) {
dlg.dismiss();
if ( result instanceof Exception ) {
// show error message
} else {
// display data
}
super.onPostExecute(result);
}
#Override
protected Object doInBackground(Object... params) {
try {
// String rawData = doPost("yourUrl");
// XMLTree data = yourParser.parse(rawData);
// return data;
} catch ( Exception e ) {
return e;
}
}
}

Categories

Resources