尽管使用了 WeakReference,AlertDialog 仍会泄漏
AlertDialog leaks despite using a WeakReference
我在处理程序中创建 AlertDialog 时遇到问题,因为它会导致内存泄漏或其他错误。
详情:
我有一个 Activity,线程和处理程序带有对 activity 的 WeakReference。
在我开始我的线程之前,我在我的 activity class 中创建了 ProgressDialog dialog
。
线程任务有一个对 MyHandler 对象的引用。
当用户在我的 activity 中关闭 dialog
时,onCancelListener 调用线程的 interrupt()。我的线程安全地完成任务并将消息 DOWNLOAD_STATE.CANCELLED 发送到主线程 activity。然后我用 MyHandler
中的代码创建 AlertDialog
问题:
问题是当用户在关闭 alert
(取消线程)后且在创建新的 AlertDialog
之前(在 MyHandler class 内)立即按下后退按钮时。花了大约一秒钟。当用户此时不按回键时,一切正常。
它泄漏在这里(在 MyHandler 内部 class):
new AlertDialog.Builder(activity).setMessage("update cancelled").setPositiveButton("OK", null).show();
正常情况是当用户按下后退按钮时,activity 被销毁(activity onBackKeyPressed 的效果),但为什么 handleMessage 没有停止并创建 AlertDialog
?
我的经纪人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();
}
}
}
内部线程的可运行:
if(Thread.interrupted())
{
Message msg=handler.obtainMessage();
msg.arg1=DOWNLOAD_STATE.CANCELLED.ordinal();
msg.arg2=counter;
msg.obj=cities.length;
handler.sendMessage(msg);
return;
}
错误堆栈跟踪 1:
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)
错误堆栈跟踪 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
通常在 Activity
暂停且对话框仍在屏幕上时发生。如果引用不为空且对话框 isShowing
,请保留对您的对话框的引用并在 onPause
中调用关闭
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?
当您在 Activity 暂停时尝试显示对话框时,通常会发生这种情况。为了避免检查 isFinishing
标志
if (activity != null && !activity.isFinishing()) {
// show dialog
}
我在处理程序中创建 AlertDialog 时遇到问题,因为它会导致内存泄漏或其他错误。
详情:
我有一个 Activity,线程和处理程序带有对 activity 的 WeakReference。
在我开始我的线程之前,我在我的 activity class 中创建了 ProgressDialog dialog
。
线程任务有一个对 MyHandler 对象的引用。
当用户在我的 activity 中关闭 dialog
时,onCancelListener 调用线程的 interrupt()。我的线程安全地完成任务并将消息 DOWNLOAD_STATE.CANCELLED 发送到主线程 activity。然后我用 MyHandler
问题:
问题是当用户在关闭 alert
(取消线程)后且在创建新的 AlertDialog
之前(在 MyHandler class 内)立即按下后退按钮时。花了大约一秒钟。当用户此时不按回键时,一切正常。
它泄漏在这里(在 MyHandler 内部 class):
new AlertDialog.Builder(activity).setMessage("update cancelled").setPositiveButton("OK", null).show();
正常情况是当用户按下后退按钮时,activity 被销毁(activity onBackKeyPressed 的效果),但为什么 handleMessage 没有停止并创建 AlertDialog
?
我的经纪人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();
}
}
}
内部线程的可运行:
if(Thread.interrupted())
{
Message msg=handler.obtainMessage();
msg.arg1=DOWNLOAD_STATE.CANCELLED.ordinal();
msg.arg2=counter;
msg.obj=cities.length;
handler.sendMessage(msg);
return;
}
错误堆栈跟踪 1:
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)
错误堆栈跟踪 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
通常在 Activity
暂停且对话框仍在屏幕上时发生。如果引用不为空且对话框 isShowing
onPause
中调用关闭
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?
当您在 Activity 暂停时尝试显示对话框时,通常会发生这种情况。为了避免检查 isFinishing
标志
if (activity != null && !activity.isFinishing()) {
// show dialog
}