1. 错误详情

在弹出对话框时候应用崩溃,并报如下错误:

android.view.WindowManager$BadTokenException: Unable to add window -- token null is not for an application
at android.view.ViewRootImpl.setView(ViewRootImpl.java:588)
at android.view.WindowManagerGlobal.addView(WindowManagerGlobal.java:310)
at android.view.WindowManagerImpl.addView(WindowManagerImpl.java:86)
at android.app.Dialog.show(Dialog.java:329)
at android.app.AlertDialog.show(AlertDialog.java:454)
at com.jephy.timepickwheeldemo.MainActivity.showTimePicker(MainActivity.java:37)
at com.jephy.timepickwheeldemo.MainActivity_ViewBinding$1.doClick(MainActivity_ViewBinding.java:34)
at butterknife.internal .DebouncingOnClickListener.onClick(DebouncingOnClickListener.java:22)
at android.view.View.performClick(View.java:5205)
at android.view.View$PerformClick.run(View.java:21178)
at android.os.Handler.handleCallback(Handler.java:739)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:160)
at android.app.ActivityThread.main(ActivityThread.java:5610)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal .os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:732)
at com.android.internal .os.ZygoteInit.main(ZygoteInit.java:622

2. 问题原因及解决

代码:

 TimePickerDialog timePickerDialog = new TimePickerDialog(getApplicationContext(), new TimePickerDialog.OnTimeSetListener() {
            @Override
            public void onTimeSet(TimePicker view, int hourOfDay, int minute) {

            }
        }, 0, 0, true);
        timePickerDialog.show();//报错指向行
timePickerDialog.show();//报错指向行

问题实际出在TimePickerDialog的创建时传入的上下文参数**getApplicationContext()**身上。将其替换成MainActivity.this之后问题就解决了。

3. 问题推广

3.1 推测其他View也会出现该问题

该问题在使用TimePickerDialog时出现,推测创建其他控件时使用**getApplicationContext()**也可能出现该问题。
于是使用TextView进行了测试。具体做法是在点击按钮的时候将动态创建一个TextView将其添加到一个Layout容器中。结果是当以MainActivity.this作为上下文传入的时候能够添加进去;当使用getApplicationContext()作为上下文时虽然没崩溃,textview也没有成功被添加到容器中。

3.2 创建View时候可以传入哪些上下文参数呢?

上面测试中可知

  • MainActivity.this 可以
  • getApplicationContext 不行

对于其他的方式呢?
在Activity中还有getApplication,getParent等方法返回的是Context或者其子孙类,它们都可以作为合法参数进行传入。
通过对这几个参数进行测试, 结果如下:

getApplication()    不行
getParent()         不行并崩溃

4. 总结与展望

根据以上试验,可以看出。我们在动态创建View时,传入的上下文参数应该是我们扩展的那个Activity的实例。
以上都只是对Activity中获取的几个上下文参数进行了测试。实际还有其他一些Context的子类比如Service并没有测试过。传入Service作为上下文参数可不可以呢?有时间的时候可以探究下。

Logo

华为开发者空间,是为全球开发者打造的专属开发空间,汇聚了华为优质开发资源及工具,致力于让每一位开发者拥有一台云主机,基于华为根生态开发、创新。

更多推荐