最近在做项目的时候,越来越多的开发者反馈SDK Dialog的show以及dismiss导致程序crash,出现的问题是传递进来的Activity被finish或者重建(横竖屏切换)了。下面分别对这两种情况说明以及解决办法。
在Dialog.show时出现crash
日志信息:
- 06-03 17:18:14.550: E/AndroidRuntime(12584): Caused by: android.view.WindowManager$BadTokenException: Unable to add window -- token android.os.BinderProxy@<span class="hljs-number">42963e08</span> is not valid; is your activity running?</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="2"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"><span class="hljs-number">06</span>-<span class="hljs-number">03</span> <span class="hljs-number">17</span>:<span class="hljs-number">18</span>:<span class="hljs-number">14.550</span>: E/AndroidRuntime(<span class="hljs-number">12584</span>): at android.view.ViewRootImpl.setView(ViewRootImpl.java:<span class="hljs-number">587</span>)</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="3"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"><span class="hljs-number">06</span>-<span class="hljs-number">03</span> <span class="hljs-number">17</span>:<span class="hljs-number">18</span>:<span class="hljs-number">14.550</span>: E/AndroidRuntime(<span class="hljs-number">12584</span>): at android.view.WindowManagerImpl.addView(WindowManagerImpl.java:<span class="hljs-number">326</span>)</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="4"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"><span class="hljs-number">06</span>-<span class="hljs-number">03</span> <span class="hljs-number">17</span>:<span class="hljs-number">18</span>:<span class="hljs-number">14.550</span>: E/AndroidRuntime(<span class="hljs-number">12584</span>): at android.view.WindowManagerImpl.addView(WindowManagerImpl.java:<span class="hljs-number">224</span>)</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="5"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"><span class="hljs-number">06</span>-<span class="hljs-number">03</span> <span class="hljs-number">17</span>:<span class="hljs-number">18</span>:<span class="hljs-number">14.550</span>: E/AndroidRuntime(<span class="hljs-number">12584</span>): at android.view.WindowManagerImpl$CompatModeWrapper.addView(WindowManagerImpl.java:149)
- 06-03 17:18:14.550: E/AndroidRuntime(12584): at android.view.Window$LocalWindowManager.addView(Window.java:561)
- 06-03 17:18:14.550: E/AndroidRuntime(12584): at android.app.Dialog.show(Dialog.java:293)
- 06-03 17:18:14.550: E/AndroidRuntime(12584): at com.umeng.socialize.controller.impl.m.onStart(SocialServiceImpl.java:1451)
- 06-03 17:18:14.550: E/AndroidRuntime(12584): at com.umeng.socialize.controller.impl.aa.onStart(SocialServiceImpl.java:2529)
- 06-03 17:18:14.550: E/AndroidRuntime(12584): at com.umeng.socialize.controller.impl.ab.onStart(SocialServiceImpl.java:2557)
- 06-03 17:18:14.550: E/AndroidRuntime(12584): at com.umeng.socialize.controller.impl.c.c(SocialServiceImpl.java:2594)
- 06-03 17:18:14.550: E/AndroidRuntime(12584): at com.umeng.socialize.controller.impl.c.doOauthVerify(SocialServiceImpl.java:2339)
- 06-03 17:18:14.550: E/AndroidRuntime(12584): at com.umeng.socialize.controller.impl.c.c(SocialServiceImpl.java:1456)
- 06-03 17:18:14.550: E/AndroidRuntime(12584): at com.umeng.socialize.controller.impl.c.postShare(SocialServiceImpl.java:1295)
- 06-03 17:18:14.550: E/AndroidRuntime(12584): … 17 more
我们知道所有的窗口创建和管理都是依附于window manager的,因此Dialog的创建也不例外。Dialog的创建流程通过查看源码可以知道,在Dialog的构造函数中,创建了一个Window对象,但我们知道Window对象并不是用于显示的,真正用于显示的是View对象。因此通过Dialog的show方法构造了一个mDecor的View对象,并最终通过WindowManager的addView()方法显示Dialog,如果此时你的activity应为某种原因被finish或者重建就会出现此问题。
解决办法:
在创建Dialog的时候,我们设置该dialog属于某个activity,这样我们根据Activity的状态决定是否显示Dialog.
创建Dialog时设置activity:
<pre name="code" class="java" style="color: rgb(51, 51, 51); font-size: 14px; line-height: 26px;">ProgressDialog <span style="font-family: 微软雅黑;">mDialog = new ProgressDialog(this);</span>
<span style="font-family: 微软雅黑;">mDialog.setMessage("test");</span>
mDialog.setCancelable(false);mDialog.setOwnerActivity(this);
显示Dialog的时候做相应地判断:
- if ( mDialog != null ) {
- Activity activity = mDialog.getOwnerActivity();
- if ( activity != null && !activity.isFinishing() ) {
- mDialog.show();
- }
- }
Dialog.dismiss时出现crash
日志信息:
- 06-03 21:03:18.027: E/AndroidRuntime(6197): java.lang.IllegalArgumentException: View not attached to window manager
- 06-03 21:03:18.027: E/AndroidRuntime(6197): at android.view.WindowManagerGlobal.findViewLocked(WindowManagerGlobal.java:385)
- 06-03 21:03:18.027: E/AndroidRuntime(6197): at android.view.WindowManagerGlobal.removeView(WindowManagerGlobal.java:287)
- 06-03 21:03:18.027: E/AndroidRuntime(6197): at android.view.WindowManagerImpl.removeView(WindowManagerImpl.java:79)
- 06-03 21:03:18.027: E/AndroidRuntime(6197): at android.app.Dialog.dismissDialog(Dialog.java:323)
- 06-03 21:03:18.027: E/AndroidRuntime(6197): at android.app.Dialog.dismiss(Dialog.java:306)
- 06-03 21:03:18.027: E/AndroidRuntime(6197): at com.umeng.soexample.MainActivity$<span class="hljs-number">1</span>$1.onComplete(MainActivity.java:61)
- 06-03 21:03:18.027: E/AndroidRuntime(6197): at com.umeng.socialize.qq.controller.impl.UMQQSsoHandler$<span class="hljs-number">4</span>.onCancel(UMQQSsoHandler.java:<span class="hljs-number">355</span>)</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="9"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"><span class="hljs-number">06</span>-<span class="hljs-number">03</span> <span class="hljs-number">21</span>:<span class="hljs-number">03</span>:<span class="hljs-number">18.027</span>: E/AndroidRuntime(<span class="hljs-number">6197</span>): at com.tencent.jsutil.PackIUiListener$1.handleMessage(ProGuard:29)
- 06-03 21:03:18.027: E/AndroidRuntime(6197): at android.os.Handler.dispatchMessage(Handler.java:99)
- 06-03 21:03:18.027: E/AndroidRuntime(6197): at android.os.Looper.loop(Looper.java:153)
- 06-03 21:03:18.027: E/AndroidRuntime(6197): at android.app.ActivityThread.main(ActivityThread.java:5297)
- 06-03 21:03:18.027: E/AndroidRuntime(6197): at java.lang.reflect.Method.invokeNative(Native Method)
- 06-03 21:03:18.027: E/AndroidRuntime(6197): at java.lang.reflect.Method.invoke(Method.java:511)
- 06-03 21:03:18.027: E/AndroidRuntime(6197): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:833)
- 06-03 21:03:18.027: E/AndroidRuntime(6197): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:600)
- 06-03 21:03:18.027: E/AndroidRuntime(6197): at dalvik.system.NativeStart.main(Native Method)
原因:Dialog在dismiss得时候是通过直接从WindowManager remove操作来完成的。当Activity被销毁后,此时的Dialog处于游离状态,在remove的时候会迭代,如果发现此View没有在数组mViews中时讲抛出IllegalArgumentException(“View not attached to window manager”)异常。解决办法:
创建Dialog的时候设置该Dialog所属的Activity,在dismiss的时候根据此activity的状态来决定是否dismiss此dialog
- if ( mDialog != null && mDialog.isShowing()) {
- Activity activity = mDialog.getOwnerActivity();
- if ( activity != null && !activity.isFinishing()) {
- mDialog.dismiss();
- }
- }