对话引发getApplication()作为上下文,“无法添加窗口 – 标记null不适用于应用程序”

我的活动正在尝试创建一个需要上下文作为参数的AlertDialog。 如果使用:

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

然而,我不愿意使用“this”作为上下文,因为即使在像屏幕旋转这样简单的事情中,Activity被破坏并被重新创建时,由于内存泄漏的可能性。 从Android开发者博客上的相关文章 :

有两种简单的方法可以避免上下文相关的内存泄漏。 最明显的就是避免脱离自己范围之外的背景。 上面的例子显示了一个静态引用的情况,但是内部类和它们对外部类的隐式引用可能同样危险。 第二个解决方案是使用应用程序上下文。 只要您的应用程序处于活动状态,并且不依赖于活动的生命周期,此上下文就会生效。 如果您打算保留需要上下文的长寿命对象,请记住应用程序对象。 你可以通过调用Context.getApplicationContext()或者Activity.getApplication()来获得它。

但是对于AlertDialog() getApplicationContext()getApplication()都不能作为Context使用,因为它引发异常:

“无法添加窗口 – 标记null不适用于应用程序”

每个参考: 1,2,3等

那么,这是否真的被认为是一个“错误”,因为我们正式建议使用Activity.getApplication() ,但它不起到广告作用?

吉姆

而不是getApplicationContext() ,只需使用ActivityName.this

使用this不适合我,但MyActivityName.this 。 希望这可以帮助任何人不能得到this工作。

您可以继续使用getApplicationContext() ,但在使用之前,您应该添加此标志: dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT) ,并且不显示错误。

将以下权限添加到您的清单:

 <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" /> 

你的对话不应该是一个“需要上下文的长期对象”。 该文件是混乱。 基本上,如果你做这样的事情:

 static Dialog sDialog; 

(注意静态

然后在某个地方做一个活动

  sDialog = new Dialog(this); 

在旋转或类似的过程中,您可能会泄露原始活动,从而破坏活动。 (除非你清理onDestroy,但在这种情况下,你可能不会使对话框对象静态)

对于某些数据结构来说,将它们设置为静态并且基于应用程序的上下文是有意义的,但通常不适用于与UI相关的东西,比如对话框。 所以像这样的东西:

 Dialog mDialog; ... mDialog = new Dialog(this); 

是好的,不应该泄漏的活动,因为它不是静态的mDialog将被释放的活动。

您不能通过不是活动或服务上下文来显示应用程序window/dialog 。 尝试传递有效的活动参考

我不得不通过一个片段中显示的自定义适配器上的构造函数发送我的上下文,并与getApplicationContext()有此问题。 我解决了它:

在片段的onCreate回调中调用this.getActivity().getWindow().getContext()

Activity上单击显示一个对话框的按钮

 Dialog dialog = new Dialog(MyActivity.this); 

为我工作。

您已经正确地识别了问题,当您说“…对于AlertDialog()既不getApplicationContext()或getApplication()可接受作为上下文,因为它会引发异常:'无法添加窗口 – 标记null不适用一个应用程序'”

要创建对话框,您需要一个活动上下文服务上下文 ,而不是应用程序上下文 (getApplicationContext()和getApplication()都返回一个应用程序上下文)。

以下是如何获取活动上下文

(1)在活动或服务中:

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

(2)在片段中: AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());

内存泄漏不是“this”引用内在的问题,这个引用是对象引用自身的(即引用实际分配的内存来存储对象的数据)。 它发生在分配的内存超过其使用寿命之后,垃圾收集器(GC)无法释放的任何分配的内存。

大多数情况下,当一个变量超出范围时,内存将被GC回收。 但是,即使在对象已超过其使用寿命之后,对由变量持有的对象(例如“x”)的引用仍然存在,也可能发生内存泄漏。 只要“x”持有对它的引用,分配的内存就会丢失,因为只要该内存仍在被引用,GC 就不会释放内存。 有时,内存泄漏并不明显,因为引用了分配的内存 。 在这种情况下,GC将不会释放内存,直到所有对该内存的引用都被删除。

为了防止内存泄漏,请检查您的代码是否存在导致分配的内存被“this”(或其他引用)无限地引用的逻辑错误。 记得检查链参考。 以下是一些工具,可以帮助您分析内存使用情况,并找出那些讨厌的内存泄漏:

  • JRockit任务控制

  • JProbe的

  • YourKit

  • AD4J

小黑客:你可以防止通过GC破坏活动(当然,你不应该这样做,但它可以帮助在某些情况下):

 public class PostActivity extends Activity { ... private Context contextForDialog = null; ... public void onCreate(Bundle savedInstanceState) { ... contextForDialog = this; } ... private void showAnimatedDialog() { mSpinner = new Dialog(contextForDialog); mSpinner.setContentView(new MySpinner(contextForDialog)); mSpinner.show(); } ... } 

如果您正在使用片段并使用AlertDialog / Toast消息,则在上下文参数中使用getActivity()。

喜欢这个

 ProgressDialog pdialog; pdialog = new ProgressDialog(getActivity()); pdialog.setCancelable(true); pdialog.setMessage("Loading ...."); pdialog.show(); 

加入

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

清单中的"android.permission.SYSTEM_ALERT_WINDOW"/>

它现在适合我。 甚至关闭并打开应用程序后,当时给我的错误。

我在一个片段中使用ProgressDialog ,并在传递getActivity().getApplicationContext()作为构造函数参数时出现此错误。 将其更改为getActivity().getBaseContext()也不起作用。

为我工作的解决方案是通过getActivity() ; 即

progressDialog = new ProgressDialog(getActivity());

使用MyDialog md = new MyDialog(MyActivity.this.getParent());

如果你不在Activity中,那么你需要在你的函数“NameOfMyActivity.this”中使用Activity活动,例如:

 public static void showDialog(Activity activity) { AlertDialog.Builder builder = new AlertDialog.Builder(activity); builder.setMessage("Your Message") .setPositiveButton("Yes", dialogClickListener) .setNegativeButton("No", dialogClickListener).show(); } //Outside your Activity showDialog(NameOfMyActivity.this); 

如果您正在使用片段并使用AlertDialog / Toast消息,请在上下文参数中使用getActivity()

为我工作。

干杯!

尝试使用将在对话框下的活动的上下文。 但是,当你使用“this”这个关键字时要小心,因为这个关键字不会每次都有效。

例如,如果您将TabActivity作为带有两个选项卡的主机,并且每个选项卡都是另一个活动,并且如果您尝试从其中一个选项卡(活动)创建对话框,并且使用“this”,则会得到异常。案例对话框应该连接到托管所有东西和可见的主机活动。 (你可以说最可见的父Activity的上下文)

我没有从任何文档中找到这个信息,而是通过尝试。 这是我没有强大背景的解决方案,如果有人有更好的了解,随时发表评论。

在我的情况下工作:

 this.getContext(); 

尝试getParent()在新的AlertDialog.Builder(getParent())上下文的参数位置; 希望它会起作用,它为我工作。

我想这也可能发生,如果你试图显示一个线程,而不是主UI线程的对话框。

在这种情况下使用runOnUiThread()。

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

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

对于未来的读者,这应该有所帮助:

 public void show() { if(mContext instanceof Activity) { Activity activity = (Activity) mContext; if (!activity.isFinishing() && !activity.isDestroyed()) { dialog.show(); } } } 

看看API后,如果你在一个片段中,你可以传递对话你的activity或者getActivity,然后在返回方法中用dialog.dismiss()强制清理它以防止泄漏。

虽然在我所知的任何地方都没有明确说明,但似乎只是在OnClickHandlers中传回对话框才能做到这一点。