36

在我正在进行的学习过程中(这次是对话框),我发现这很有效:

  AlertDialog.Builder builder = new AlertDialog.Builder(this);

虽然以下不起作用(在运行时失败并出现 WindowManager$BadTokenException):

  AlertDialog.Builder builder = new AlertDialog.Builder(this.getApplicationContext());

我不明白为什么,因为AlertDialog.Builder的构造函数被定义为接受 Context 作为参数,而不是 Activity:

公共 AlertDialog.Builder(上下文上下文)

使用此构建器及其创建的 AlertDialog 的上下文的构造器。

我错过了什么?

4

2 回答 2

26

一个活动继承一个上下文。AlertDialog.Builder 指定了一个 Context 参数,因为它可以被作为 Context 子类的任何类使用,包括 Activity、ListActivity、Service ......(这背后有一个常见的编码习惯 - 你可以了解更多关于它的信息通过阅读 Joshua Bloch 出色的 Effective Java 中的 Item I8(关于接口和抽象类)。

getApplicationContext() 返回您的应用程序的上下文,这与您的活动上下文基本相同 - 而“大部分”是让您失望的原因。细节尚不清楚,但这是一个广泛遇到的问题,典型的答案是使用将警报写入屏幕的上下文。请注意,这不是getApplicationContext() 返回的那个。

现在,如果您像我一样,您可能会说“但我正在一个不继承自 Activity 的类中工作——这就是为什么我首先要为此使用 getApplicationContext() ——嗯!” 我实际上并没有那样粗鲁地说;p ..关键是我也来过这里。我这样修复它:1)问自己“我是否在非活动类中有我的 UI AlertDialog 代码,因为我想跨活动共享它......甚至跨 ListActivities、服务......?”。如果没有,嗯......你真的有代码中的 AlertDialog UI 调用,你不能保证可以访问 UI(以及上下文)吗?如果是这样,请重新考虑您的设计。

假设您确实想在活动中分享这门课,……答案就很清楚了。您希望您的类可供各种调用者使用,每个调用者可能都有自己的上下文:因此调用者必须将其上下文作为参数传递给您的类:

myClass(Context theContext, ...) { ... }

然后,每个活动、服务等都会​​进行如下调用:

myClass(this, ...);

看起来熟悉?

一定要小心!如果您正在共享代码,则必须考虑不同调用并行进入您的共享代码的可能性,以及所有许多后果。这超出了我们的范围......

玩得开心 :)

于 2011-03-29T00:29:24.633 回答
16

AlertDialogDialog的子类,它有一个关联的Window,它有一个关联的LayoutParams。这些参数之一是窗口的类型。默认类型是TYPE_APPLICATION_ATTACHED_DIALOG,它需要一个父窗口。

与 Activity 关联的WindowManager被配置为使用 Activity 的窗口作为父窗口。与应用程序关联的 WindowManager 没有关联的父窗口。

底线:要成功显示对话框,您必须将默认窗口类型更改为不需要父窗口的类型,或者您必须使用具有关联父窗口的上下文。

于 2016-09-24T13:15:41.847 回答