活动泄漏了最初添加的窗口
这个错误是什么,为什么会发生?
05-17 18:24:57.069: ERROR/WindowManager(18850): Activity com.mypkg.myP has leaked window com.android.internal.policy.impl.PhoneWindow$DecorView@44c46ff0 that was originally added here 05-17 18:24:57.069: ERROR/WindowManager(18850): android.view.WindowLeaked: Activity ccom.mypkg.myP has leaked window com.android.internal.policy.impl.PhoneWindow$DecorView@44c46ff0 that was originally added here 05-17 18:24:57.069: ERROR/WindowManager(18850): at android.view.ViewRoot.<init>(ViewRoot.java:231) 05-17 18:24:57.069: ERROR/WindowManager(18850): at android.view.WindowManagerImpl.addView(WindowManagerImpl.java:148) 05-17 18:24:57.069: ERROR/WindowManager(18850): at android.view.WindowManagerImpl.addView(WindowManagerImpl.java:91) 05-17 18:24:57.069: ERROR/WindowManager(18850): at android.view.Window$LocalWindowManager.addView(Window.java:424) 05-17 18:24:57.069: ERROR/WindowManager(18850): at android.app.Dialog.show(Dialog.java:239) 05-17 18:24:57.069: ERROR/WindowManager(18850): at com.mypkg.myP$PreparePairingLinkageData.onPreExecute(viewP.java:183) 05-17 18:24:57.069: ERROR/WindowManager(18850): at android.os.AsyncTask.execute(AsyncTask.java:391) 05-17 18:24:57.069: ERROR/WindowManager(18850): at com.mypkg.myP.onCreate(viewP.java:94) 05-17 18:24:57.069: ERROR/WindowManager(18850): at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1047) 05-17 18:24:57.069: ERROR/WindowManager(18850): at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2544) 05-17 18:24:57.069: ERROR/WindowManager(18850): at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2621) 05-17 18:24:57.069: ERROR/WindowManager(18850): at android.app.ActivityThread.access$2200(ActivityThread.java:126) 05-17 18:24:57.069: ERROR/WindowManager(18850): at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1932) 05-17 18:24:57.069: ERROR/WindowManager(18850): at android.os.Handler.dispatchMessage(Handler.java:99) 05-17 18:24:57.069: ERROR/WindowManager(18850): at android.os.Looper.loop(Looper.java:123) 05-17 18:24:57.069: ERROR/WindowManager(18850): at android.app.ActivityThread.main(ActivityThread.java:4595) 05-17 18:24:57.069: ERROR/WindowManager(18850): at java.lang.reflect.Method.invokeNative(Native Method) 05-17 18:24:57.069: ERROR/WindowManager(18850): at java.lang.reflect.Method.invoke(Method.java:521) 05-17 18:24:57.069: ERROR/WindowManager(18850): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:860) 05-17 18:24:57.069: ERROR/WindowManager(18850): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:618) 05-17 18:24:57.069: ERROR/WindowManager(18850): at dalvik.system.NativeStart.main(Native Method)
在退出活动后,您正试图显示一个对话框。
[编辑]
这个问题是Android开发人员的谷歌最热门的search之一,因此,从评论添加一些重要的点,这可能会更有助于未来的调查,而不会深入的评论对话。
答案1 :
在退出活动后,您正试图显示一个对话框。
答案2
这个错误在某些情况下可能有些误导(尽pipe答案仍然是完全准确的) – 即在我的情况下,在AsyncTask中引发了一个未处理的Exception,导致Activityclosures,然后一个打开的progressdialog导致这个exception。日志中的“真正”例外情况稍早
答案3
在退出Activity之前创build的Dialog实例上调用dismiss(),例如在onPause()或onDestroy()
解决方法是在退出Activity
之前,在viewP.java:183
创build的Dialog
调用dismiss()
,例如在onPause()
。 所有的Window
和Dialog
应该在离开Activity
之前closures。
如果您使用的是AsyncTask
,那么这个日志消息可能是骗人的。 如果你在你的日志中查找,你可能会发现另一个错误,可能是你的AsyncTask
doInBackground()
方法中的一个错误,使得你的当前Activity
被炸毁,因此一旦AsyncTask
回来,rest。 其他一些用户已经在这里解释:-)
你可以通过一个简单/愚蠢的错误,例如,在显示AlertDialog
后意外地调用finish()
,如果你在switch语句中错过了一个break调用语句来得到这个exception…
@Override public void onClick(View v) { switch (v.getId()) { case R.id.new_button: openMyAlertDialog(); break; <-- If you forget this the finish() method below will be called while the dialog is showing! case R.id.exit_button: finish(); break; } }
finish()
方法将closuresActivity
,但AlertDialog
仍在显示!
所以当你专注于代码,寻找不好的线程问题或复杂的编码等,不要忽略了树木的森林。 有时,它可能只是一个简单和愚蠢的失踪断言。 🙂
我通过在AlertDialog
上错误地调用hide()
而不是dismiss()
来触发这个错误。
尝试在退出活动后显示对话框时出现此问题。
我只是写下下面的代码就解决了这个问题:
@Override public void onDestroy(){ super.onDestroy(); if ( progressDialog!=null && progressDialog.isShowing() ){ progressDialog.cancel(); } }
基本上,你从哪个类开始progressDialog,重写onDestroy方法,这样做。 它解决了“活动漏窗”的问题。
我最近面临同样的问题。
这个问题背后的原因是在对话被解散之前活动被closures。 发生上述情况有多种原因。 在上面的post中提到的也是正确的。
我陷入了一种情况,因为在线程中,我正在调用一个抛出exception的函数。 正因为如此,窗户被解雇,因此是例外。
我有相同的晦涩的错误信息,不知道为什么。 鉴于从以前的答案线索,我改变我的非GUI调用mDialog.finish()是mDialog.dismiss()和错误消失。 这并不影响我的小部件的行为,但这是令人不安的,可能已经标记了一个重要的内存泄漏。
我有同样的问题,发现这个网页,而我的情况是不同的,我叫一个if块完成之前,它定义了警报框。 所以简单地打电话解雇将不起作用(因为它还没有做),但在阅读亚历克斯Volovoy的答案,并意识到这是警报框造成它我试图添加一个返回语句后,完成内部,如果块和解决了这个问题。 我想,一旦你打完了,就停止了一切,并在那里完成。 但它并没有,它似乎完成了代码块的结束。 所以如果你想实现一个情况,有时它会在做一些代码之前完成,你必须在完成之后立即返回一个return语句,否则它将继续执行,并且在结束时调用完成的代码不在你叫它的地方。 这就是为什么我得到所有这些奇怪的错误。
private picked(File aDirectory) { if(aDirectory.length()==0){setResult(RESULT_CANCELED, new Intent()); finish(); return;} AlertDialog.Builder alert= new AlertDialog.Builder(this); // Start dialog builder alert.setTitle("Question").setMessage("Do you want to open that file?"+aDirectory.getName()); alert.setPositiveButton("OK", okButtonListener).setNegativeButton("Cancel", cancelButtonListener); alert.show(); }
如果你在我打完电话之后没有把这个回报放在那里,就会像在alert.show();
之后调用它alert.show();
因此,我说我在对话出现之后就完成了窗口的泄漏,尽pipe事实并非如此。 我想我会在这里添加这个,因为这表明完成命令的行为不同,然后我认为它做了,我猜想还有其他人像我之前发现的一样思考。
我在我的video播放器应用程序中获取这些日志。 video播放器closures时,这些消息被抛出。 有趣的是,我曾经以随机的方式在一些运行中得到这些日志。 另外我的应用程序不涉及任何progressdialog
。 最后,我用下面的实现来解决这个问题。
@Override protected void onPause() { Log.v("MediaVideo", "onPause"); super.onPause(); this.mVideoView.pause(); this.mVideoView.setVisibility(View.GONE); } @Override protected void onDestroy() { Log.v("MediaVideo", "onDestroy"); super.onDestroy(); } @Override protected void onResume() { Log.v("MediaVideo", "onResume"); super.onResume(); this.mVideoView.resume(); }
通过调用mVideoView.pause()
并设置GONE
visibility
来覆盖OnPause
。 这样我可以解决“ Activity has leaked window
”日志错误问题。
活动破坏时closures对话框
@Override protected void onDestroy() { super.onDestroy(); if (pDialog!=null && pDialog.isShowing()){ pDialog.dismiss(); } }
这可能有帮助。
if (! isFinishing()) { dialog.show(); }
不仅试图显示一个警报,但它可以调用,当你完成一个特定的活动实例,并尝试开始新的活动,服务或停止它..例如..
OldActivity instance; oncreate() { instance=this; } instance.finish(); instance.startActivity(new Intent(ACTION_MAIN).setClass(instance, NewActivity.class));
这不是问题的答案,而是与主题相关。
如果活动在Manifest中定义了一个属性
android:noHistory="true"
那么执行onPause()之后,活动的上下文就会丢失。 所以所有的视图使用这个上下文可能会给这个错误。
这可以是,如果你在doInBackground()
函数有一个错误,并有此代码。
最后尝试添加对话框。 首先检查并修复doInBackground()
函数
protected void onPreExecute() { super.onPreExecute(); pDialog = new ProgressDialog(CreateAccount.this); pDialog.setMessage("Creating Product.."); pDialog.setIndeterminate(false); pDialog.setCancelable(true); pDialog.show(); } protected String doInBackground(String...args) { ERROR CAN BE IS HERE } protected void onPostExecute(String file_url) { // dismiss the dialog once done pDialog.dismiss();
当Activity
有效finished
后,当您尝试显示警报时,会发生“ Activity has leaked window that was originally added...
”错误。
你有两个selectAFAIK:
- 反思您的警报login:在实际退出您的活动之前,请在
dialog
调用dismiss()
。 - 把
dialog
放在不同的线程中,并在该thread
上运行(与当前activity
无关)。
有ProgressDialog仍显示时,我完成一个活动的问题。
所以首先隐藏对话框,然后完成活动。
试试这个代码:
public class Sample extends Activity(){ @Override public void onCreate(Bundle instance){ } @Override public void onStop() { super.onStop(); progressdialog.dismiss(); // try this } }
这发生在我身上,当我在AsyncTask
使用ProgressDialog
。 其实我在onPostExecute
使用hide()
方法。 根据@Alex Volovoy的回答,我需要使用dismiss()
和ProgressDialog
在onPostExecute中将其删除。
progressDialog.hide(); // Don't use it, it gives error progressDialog.dismiss(); // Use it
您必须在AsyncTask
onPreExecute
方法中创buildProgressdialog
对象,并且您应该dismiss
onPostExecute
方法。
在我的情况下,原因是我忘记了在Android清单文件中包含权限。
我怎么知道的? 好吧,就像@Bobby在接受的答案下面的评论中所说的那样,只要进一步向上滚动到你的日志,你就会看到第一个真正抛出Exception的原因或事件。 显然,消息“活动泄漏了最初添加的窗口”仅仅是一个exception,无论第一个exception是什么。
尝试下面的代码,它将工作任何时候你会解雇的进展对话,它会看到它的实例是否可用。
try { if (null != progressDialog && progressDialog.isShowing()) { progressDialog.dismiss(); progressDialog = null; } } catch (Exception e) { e.printStackTrace(); }
这个问题的答案都是正确的,但是让我有点困惑的是要真正理解为什么。 玩了大约2个小时后,这个错误的原因(在我的情况)打我:
你已经知道,从阅读其他答案,已经X has leaked window DecorView@d9e6131[]
错误意味着一个对话框已经打开,当你的应用程序closures。 但为什么?
这可能是,你的应用程序在打开对话框时出于其他原因而崩溃
这会导致您的应用程序因为您的代码中的一些错误而closures,导致在您的应用程序由于其他错误而closures的同时保持打开对话框。
所以,看看你的逻辑。 解决第一个错误,然后第二个错误将自行解决
一个错误会导致另一个错误,如DOMINOS!
只要确保您的活动没有意外closures,因为在代码中某处引发了一些exception。 当doinBackground方法中的活动面向强制closures时,通常发生在asynchronous任务中,然后asynchronous请求返回到onPostexecute方法。
窗口泄漏exception有两个原因:
1)当Activity Context不存在时显示对话框,解决这个问题你应该只显示对话框你确定Activity存在:
if(getActivity()!= null && !getActivity().isFinishing()){ Dialog.show(); }
2)没有正确解除对话框,解决使用此代码:
@Override public void onDestroy(){ super.onDestroy(); if ( Dialog!=null && Dialog.isShowing() ){ Dialog.dismiss(); } }
我有同样的问题。 该错误不是在Dialog
而是在EditText
。 我试图改变一个Edittext
里的Assynctask
。 唯一能解决的就是创build一个新的runnable
。
runOnUiThread(new Runnable(){ @Override public void run() { ... } });
我正在使用一个video播放器的onError对话框,而不是发疯(我已经testing了所有这些解决scheme)
我select了DialogFragment
http://developer.android.com/reference/android/app/DialogFragment.html 。
您可以在内部DialogFragment
类中返回构build器创build,只需重写onCreateDialog
我有另一个解决scheme,并想知道它是否对您有用:而不是解雇onDestroy,这似乎是领先的解决scheme,我扩展ProgressDialog …
public class MyProgressDialog extends ProgressDialog { private boolean isDismissed; public MyProgressDialog(Context context) { super(context); } @Override public void onDetachedFromWindow() { super.onDetachedFromWindow(); dismiss(); } @Override public void dismiss() { if (isDismissed) { return; } try { super.dismiss(); } catch (IllegalArgumentException e) { // ignore } isDismissed = true; }
这是可取的,AFAIC,因为你不必把进度对话框作为一个成员,只是射击(显示),忘记
运行猴子testing时,我也遇到WindowLeaked问题。下面是logcat。
android.support.v7.app.AppCompatDelegateImplV7$ListMenuDecorView@4334fd40 that was originally added here android.view.WindowLeaked: Activity com.myapp.MyActivity has leaked window android.support.v7.app.AppCompatDelegateImplV7$ListMenuDecorView@4334fd40 that was originally added here at android.view.ViewRootImpl.<init>(ViewRootImpl.java:409) at android.view.WindowManagerImpl.addView(WindowManagerImpl.java:312) at android.view.WindowManagerImpl.addView(WindowManagerImpl.java:224) at android.view.WindowManagerImpl$CompatModeWrapper.addView(WindowManagerImpl.java:149) at android.view.Window$LocalWindowManager.addView(Window.java:554) at android.support.v7.app.AppCompatDelegateImplV7.openPanel(AppCompatDelegateImplV7.java:1150) at android.support.v7.app.AppCompatDelegateImplV7.onKeyUpPanel(AppCompatDelegateImplV7.java:1469) at android.support.v7.app.AppCompatDelegateImplV7.onKeyUp(AppCompatDelegateImplV7.java:919) at android.support.v7.app.AppCompatDelegateImplV7.dispatchKeyEvent(AppCompatDelegateImplV7.java:913) at android.support.v7.app.AppCompatDelegateImplBase$AppCompatWindowCallbackBase.dispatchKeyEvent(AppCompatDelegateImplBase.java:241) at com.android.internal.policy.impl.PhoneWindow$DecorView.dispatchKeyEvent(PhoneWindow.java:2009) at android.view.ViewRootImpl.deliverKeyEventPostIme(ViewRootImpl.java:3929) at android.view.ViewRootImpl.deliverKeyEvent(ViewRootImpl.java:3863) at android.view.ViewRootImpl.deliverInputEvent(ViewRootImpl.java:3420) at android.view.ViewRootImpl.doProcessInputEvents(ViewRootImpl.java:4528) at android.view.ViewRootImpl.enqueueInputEvent(ViewRootImpl.java:4506) at android.view.ViewRootImpl$WindowInputEventReceiver.onInputEvent(ViewRootImpl.java:4610) at android.view.InputEventReceiver.dispatchInputEvent(InputEventReceiver.java:171) at android.os.MessageQueue.nativePollOnce(Native Method) at android.os.MessageQueue.next(MessageQueue.java:125) at android.os.Looper.loop(Looper.java:124) at android.app.ActivityThread.main(ActivityThread.java:4898) at java.lang.reflect.Method.invokeNative(Native Method) at java.lang.reflect.Method.invoke(Method.java:511) at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1008) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:775) at dalvik.system.NativeStart.main(Native Method)
我的活动是AppCompatActivity.And我用下面的代码在活动中解决它。
@Override public boolean dispatchKeyEvent(KeyEvent event) { // added by sunhang : intercept menu key to resove a WindowLeaked error in monkey-test. if (event.getKeyCode() == KeyEvent.KEYCODE_MENU) { return true; } return super.dispatchKeyEvent(event); }
if (mActivity != null && !mActivity.isFinishing() && mProgressDialog != null && mProgressDialog.isShowing()) { mProgressDialog.dismiss(); }