使用getApplication()作为上下文时,对话框抛出“无法添加窗口-令牌为空不是应用程序”的错误。

695

我的Activity试图创建一个需要Context作为参数的AlertDialog。如果我使用以下代码,则可以正常工作:

AlertDialog.Builder builder = new AlertDialog.Builder(this);
然而,我对使用"this"作为上下文感到不安,因为即使在像屏幕旋转这样简单的事情中,Activity被销毁和重新创建时可能会出现内存泄漏的风险。来自Android开发者博客上一篇相关文章的说法如下:

有两种简单的方法可以避免上下文相关的内存泄漏。最明显的方法是避免将上下文从其自身的范围之外逃逸。上面的示例显示了静态引用的情况,但是内部类及其对外部类的隐式引用同样危险。第二个解决方案是使用Application上下文。此上下文将与应用程序一起存在,并且不依赖于活动生命周期。如果您计划保留需要上下文的长期对象,请记住应用程序对象。您可以通过调用Context.getApplicationContext()或Activity.getApplication()轻松获取它。

但是,对于AlertDialog(),无论是getApplicationContext()还是getApplication()都不可接受作为上下文,因为它会抛出异常:

"Unable to add window — token null is not for an application”

相关参考:123等。
那么,既然我们被官方建议使用Activity.getApplication(),但实际上它没有按照广告所说的正常工作,那么这真的应该被认为是一个“bug”吗?
Jim

第一项建议使用getApplication的参考资料:http://android-developers.blogspot.com/2009/01/avoiding-memory-leaks.html - gymshoe
其他参考资料:https://dev59.com/GHI_5IYBdhLWcg3wBuRs - gymshoe
1
请参考以下内容:https://dev59.com/aXE85IYBdhLWcg3wvGKm - gymshoe
http://groups.google.com/group/android-developers/browse_thread/thread/7a648edddccf6f7d - gymshoe
显示剩余2条评论
28个回答

2

在我的工作中:

this.getContext();

2

如果您试图从非主UI线程显示对话框,也可能会发生这种情况。

在这种情况下,请使用runOnUiThread()


2

另一种可能是创建如下对话框:

final Dialog dialog = new Dialog(new ContextThemeWrapper(
            this, R.style.MyThemeDialog));

1
在查看API后,如果您在一个片段中,则可以将对话框传递给您的活动或getActivity,然后在返回方法中使用dialog.dismiss()强制清除它以防止泄漏。尽管我不知道有没有明确说明,但似乎您只是为了这个目的而在OnClickHandlers中返回对话框。

1
我的解决方法是传递活动而不是上下文。
我想要一个自定义布局的对话框,但为了保持代码分离,我将其创建在一个单独的类中,否则我将不得不将那一块代码复制粘贴到每个我想使用对话框的活动中。
解决方案解释了我的情况,但它提供了核心解决方案:
  1. 由于我正在使用ViewAdapter,我用Activity(而不是上下文ex. -> [kotlin] activity: Activity)作为参数初始化了适配器 -> ex. [kotlin] this@MainActivity
  2. 然后我将该参数传递给Viewholder
  3. 之后再传递给将填充对话框的类。
在到达您想要填充的对话框之前,请在所有地方都使用activity[可选名称]:Activity[强制类型]。
尽管需要传递很多参数,但这比到处复制和粘贴相同的代码更有意义。

1
伙计们,我有一份简单的备忘单。创建一个文件,随便给它起个名字,然后在里面写下这段代码。
fun Context.alertdialog(context: Context, msg: String, icon: Drawable, title:String){
    val alertDialog = AlertDialog.Builder(context)
    alertDialog.setIcon(icon)
        .setTitle(title)
        .setMessage(msg)
    alertDialog.show()
}

现在,当您需要显示警报对话框时,请在任何地方仅使用此方法。
requireActivity().alertdialog(requireContext(), resources.getString(R.string.pass_title),
                resources.getDrawable(R.drawable.pass_ic_name), "title")

祝Kotlin好运


1
如果您的对话框是在适配器上创建的:
请将 Activity 传递给适配器构造函数:
adapter = new MyAdapter(getActivity(),data);

在适配器上接收:

 public MyAdapter(Activity activity, List<Data> dataList){
       this.activity = activity;
    }

现在你可以在你的构建器上使用。
            AlertDialog.Builder alert = new AlertDialog.Builder(activity);

0

这是我为我的应用程序解决相同错误的方法:
在创建对话框后添加以下行:

dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG);  

您不需要获取上下文。如果您要在当前弹出的对话框上弹出另一个对话框,或者获取上下文不方便时,这将特别有用。

希望这可以帮助您进行应用程序开发。

大卫


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接