活动已泄漏最初添加的窗口

这个错误是什么,为什么会发生?

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 here05-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 here05-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)
654493 次浏览

您试图在退出活动后显示一个对话框。

[编辑]

这个问题是谷歌Android开发者的热门搜索之一,因此,从评论中添加一些重要的观点,这可能对未来的研究者更有帮助,而不必深入评论对话。

答案1

您试图在退出活动后显示一个对话框。

答案2

这个错误在某些情况下可能有点误导(虽然答案仍然是完全准确的)-即在我的情况下未处理的异常抛出在AsyncTeam中,这导致活动关闭,然后打开进度对话框导致此所以“真正的”异常在日志中稍早一些

答案3

在您退出之前创建的Dialog实例上调用disms()

活动,例如在onPance()或onDestroy()中

解决方案是在退出Activity之前在viewP.java:183中创建的Dialog上调用dismiss(),例如在onPause()中。所有Windowss应该在离开Activity之前关闭。

如果您使用的是AsyncTask,可能该日志消息可能是欺骗性的。如果您在日志中查找,您可能会发现另一个错误,可能是AsyncTaskdoInBackground()方法中的一个错误,那就是使您当前的Activity爆炸,因此一旦AsyncTask回来…嗯,你知道其余的。其他一些用户已经在这里解释过了:-)

您可以通过一个简单/愚蠢的错误来获得此异常,例如,在显示了AlertDialog之后意外调用finish(),如果您错过了Switch语句中的中断调用语句…

   @Overridepublic void onClick(View v) {switch (v.getId()) {case R.id.new_button:openMyAlertDialog();break; <-- If you forget this the finish() method belowwill be called while the dialog is showing!case R.id.exit_button:finish();break;}}

finish()方法将关闭Activity,但AlertDialog仍在显示!

因此,当你专注地盯着代码,寻找糟糕的线程问题或复杂的编码等时,不要只顾树而不管森林。有时它可能只是像丢失的off语句一样简单和愚蠢。:)

我有同样的模糊错误信息,不知道为什么。根据前面答案的线索,我将非GUI调用mDialog.finish()更改为mDialog.dismiss(),错误消失了。这并没有影响我的小部件的行为,但它令人不安,很可能已经标记了一个重要的内存泄漏。

我遇到了同样的问题,找到了这个页面,虽然我的情况不同,但我在定义警报框之前从if块调用finish

所以,简单地调用dismiss是行不通的(因为它还没有被创建),但是在阅读了亚历克斯·沃洛沃伊的之后,回答并意识到这是导致它的警报框。我试图在if块内完成后添加一个返回语句,并解决了这个问题。

我以为一旦你调用完,它就会停止所有内容并在那里完成,但它没有。它似乎走到它所在的代码块的末尾,然后完成。

所以,如果你想实现一种情况,有时它会在执行某些代码之前完成,你必须在完成后立即放置一个返回语句,否则它会继续下去,并表现得像在代码块的末尾调用了完成,而不是在你调用它的地方。这就是为什么我得到所有这些奇怪的错误。

private picked(File aDirectory){if(aDirectory.length()==0){setResult(RESULT_CANCELED, new Intent());finish();return;}AlertDialog.Builder alert= new AlertDialog.Builder(this); // Start dialog builderalert.setTitle("Question").setMessage("Do you want to open that file?"+aDirectory.getName());alert.setPositiveButton("OK", okButtonListener).setNegativeButton("Cancel", cancelButtonListener);alert.show();}

如果你不把返回后,我叫完在那里,它会表现得好像你叫它后alert.show();,因此它会说,窗口泄漏完成后,你使对话框出现,即使不是这种情况,它仍然认为它是。

我想我会在这里添加这个,因为这显示了完成命令的行为不同,然后我认为它做到了,我猜还有其他人在我发现这个之前和我想的一样。

我在AlertDialog上错误地调用hide()而不是dismiss()触发了这个错误。

我最近遇到了同样的问题。

此问题背后的原因是活动在对话框被关闭之前被关闭。上述情况的发生有各种原因。上面帖子中提到的那些也是正确的。

我遇到了一种情况,因为在线程中,我正在调用一个抛出异常的函数。因为这个窗口被解雇,因此出现了异常。

我在我的视频播放器应用程序中得到这些日志。这些消息是在视频播放器关闭时抛出的。有趣的是,我曾经以随机的方式在几次运行中获得这些日志。此外,我的应用程序不涉及任何progressdialog。最后,我通过以下实现解决了这个问题。

@Overrideprotected void onPause(){Log.v("MediaVideo", "onPause");super.onPause();this.mVideoView.pause();this.mVideoView.setVisibility(View.GONE);}
@Overrideprotected void onDestroy(){Log.v("MediaVideo", "onDestroy");super.onDestroy();}
@Overrideprotected void onResume(){Log.v("MediaVideo", "onResume");super.onResume();this.mVideoView.resume();}

用调用mVideoView.pause()覆盖OnPause,并将visibility设置为GONE。这样我就可以解决“Activity has leaked window”日志错误问题。

当您尝试在Activity有效finished之后显示警报时,会发生“Activity has leaked window that was originally added...”错误。

您有两种选择AFAIK:

  1. 重新考虑您的警报的登录:在实际退出您的活动之前在dialog上调用dismiss()
  2. dialog放在不同的线程中,并在thread上运行它(独立于当前的activity)。

当您退出活动后尝试显示对话框时会出现此问题。

我只是通过写下以下代码来解决这个问题:

@Overridepublic void onDestroy(){super.onDestroy();if ( progressDialog!=null && progressDialog.isShowing() ){progressDialog.cancel();}}

基本上,你从哪个类开始进展Dialog,覆盖onDestroy方法并这样做。它解决了“活动已泄漏窗口”问题。

在我的情况下,原因是我忘记在Android清单文件中包含权限。

我是怎么发现的?嗯,就像@Bobby在已接受答案下方的评论中所说的那样,只需进一步滚动到您的日志,您将看到真正引发异常的第一个原因或事件。显然,消息“活动已泄漏最初添加的窗口”只是由第一个异常导致的异常。

不仅可以尝试显示警报,还可以在您完成特定活动实例并尝试启动新活动/服务或尝试停止它时调用它。

示例:

OldActivity instance;
oncreate() {instance=this;}instance.finish();instance.startActivity(new Intent(ACTION_MAIN).setClass(instance, NewActivity.class));

当ProgressDialog仍然显示时,我完成了一个活动。

因此,首先隐藏对话框,然后完成活动。

试试这个代码:

public class Sample extends Activity(){@Overridepublic void onCreate(Bundle instance){
}@Overridepublic void onStop() {super.onStop();progressdialog.dismiss(); // try this}
}

这可能有帮助。

if (! isFinishing()) {
dialog.show();
}

你必须在AsyncTaskonPreExecute方法中制作Progressdialog对象,你应该在onPostExecute方法中制作dismiss对象。

活动销毁时关闭对话框

@Overrideprotected void onDestroy(){super.onDestroy();if (pDialog!=null && pDialog.isShowing()){pDialog.dismiss();}}

如果您在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 donepDialog.dismiss();

只要确保你的活动不会因为代码中某处引发的一些异常而意外关闭。通常它发生在异步任务中,当活动在doin背景方法中面临强制关闭,然后异步任务返回到onPost执行方法时。

尝试下面的代码,它将在您关闭进度对话框的任何时间工作,它将查看其实例是否可用。

try {if (null != progressDialog && progressDialog.isShowing()) {progressDialog.dismiss();progressDialog = null;}} catch (Exception e) {e.printStackTrace();}

我正在使用视频播放器的onError对话框,而不是发疯(我已经测试了所有这些解决方案)

我选择了DialogFragmenthttp://developer.android.com/reference/android/app/DialogFragment.html

您可以在内部DialogFragment类中返回构建器创建,只需覆盖onCreateDialog

我有同样的问题。错误不在Dialog中,而是在EditText中。我试图在Assynctask中更改Edittext的值。我唯一能解决的就是创建一个新的runnable

runOnUiThread(new Runnable(){@Overridepublic void run() {...}});

窗口泄漏异常有两个原因:

1)当活动上下文不存在时显示对话框,为了解决这个问题,你应该只显示你确定活动存在的对话框:

if(getActivity()!= null && !getActivity().isFinishing()){Dialog.show();}

2)不适当地关闭对话框,要解决使用此代码:

@Overridepublic void onDestroy(){super.onDestroy();if ( Dialog!=null && Dialog.isShowing() ){Dialog.dismiss();}}

当我在AsyncTask中使用ProgressDialog时,这种情况发生在我身上。实际上我在onPostExecute中使用hide()方法。基于@Alex Volosey的回答,我需要使用dismiss()ProgressDialog来删除它在onPostExecute中并完成。

progressDialog.hide(); // Don't use it, it gives error
progressDialog.dismiss(); // Use it

我有另一个解决方案,想知道它是否对你有效:而不是在onDestroy中解雇,这似乎是主要的解决方案,我正在扩展ProgressDialog…

public class MyProgressDialog extends ProgressDialog {
private boolean isDismissed;
public MyProgressDialog(Context context) {super(context);}
@Overridepublic void onDetachedFromWindow() {super.onDetachedFromWindow();dismiss();}
@Overridepublic void dismiss() {if (isDismissed) {return;}try {super.dismiss();} catch (IllegalArgumentException e) {// ignore}isDismissed = true;}

这是更好的,AFAIC,因为你不必持有进度对话框作为成员,只需火(显示)和忘记

这不是问题的答案,但它与主题相关。

如果活动在清单中定义了一个属性

 android:noHistory="true"

然后在执行onP暂停()后,活动的上下文丢失。所以所有使用这个上下文的视图都可能会出现此错误。

我在运行猴子测试时也遇到了Windows泄漏问题。

android.support.v7.app.AppCompatDelegateImplV7$ListMenuDecorView@4334fd40 that was originally added hereandroid.view.WindowLeaked: Activity com.myapp.MyActivity has leaked window android.support.v7.app.AppCompatDelegateImplV7$ListMenuDecorView@4334fd40 that was originally added hereat 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)

我的活动是AppCompatActive。我在活动中使用以下代码重新整理了它。

@Overridepublic 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();}

我也遇到了这个问题一段时间,但我意识到这不是因为dialog在我的情况下,这是因为ActionMode。所以如果你试图在ActionMode打开时完成活动,它会导致这个问题。在你的活动的onPause中完成动作模式。

 private ActionMode actionMode;
@Overridepublic void onActionModeStarted(ActionMode mode) {super.onActionModeStarted(mode);actionMode = mode;}
@Overrideprotected void onPause() {super.onPause();if (actionMode != null) actionMode.finish();}

根据我的问题是,你试图调用一个对话框后,一个活动正在完成,所以根据我,你能做的是给一些延迟使用处理程序,你的问题将得到解决,例如:

 Handler handler=new Handler();handler.postDelayed(new Runnable() {@Overridepublic void run() {dialog.show();//ordialog.dismiss();
}},100);

这个问题的答案都是正确的,但对我来说,真正理解为什么有点困惑。在玩了大约两个小时后,这个错误的原因(在我的情况下)击中了我:

通过阅读其他答案,您已经知道hasX has leaked window DecorView@d9e6131[]错误意味着您的应用程序关闭时对话框处于打开状态。但是为什么呢?

可能是您的应用程序在对话框打开时因其他原因崩溃

这会导致您的应用程序关闭,因为您的代码中有一些bug,这会导致对话框在您的应用程序因其他错误而关闭的同时保持打开状态。

所以,看看你的逻辑。解决第一个错误,然后第二个错误会自己解决在这里输入图像描述

一个错误导致另一个错误,导致另一个错误,比如DOMINOS!

通常,此问题是由于进度对话框引起的:您可以通过在活动中使用以下任何一种方法来解决此问题:

 // 1):@Overrideprotected void onPause() {super.onPause();if ( yourProgressDialog!=null && yourProgressDialog.isShowing() ){yourProgressDialog.cancel();}}
// 2) :@Overrideprotected void onDestroy() {super.onDestroy();if ( yourProgressDialog!=null && yourProgressDialog.isShowing(){yourProgressDialog.cancel();}}

最好的解决方案是在异常发生时在try catch和dismise对话框中添加对话框

只需使用下面的代码

 try {dialog.show();} catch (Exception e) {dialog.dismiss();}

最好的解决方案是把这个放在显示progressbarprogressDialog之前

if (getApplicationContext().getWindow().getDecorView().isShown()) {
//Show Your Progress Dialog
}

尝试显示来自后台的Toast线程时出现此错误。它是通过在UI线程上运行UI相关代码来解决的

确保调用this.dialog.show(活动)

也许您在活动中使用了findViewById而不是dialog.findViewById,然后在null实例上设置了OnClickListener,这可能导致了原始错误。

如果您正在处理LiveData,当更新值而不是使用liveData.value = someValue时,请尝试执行liveData.postValue(someValue)

这是一个解决方案,当你确实想驳回 AlertDialog但不想保留引用到它里面的活动。

解决方案要求您在项目中具有androidx.lifecycle依赖项(我相信在评论的那一刻,这是一个常见的要求)

这允许您将对话框的解除委托给外部对象(观察者),并且您不再需要关心它,因为当活动死亡时它会自动取消订阅。(这里是证明:https://github.com/googlecodelabs/android-lifecycles/issues/5)。

所以,观察者保持对话框的引用,而活动保持对观察者的引用。当“onP暂停”发生时-观察者关闭对话框,当“onDestroy”发生时-活动删除观察者,所以不会发生泄漏(好吧,至少我再也看不到logcat中的错误了)

// observerclass DialogDismissLifecycleObserver( private var dialog: AlertDialog? ) : LifecycleObserver {@OnLifecycleEvent(Lifecycle.Event.ON_PAUSE)fun onPause() {dialog?.dismiss()dialog = null}}// activity codeprivate fun showDialog() {if( isDestroyed || isFinishing ) returnval dialog = AlertDialog.Builder(this, R.style.DialogTheme)// dialog setup skipped.create()lifecycle.addObserver( DialogDismissLifecycleObserver( dialog ) )dialog.show()}

我正在制作一个已经接近4.5万行的科学应用程序,我使用异步任务,以便能够中断长任务,如果需要的话,用户可以点击一下。

因此,存在响应式用户交互界面,有时并行执行长任务。

当长任务结束时,我需要运行一个管理用户交互界面的例程。

所以,在异步任务结束时,我做了一个涉及接口的操作,不能直接执行,否则会出错。所以我使用

this.runOnUiThread(Runnable { x(...)})   // Kotlin

很多时候,这个错误发生在函数x的某个点。

如果函数x在线程外调用

              x(...)  // Kotlin

Android Studio将显示一个带有错误行的调用堆栈,并且可以在几分钟内轻松解决问题。

由于我的源代码是驯服的,并且没有严重的结构问题(上面的许多答案描述了这种错误),这个可怕的错误消息的原因更严重,也不太重要。

它只是链接到线程的执行中的任何愚蠢错误(例如,访问超出定义长度的向量),如以下示意图示例所示:

           var i = 10                  // Kotlin...var arr = Array(5){""}var element = arr[i]       // 10 > 5, it's a index overflow

关于这个愚蠢的错误,不幸的是,Android Studio没有指出它。

我甚至认为这是一个bug,因为Android Studio知道有一个错误,它位于哪里,但是,由于某种未知的原因,它会丢失并给出一个随机消息,与问题完全脱节,即一个没有提示的奇怪消息。

解决方案:有很大的耐心在调试器中一步一步地运行,直到到达错误线,Android Studio拒绝提供。

这种情况在我身上发生过几次,我想这是android项目中非常常见的错误。在我使用线程之前,我从未给过我这种错误。

没有人是万无一失的,我们很容易犯小错误。在这种情况下,你不能指望Android Studio的直接帮助来发现你的错误在哪里!

活动销毁前关闭进度条

@Overrideprotected void onDestroy() {try {if (progressDialog != null)progressDialog.dismiss();} catch (Exception e) {e.printStackTrace();}super.onDestroy();}

如果只是处理 DialogActicity.onConfigurationChanged出现的问题

如果你只处理 Activity.onConfigurationChangedDialog的问题

//若`AndroidManifest.xml`中已经配置了`android:configChanges="orientation|screenSize|screenLayout|smallestScreenSize"`则不需要设置该项
//If `android:configChanges="orientation|screenSize|screenLayout|smallestScreenSize"` has been configured in `AndroidManifest.xml`, you do not need to set this item
Acticity/Context.registerComponentCallbacks(object : ComponentCallbacks {
override fun onConfigurationChanged(newConfig: Configuration) {
dialog?.dismiss()
}
override fun onLowMemory() {
}
})

onDestroy中销毁更保险点

on Destroy中销毁比较安全

override fun onDestroy() {
super.onDestroy()
DialogManager.dismiss()
}

也许这对你有用

我使用的是 Jetpack Compose,没有对话,所以这些答案大部分都不适用于我。结果发现,我正在访问 Kotlin Coroutine中的超出范围的数组索引。 我用 trycatch包装了所有的协同程序调用。

try {
viewModelScope.launch(Dispatchers.IO) {
....
}
} catch (e: Exception) {
Log.e("Exception: ", e.message.toString())
}

最后发现了错误(或者我应该说我的错误: P)。

唯一的答案是

  @Override
public void onBackPressed() {


exit_popup();
// super.onBackPressed(); remove this line


}

这就是我如何在活动的 finesh ()之前解决这个 bottom SheetDialog.release ()对话框的

  startActivity(Intent(this, Activity::class.java))
bottomSheetDialog.dismiss()
finish()

比之前的答案要晚得多,在2022年人们使用 Kotlin 时,当 Kotlin coroutine 试图从错误的(非 main) coroutine 上下文修改弹出窗口时,我们也得到了错误的答案。

产生错误:

CoroutineScope(Dispatchers.IO).launch{
someCodeThatNeedsOtherContext()
someViewBinding.someAttribute = someValue // We get the error here
}

不会产生错误:

CoroutineScope(Dispatchers.IO).launch{
someCodeThatNeedsOtherContext()
CoroutineScope(Dispatchers.Main).launch{
someViewBinding.someAttribute = someValue // No error here
}
}