How to reproduce the bug:
Settings -> Developer Options -> Don't keep Activities
.AsyncTask
is executing and the ProgressDialog
is showing.The Android OS will destroy an activity as soon as it is hidden. When onPostExecute
is called the Activity
will be in "finishing" state and the ProgressDialog
will be not attached to Activity
.
How to fix it:
onPostExecute
method. ProgressDialog
in onDestroy
method. Otherwise, android.view.WindowLeaked
exception will be thrown. This exception usually comes from dialogs that are still active when the activity is finishing.Try this fixed code:
public class YourActivity extends Activity {
private void showProgressDialog() {
if (pDialog == null) {
pDialog = new ProgressDialog(StartActivity.this);
pDialog.setMessage("Loading. Please wait...");
pDialog.setIndeterminate(false);
pDialog.setCancelable(false);
}
pDialog.show();
}
private void dismissProgressDialog() {
if (pDialog != null && pDialog.isShowing()) {
pDialog.dismiss();
}
}
@Override
protected void onDestroy() {
dismissProgressDialog();
super.onDestroy();
}
class LoadAllProducts extends AsyncTask<String, String, String> {
// Before starting background thread Show Progress Dialog
@Override
protected void onPreExecute() {
showProgressDialog();
}
//getting All products from url
protected String doInBackground(String... args) {
doMoreStuff("internet");
return null;
}
// After completing background task Dismiss the progress dialog
protected void onPostExecute(String file_url) {
if (YourActivity.this.isDestroyed()) { // or call isFinishing() if min sdk version < 17
return;
}
dismissProgressDialog();
something(note);
}
}
}
Issue could be that the Activity
have been finished
or in progress of finishing
.
Add a check isFinishing
, and dismiss dialog only when this is false
if (!YourActivity.this.isFinishing() && pDialog != null) {
pDialog.dismiss();
}
isFinishing : Check to see whether this activity is in the process of finishing,either because you called finish
on it or someone else has requested that it finished.
For Dialog
created in a Fragment
, I use the following code:
ProgressDialog myDialog = new ProgressDialog(getActivity());
myDialog.setOwnerActivity(getActivity());
...
Activity activity = myDialog.getOwnerActivity();
if( activity!=null && !activity.isFinishing()) {
myDialog.dismiss();
}
I use this pattern to deal with the case when a Fragment
may be detached from the Activity
.
See how the Code is working here:
After calling the Async task, the async task runs in the background. that is desirable. Now, this Async task has a progress dialog which is attached to the Activity, if you ask how to see the code:
pDialog = new ProgressDialog(CLASS.this);
You are passing the Class.this
as context to the argument. So the Progress dialog is still attached to the activity.
Now consider the scenario:
If we try to finish the activity using the finish() method, while the async task is in progress, is the point where you are trying to access the Resource attached to the activity ie the progress bar
when the activity is no more there.
Hence you get:
java.lang.IllegalArgumentException: View not attached to the window manager
Solution to this:
1) Make sure that the Dialog box is dismissed or canceled before the activity finishes.
2) Finish the activity, only after the dialog box is dismissed, that is the async task is over.
Based on @erakitin answer, but also compatible for Android versions < API level 17. Sadly Activity.isDestroyed() is only supported since API level 17, so if you're targeting an older API level just like me, you'll have to check it yourself. Haven't got the View not attached to window manager
exception after that.
Example code
public class MainActivity extends Activity {
private TestAsyncTask mAsyncTask;
private ProgressDialog mProgressDialog;
private boolean mIsDestroyed;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (condition) {
mAsyncTask = new TestAsyncTask();
mAsyncTask.execute();
}
}
@Override
protected void onResume() {
super.onResume();
if (mAsyncTask != null && mAsyncTask.getStatus() != AsyncTask.Status.FINISHED) {
Toast.makeText(this, "Still loading", Toast.LENGTH_LONG).show();
return;
}
}
@Override
protected void onDestroy() {
super.onDestroy();
mIsDestroyed = true;
if (mProgressDialog != null && mProgressDialog.isShowing()) {
mProgressDialog.dismiss();
}
}
public class TestAsyncTask extends AsyncTask<Void, Void, AsyncResult> {
@Override
protected void onPreExecute() {
super.onPreExecute();
mProgressDialog = ProgressDialog.show(MainActivity.this, "Please wait", "doing stuff..");
}
@Override
protected AsyncResult doInBackground(Void... arg0) {
// Do long running background stuff
return null;
}
@Override
protected void onPostExecute(AsyncResult result) {
// Use MainActivity.this.isDestroyed() when targeting API level 17 or higher
if (mIsDestroyed)// Activity not there anymore
return;
mProgressDialog.dismiss();
// Handle rest onPostExecute
}
}
}
@Override
public void onPause() {
super.onPause();
if(pDialog != null)
pDialog .dismiss();
pDialog = null;
}
refer this.
Override onConfigurationChanged and dismiss progress dialog. If progress dialog is created in portrait and dismisses in landscape then it will throw View not attached to window manager error.
Also stop the progress bar and stop the async task in onPause(), onBackPressed and onDestroy method.
if(asyncTaskObj !=null && asyncTaskObj.getStatus().equals(AsyncTask.Status.RUNNING)){
asyncTaskObj.cancel(true);
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With