Issue
This question has to do with an AsyncTask
that needs to kill a ProgressDialog
. While the task is running, the activity gets destroyed and recreated (phone rotation, for example). A new dialog gets made with the help of onSaveInstanceState()
but the AsyncTask
, spawned by the previously destroyed activity, can't see it.
Picture, if you will... (quick mockup code for example's sake).
public class Bob extends Activity {
private ProgressDialog m_d;
public void onCreate(Bundle b) {
m_d = new ProgressDialog(this);
// ...
if (b != null) {
if (b.getBoolean("dialog") == true)
m_d.show();
}
// ...
}
public void onSaveInstanceState(Bundle b) {
super.onSaveInstanceState(b);
b.putBoolean("dialog", (m_d.isShowing()));
}
public void onDestroy() {
if (m_d.isShowing()) {
m_d.dismiss();
m_d = null;
}
//...
}
}
The AsyncTask
onPreExecute()
does m_d.show()
and onPostExecute()
does m_d.hide()
.
The problem is when my activity gets recreated (say, on phone rotation), the AsyncTask
seems to have the old m_d
. It is null
, because that got killed in onDestroy()
.
It doesn't have the new m_d
, created when the activity got recreated. So now I have a ProgressDialog
and the guy who was supposed to kill it in onPostExecute()
can't see it.
Now what? I need the old AsyncTask
to somehow signal the new ProgressDialog
to go away.
private OnItemSelectedListener onSpinnerSelection = new OnItemSelectedListener() {
public void onItemSelected(AdapterView<?> arg0, View arg1, int arg2, long arg3) {
// ...
new Switcharoo().execute();
}
}
private class Switcharoo extends AsyncTask<Void, Void, Void> {
protected void onPreExecute() {
m_d.show();
// ...
}
protected void onPostExecute() {
if (m_d != null) m_d.hide();
// ...
}
protected Void doInBackground(Void... arg0) {
// ...
}
}
If Android doesn't kill my activity while the task is running, it's fine. The ProgressDialog
pops up and goes away like I expect.
If Android decides to restart my activity for any reason while the task is running, m_d
will be null
in onPostExecute()
even though I recreated it in onCreate()
- it has the old m_d
, not the new one.
Solution
There are two problems: the first is that the AsyncTask
is bound to the activity that has created it. I mean, the instance of the activity.
If you want it to survive between activities rotations you have to store it somewhere else (check this for example). In any case, you need to have a reference to it from the new activity (another thing you could do is to use a model fragment, i.e. a fragment with no UI that you set as setRetainInstance(true)
).
Once you have the reference to the async task from the newly created activity, nothing prevents you to have m_d
local to the async task and a setter method that updates it with the new dialog.
Note also that it would be a good practice to have weak references pointing to the activity and the dialog itself in order to allow garbage collection. Otherwise the dialog (and probably the activity itself) would not be freed until the execution of the task itself ended.
Answered By - fedepaol
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.