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!
Related
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);
}
I want to develop an Android application which asks a server for some data, and displays these data in a ListView.
Currently, I am using a single Activity (without fragments), and the layout is very simple: it consists of an ImageView, an EditText and a ListView. When the ImageView is clicked it gets the content of the EditText and sends it to the server as a new item and automatically updates the Listview (am calling the method of retreiving the objects after the add operation).
I created an AsyncTask class with a progress dialog inside the Activity which the job in background is getting the objects from the server and then assigning them to a List (member of the enclosing class).
With that practice, am facing a lot of problems: the list gets displayed correctly but very slowly! and when I press the ImageView the AsyncTask is then called to do its job after adding the new item but the problem is that its dialog never dismisses.
My question is what is the best practice with this situation in Android? what is the best design pattern? should I use fragments? How should I manage my Threads?
UDATE:
here is the AsyncTask:
class RemoteDataTask extends AsyncTask<Void, Void, Void> {
private UserDetailsActivity context;
RemoteDataTask(UserDetailsActivity context) {
this.context = context;
}
#Override
protected void onPreExecute() {
super.onPreExecute();;
mProgressDialog = ProgressDialog.show(context, "Looking for posts", "Loading...", true, false);
}
#Override
protected Void doInBackground(Void... params) {
UserDetailsActivity.this.posts.clear();
posts = new PostManager(context).userPosts(ParseUser.getCurrentUser());
return null;
}
#Override
protected void onPostExecute(Void result) {
postList = (ListView) findViewById(R.id.post_list);
adapter = new PostsListAdapter(context, UserDetailsActivity.this.posts);
postList.setAdapter(adapter);
mProgressDialog.dismiss();
}
}
And the method wich retreives the posts:
public void refreshPostList() {
try {
BusInfo.getInstance().register(UserDetailsActivity.this); // register the Bus to recieve results.
} catch (Exception e) {
Log.d("My application says : ;) ", "Erro registering " + e);
}
pd = ProgressDialog.show(this, "Please Wait", "Loading");
new ExprienceEdit(this, "hello").execute();
}
And the Button with its method
public void newPost(View v) {
ParseObject post = new ParseObject("Post");
post.put("content", editText.getText().toString());
post.saveInBackground();
refreshPostList();
}
<ImageView
android:id="#+id/new_post"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:onClick="newPost"
android:padding="10dp"
android:src="#drawable/ic_action_post" />
Regarding the progress dialog not being dismissed:
Where is mProgressDialog dialog declared? I suggest you move it into the RemoteDataTask. (I'm guessing you are at some point overriding the current instance and therefore the dismiss isn't working)
Regarding the slow refresh of the list, post your Adapter code. You should do correct recycling of views and you shouldn't recreate the Adapter everytime but set the data and call notifyDataSetChanged so the listView will recycle the views with the new data. Look into this answer regarding correct recycling of views: https://stackoverflow.com/a/6923513/348378
Edit 1
I also suggest this to prevent having multiple refreshTasks:
public void refreshPostList() {
if(dataTask == null) {
dataTask = new RemoteDataTask(this).execute();
}
}
#Override
protected void onPostExecute(Void result) {
// you stuff
dataTask = null;
}
You can also consider cancelling the current task and starting a new one depending on required behavior.
you should pass ProgressDialog to your AsyncTask class constructor and in any class that want to use AsyncTask class(in your case RemoteDataTask) you should instantiate progress dialog and pass as second argument to your RemoteDataTask to control the visibility from specific custom class.
maybe this help.
The best way to deal with asynctasks is by using otto :
Otto actually is a singltone bus : please refer to this website http://square.github.io/otto/
Any piece of code would be great to help you more with the problem you are facing.
Any questions I am ready to answer.
BusInfo.getInstance.register(ActivityName.this) // register the Bus to recieve results.
pd = ProgressDialog.show(ActivityName.this, "Please Wait", "Loading");
new ExperienceEdit(getApplicationContext(), "hello").execute(); //async task to be executed let us say on button click
Now the experience edit is:
public class ExperienceEdit extends AsyncTask<Void, Void, String> {
Context c;
String id;
public ExperienceEdit(Context c, String id\) {
this.c = c;
this.id = id;
}
#Override
protected String doInBackground(Void... voids) {
//right the call to back here
}
#Override
public void onPostExecute(String result) {
try {
BusInfo.getInstance().post(new ExperienceEditResult(result));
} catch (Exception e) {
e.printStackTrace();
}
}
}
The result after posting is subscribed at the activity like this :
#Subscribe
public void onAsyncTaskResult(EditExperienceResult result) {
if (pd != null)
pd.dismiss();
object = result.getResult();
if (object != null) {
if (object.equals("success")) {
Toast.makeText(getApplicationContext(), "Success", Toast.LENGTH_SHORT).show();
onBackPressed();
} else Toast.makeText(getApplicationContext(), "Failure", Toast.LENGTH_SHORT).show();
} else
Toast.makeText(getApplicationContext(), "Please try again later", Toast.LENGTH_SHORT).show();
}
The ExperienceEditResult here happens to be a string (you can have it whatever you want) :
public class ExperienceEditResult {
private String result;
public ExperienceEditResult(String result) {
this.result = result;
}
public String getResult() {
return result;
}
}
The BusInfo class is :
public class BusInfo {
private static final Bus BUS = new Bus();
public static Bus getInstance() {
return BUS;
}
}
Do not forget to unregister the bus onDestroy of the activity: BusInfo.getInstance().unregister(ActivityName.this);
If you aslso want to prevent the progress dialogue from always showing because sometimes it is showing twice due to a double click on button add this : if(pd!=null&&pd.isShowing()){
Log.v("pd is showing","showing");
} else {pd= ProgressDialgue.show...}
I have an AsyncTask that is supposed to show a progress bar while it uploads some stuff via Internet. Sometimes it works like a charm and sometimes it does not show any progress bar. Here is the code:
public class Upload extends AsyncTask<Void, Void, Void> {
private ProgressDialog dialog = new ProgressDialog(Activity.this);
protected void onPreExecute() {
dialog = ProgressDialog.show(Activity.this, "wait...", "", true, true);
}
#Override
protected Void doInBackground(Void... params) {
//upload stuff
return null;
}
protected void onPostExecute(Void result) {
try {
if (dialog.isShowing())
dialog.dismiss();
dialog = null;
} catch (Exception e) {
// nothing
}
Intent next = new Intent(getApplicationContext(), SecondActivity.class);
startActivity(next);
}
}
}
The doInBackground and onPostExecute work always, and sometimes altogether it works like a charm. But sometimes, there is no progress bar while it is uploading. Is this a race condition? I do not think so, but I cannot find any explanation.
You're creating the object twice in the class. The ProgressDialog.show already returns a created ProgressDialog object, but you have instantiated it first at the top. The ProgressDialog should be instantiated once, so try removing the instantiation at the top and try again, like so:
private ProgressDialog dialog;
protected void onPreExecute() {
dialog = ProgressDialog.show(Activity.this, "wait...", "", true, true);
}
Maybe it is because void parameter that causes that problem. Just try to use Integer as your parameters.:
public class Upload extends AsyncTask<Integer, Integer, Integer>
Quick summary: I'm making an application that parses a binary file, stores vertices and their properties, and displays them in openGL. I'm trying to implement a ProgressDialog while it parses, but I'm having considerable trouble. I've tried implementing this in many places, but this is my current setup:
public class PointViewer extends Activity{
...
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Bundle extras = getIntent().getExtras();
filePath = extras.getString("file_path");
mGLView = new GLSurfaceView(this);
theRenderer = new OpenGLRenderer();
mGLView.setRenderer(theRenderer);
//Parse the file and set the arrays
theRenderer.setLAS(filePath);
setContentView(mGLView);
}
...
}
The Rendering class...
public class OpenGLRenderer extends Activity implements GLSurfaceView.Renderer {
...
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
public void setLAS (String fileName){
new ProgressTask(this).execute();
}
...
/*
* The class for the progress dialog
*/
private class ProgressTask extends AsyncTask<String, Void, Boolean> {
private ProgressDialog dialog;
private Context context;
//private List<Message> messages;
public ProgressTask(Context ctx) {
context = ctx;
dialog = new ProgressDialog(context);
}
/** progress dialog to show user that the backup is processing. */
protected void onPreExecute() {
this.dialog.setMessage("Progress start");
this.dialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
this.dialog.show();
}
#Override
protected void onPostExecute(final Boolean success) {
if (dialog.isShowing()) {
dialog.dismiss();
}
if (success) {
Toast.makeText(context, "OK", Toast.LENGTH_LONG).show();
} else {
Toast.makeText(context, "Error", Toast.LENGTH_LONG).show();
}
}
protected Boolean doInBackground(final String... args) {
try{
ptCloud = new PointCloud(args[0]);
...
dialog.setProgress(percentParsed);
return true;
} catch (Exception e){
Log.e("tag", "error", e);
return false;
}
}
}
When I call dialog = new ProgressDialog(context); It errors on a null pointer exception, I'm assuming because there is a context issue... Does anyone have any ideas?
First, you shouldn't create OpenGLRenderer yourself, because its an Activity and is supposed to be managed by system. When you create OpenGLRenderer yourself, then this activity has its context incorrectly initialized. And when your create ProgressDialog with invalid context, you receive NullPointerException.
But even if you start OpenGlRenderer correctly, your app will still crash at line:
dialog.setProgress(percentParsed);
You should use publishProgress instead and update ProgressDialog in AsyncTask's onProgressUpdate function. That's because you can't update UI from non-ui thread.
maybe try replaceing "this" with "OpenGLRenderer.this" inside your setLAS() method. It doesn't seem like it from the code you've posted but sometimes if you are making that call from a different object type it will try to pass in an OnClickListener (or whatever object your calling from) instead of an activity, thus the object has no context. Like I said doesn't seem like that is the case, but worth a shot.
Also where are you calling setLAS() from? perhaps post that section of your code too.
Edit:
Try modifying your setLAS() method to have a Context parameter and pass it in from your first activity, and just pass it along from the second activity to the async task instead of using the context from the second activity.
The next version of my app needs to upgrade the database and this takes quite a bit of time. I'd like to show a progressDialog to update the user on the progress. Problem is, I can't quite figure out how and where to create the dialog.
My basic setup is that I have an activity which is essentially a splashscreen. It's on this screen I would like to show the progress. I have a separate DbAdapter.java file where a DatabaseHelper class extends SQLiteOpenHelper, where I override onUpgrade (the upgrade part is working fine).
I've tried a few different places to implement the progress dialog, but I don't seem to find the right spot. I tried passing context from my splashscreen activity to onUpgrade, but when onUpgrade runs it seems to be getting the context from my ContentProvider instead.
Does anyone have a good example of how to display a progress dialog when upgrading a database?
You need to implement an AsyncTask. Example:
class YourAsyncTask extends AsyncTask<Void, Void, Void> {
private ProgressDialog progressDialog;
#Override
protected void onPreExecute() {
//show your dialog here
progressDialog = ProgressDialog.show(this, "title", "message", true, false)
}
#Override
protected Void doInBackground(Void... params) {
//update your DB - it will run in a different thread
return null;
}
#Override
protected void onPostExecute(Void result) {
//hide your dialog here
progressDialog.dismiss();
}
}
Then you just have to call
new YourAsyncTask().execute();
You can read more about AsyncTask here: http://developer.android.com/reference/android/os/AsyncTask.html
ProgressDialog myProgressDialog = null;
public void DownloadFiles() {
myProgressDialog = ProgressDialog.show(this, "Please wait !",
"Updating...", true);
new Thread() {
public void run() {
try {
//Your upgrade method !
YourUpdateFunction();
} catch (Exception e) {
Log.v(TAG, "Error");
}
myProgressDialog.dismiss();
}
}.start();
}