首页 > 代码库 > ActivityGroup window bad token问题深入分析
ActivityGroup window bad token问题深入分析
最近帮别人调试一个webview的页面,很奇怪的遇到了以下问题:
H5页面中会检测地址中传递的参数,若检测到特定参数异常,则会弹出Dialog进行提示
Dialog:android.view.WindowManager$BadTokenException:
但是在单独的测试工程中并没有发生异常,这时我注意到日志中包含localactivitymanager的内容,之后发现果然是只有在TabHost中才会发生这种情况.
类似的情况,如果我们在ActivityGroup或者TabActivity中的子Activity创建Dialog若使用以下的代码
progressDialog = new ProgressDialog(XXX.this)
创建就会出现如下Exception:
05-24 12:34:42.236: ERROR/AndroidRuntime(6362): android.view.WindowManager$BadTokenException: Unable to add window -- token android.app.LocalActivityManager$LocalActivityRecord@43e5b158 is not valid; is your activity running?
实际上出现这种问题的主要原因是显示UI界面时,context选择错误。
因为new对话框的时候,参数content 指定成了this,即指向当前子Activity的content。但子Activity是动态创建的,不能保证一直存在。其父Activity的content是稳定存在的,所以有下面的解决办法
若ActivityGroup中嵌套ActivityGroup,嵌套多少就该使用多少个getParent()。
为什么要使用getParent我们可以从ActivityGroup的内部机制来理解:
TabActivity的父类是ActivityGroup,而ActivityGroup的父类是Activity。因此从Ams的角度来看,ActivityGroup与普通的Activity没有什么区别,其生命周期包括标准的start,stop,resume,destroy等,而且系统中只允许同时允许一个ActivityGroup.但ActivityGroup内部有一个重要成员变量,其类型为LocalActivityManager,该类的最大特点在于它可以访问应用进程的主类,即ActivityThread类。Ams要启动某个Activity或者赞同某个Activity都是通过ActivityThread类执行的,而LocalActivityManager类就意味着可以通过它来装载不同的Activity,并控制Activity的不同的状态。注意,这里是装载,而不是启动,这点很重要。所谓的启动,一般是指会创建一个进程(如果所在的应用经常还不存在)运行该Activity,而装载仅仅是指把该Activity作为一个普通类进行加载,并创建一个该类的对象而已,而该类的任何函数都没有被运行。装载Activity对象的过程对AmS来讲是完全不可见的,那些嵌入的Activity仅仅贡献了自己所包含的Window窗口而已。而子Activity的不同状态是通过moveToState来处理的。
所以子Activity不是像普通的Activity一样,它只是提供Window而已,所以在创建Dialog时就应该使用getParent获取ActivityGroup真正的Activity,才可以加Dialog加入Activity中。
如果遇到类似的 window bak token的异常,我们也可以从这个方面着手去分析解决.