I have a problem with creating AlertDialog inside a Handler, because it causes memory leaks or another errors.
I have an Activity, Thread and Handler with a WeakReference to an activity.
Before I start my thread, I create ProgressDialog dialog
in my activity class.
Thread task have a reference to MyHandler object.
When user dismisses dialog
in my activity, the onCancelListener calls thread's interrupt(). My thread finishes safely task and send Message DOWNLOAD_STATE.CANCELLED to main activity thread. Then I cretate AlertDialog with code inside MyHandler
The problem is when the user press a back button immediately after dismissing alert
(which cancells thread) and before new AlertDialog
has been created (inside MyHandler class). It tooks about second. When user doesn't press back in this time, everything is working.
It leaks here (inside MyHandler class):
new AlertDialog.Builder(activity).setMessage("update cancelled").setPositiveButton("OK", null).show();
The normal thing is when user presses the back button, activity is destroyed (effect of activity onBackKeyPressed), but why handleMessage isn't stopped and creates AlertDialog
?
My handler class:
static class MyHandler extends Handler {
WeakReference<MainActivity> activityRef;
MyHandler(MainActivity activity)
{
this.activityRef=new WeakReference<MainActivity>(activity);
}
@Override
public void handleMessage(Message msg) {
MainActivity activity=activityRef.get();
if(activity==null)
return;
if (msg.arg1==DownloadTask.DOWNLOAD_STATE.FINISHED.ordinal())
{
activity.dialog.dismiss();
Toast.makeText(activity, "updated", Toast.LENGTH_LONG).show();
}
else if( msg.arg1== DownloadTask.DOWNLOAD_STATE.CANCELLED.ordinal())
{
new AlertDialog.Builder(activity).setMessage("update cancelled").setPositiveButton("OK", null).show();
}
else if(msg.arg1==DownloadTask.DOWNLOAD_STATE.ERROR.ordinal())
{
activity.dialog.dismiss();
new AlertDialog.Builder(activity).setMessage(activity.getString(R.string.no_connection_info)).setPositiveButton("OK", null).show();
}
}
}
Inside thread's runnable:
if(Thread.interrupted())
{
Message msg=handler.obtainMessage();
msg.arg1=DOWNLOAD_STATE.CANCELLED.ordinal();
msg.arg2=counter;
msg.obj=cities.length;
handler.sendMessage(msg);
return;
}
Error stack trace1:
android.view.WindowLeaked: Activity com.mycompany.mooz.MainActivity has leaked window com.android.internal.policy.impl.PhoneWindow$DecorView@42723848 that was originally added here
at android.view.ViewRootImpl.<init>(ViewRootImpl.java:403)
at android.view.WindowManagerImpl.addView(WindowManagerImpl.java:311)
at android.view.WindowManagerImpl.addView(WindowManagerImpl.java:224)
at android.view.WindowManagerImpl$CompatModeWrapper.addView(WindowManagerImpl.java:149)
at android.view.Window$LocalWindowManager.addView(Window.java:554)
at android.app.Dialog.show(Dialog.java:277)
at android.support.v7.app.AlertDialog$Builder.show(AlertDialog.java:902)
at com.mycompany.mooz.MainActivity$MyHandler.handleMessage(MainActivity.java:55)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:137)
at android.app.ActivityThread.main(ActivityThread.java:4921)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:511)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1027)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:794)
at dalvik.system.NativeStart.main(Native Method)
Error stack trace 2:
android.view.WindowManager$BadTokenException: Unable to add window -- token android.os.BinderProxy@427329e0 is not valid; is your activity running?
at android.view.ViewRootImpl.setView(ViewRootImpl.java:700)
at android.view.WindowManagerImpl.addView(WindowManagerImpl.java:345)
at android.view.WindowManagerImpl.addView(WindowManagerImpl.java:224)
at android.view.WindowManagerImpl$CompatModeWrapper.addView(WindowManagerImpl.java:149)
at android.view.Window$LocalWindowManager.addView(Window.java:554)
at android.app.Dialog.show(Dialog.java:277)
at android.support.v7.app.AlertDialog$Builder.show(AlertDialog.java:902)
at com.mycompany.mooz.MainActivity`enter code here`$MyHandler.handleMessage(MainActivity.java:55)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:137)
at android.app.ActivityThread.main(ActivityThread.java:4921)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:511)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1027)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:794)
at dalvik.system.NativeStart.main(Native Method)
Activity com.mycompany.mooz.MainActivity has leaked window com.android.internal.policy.impl.PhoneWindow$DecorView@42723848 that was originally added here
it usually happens when the Activity
is being paused and the dialog is still at screen. Keep a reference to your Dialog and call dismiss in onPause
if the reference is not null and the dialog isShowing
if (mDialog != null && mDialog.isShowing()) {
mDialog.dismiss();
}
android.view.WindowManager$BadTokenException: Unable to add window -- token android.os.BinderProxy@427329e0 is not valid; is your activity running?
this usually happens when you try to show a dialog while the Activity is being paused. To avoid check the isFinishing
flag
if (activity != null && !activity.isFinishing()) {
// show dialog
}