Android java.lang.IllegalArgumentException:视图未附加到窗口管理器
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/2745061/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
java.lang.IllegalArgumentException: View not attached to window manager
提问by alex2k8
I have an activity that starts AsyncTask and shows progress dialog for the duration of operation. The activity is declared NOT be recreated by rotation or keyboard slide.
我有一个活动,它启动 AsyncTask 并在操作期间显示进度对话框。活动声明为不能通过旋转或键盘滑动重新创建。
<activity android:name=".MyActivity"
android:label="@string/app_name"
android:configChanges="keyboardHidden|orientation"
>
<intent-filter>
</intent-filter>
</activity>
Once task completed, I dissmiss dialog, but on some phones (framework: 1.5, 1.6) such error is thrown:
任务完成后,我会关闭对话框,但在某些手机(框架:1.5、1.6)上会抛出此类错误:
java.lang.IllegalArgumentException: View not attached to window manager
at android.view.WindowManagerImpl.findViewLocked(WindowManagerImpl.java:356)
at android.view.WindowManagerImpl.removeView(WindowManagerImpl.java:201)
at android.view.Window$LocalWindowManager.removeView(Window.java:400)
at android.app.Dialog.dismissDialog(Dialog.java:268)
at android.app.Dialog.accessfinal Dialog dialog = new AlertDialog.Builder(context)
.setTitle("Processing...")
.setCancelable(true)
.create();
final AsyncTask<MyParams, Object, MyResult> task = new AsyncTask<MyParams, Object, MyResult>() {
@Override
protected MyResult doInBackground(MyParams... params) {
// Long operation goes here
}
@Override
protected void onPostExecute(MyResult result) {
dialog.dismiss();
onCompletion(result);
}
};
task.execute(...);
dialog.setOnCancelListener(new OnCancelListener() {
@Override
public void onCancel(DialogInterface arg0) {
task.cancel(false);
}
});
dialog.show();
0(Dialog.java:69)
at android.app.Dialog.run(Dialog.java:103)
at android.app.Dialog.dismiss(Dialog.java:252)
at xxx.onPostExecute(xxx.java:xxx)
My code is:
我的代码是:
@Override
protected void onPostExecute(MyResult result) {
try {
if ((this.mDialog != null) && this.mDialog.isShowing()) {
this.mDialog.dismiss();
}
} catch (final IllegalArgumentException e) {
// Handle or log or ignore
} catch (final Exception e) {
// Handle or log or ignore
} finally {
this.mDialog = null;
}
}
From what I have read (http://bend-ing.blogspot.com/2008/11/properly-handle-progress-dialog-in.html) and seen in Android sources, it looks like the only possible situation to get that exception is when activity was destroyed. But as I have mentioned, I forbid activity recreation for basic events.
从我读过的(http://bend-ing.blogspot.com/2008/11/properly-handle-progress-dialog-in.html)和在Android源代码中看到的,它看起来是唯一可能的情况例外是活动被破坏时。但正如我所提到的,我禁止基本事件的活动娱乐。
So any suggestions are very appreciated.
所以任何建议都非常感谢。
回答by Damjan
I too get this error sometimeswhen I dismiss dialog and finish activity from onPostExecute method. I guess sometimes activity gets finished before dialog successfully dismisses.
当我关闭对话框并从 onPostExecute 方法完成活动时,有时我也会收到此错误。我想有时活动会在对话成功解除之前完成。
Simple, yet effective solution that works for me
对我有用的简单而有效的解决方案
public void dismissWithCheck(Dialog dialog) {
if (dialog != null) {
if (dialog.isShowing()) {
//get the Context object that was used to great the dialog
Context context = ((ContextWrapper) dialog.getContext()).getBaseContext();
// if the Context used here was an activity AND it hasn't been finished or destroyed
// then dismiss it
if (context instanceof Activity) {
// Api >=17
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
if (!((Activity) context).isFinishing() && !((Activity) context).isDestroyed()) {
dismissWithTryCatch(dialog);
}
} else {
// Api < 17. Unfortunately cannot check for isDestroyed()
if (!((Activity) context).isFinishing()) {
dismissWithTryCatch(dialog);
}
}
} else
// if the Context used wasn't an Activity, then dismiss it too
dismissWithTryCatch(dialog);
}
dialog = null;
}
}
public void dismissWithTryCatch(Dialog dialog) {
try {
dialog.dismiss();
} catch (final IllegalArgumentException e) {
// Do nothing.
} catch (final Exception e) {
// Do nothing.
} finally {
dialog = null;
}
}
回答by Ivo Stoyanov
Here is my "bullet proof" solution, which is compilation of all good answers that I found on this topic (thanks to @Damjan and @Kachi). Here the exception is swallowed only if all other ways of detection did not succeeded. In my case I need to close the dialog automatically and this is the only way to protect the app from crash. I hope it will help you! Please, vote and leave comments if you have remarks or better solution. Thank you!
这是我的“防弹”解决方案,它是我在这个主题上找到的所有好的答案的汇编(感谢 @Damjan 和 @Kachi)。这里只有在所有其他检测方式都没有成功时才会吞下异常。就我而言,我需要自动关闭对话框,这是保护应用程序免于崩溃的唯一方法。我希望它会帮助你!如果您有意见或更好的解决方案,请投票并发表评论。谢谢!
public ProgressDialog mDialog;
回答by Paul Mennega
I may have a workaround.
我可能有一个解决方法。
Was having the same issue, where I am loading lots of items (via the file system) into a ListView
via an AsyncTask
. Had the onPreExecute()
firing up a ProgressDialog
, and then both onPostExecute()
and onCancelled()
(called when the task is cancelled explicitly via AsyncTask.cancel()
) closing it via .cancel()
.
遇到了同样的问题,我将大量项目(通过文件系统)加载到ListView
通过AsyncTask
. 有onPreExecute()
点火了ProgressDialog
,然后这两个onPostExecute()
和onCancelled()
(当任务是通过明确取消所谓AsyncTask.cancel()
通过关闭它).cancel()
。
Got the same "java.lang.IllegalArgumentException: View not attached to window manager" error when I was killing the dialog in the onCancelled()
method of the AsyncTask
(I'd seen this done in the excellent Shelves app).
当我在 的onCancelled()
方法中杀死对话框时,得到了相同的“java.lang.IllegalArgumentException: View not attach to window manager”错误AsyncTask
(我在优秀的Shelves 应用程序中看到过这个)。
The workaround was to create a public field in the AsyncTask
that contains the ProgressDialog
:
解决方法是在AsyncTask
包含以下内容的公共字段中创建ProgressDialog
:
AsyncTask.mDialog.cancel();
Then, in onDestroy()
when I cancel my AsyncTask
, I can also kill the associated dialog via:
然后,onDestroy()
当我取消 my 时AsyncTask
,我还可以通过以下方式终止关联的对话框:
public void hideProgress() {
if(mProgressDialog != null) {
if(mProgressDialog.isShowing()) { //check if dialog is showing.
//get the Context object that was used to great the dialog
Context context = ((ContextWrapper)mProgressDialog.getContext()).getBaseContext();
//if the Context used here was an activity AND it hasn't been finished or destroyed
//then dismiss it
if(context instanceof Activity) {
if(!((Activity)context).isFinishing() && !((Activity)context).isDestroyed())
mProgressDialog.dismiss();
} else //if the Context used wasnt an Activity, then dismiss it too
mProgressDialog.dismiss();
}
mProgressDialog = null;
}
}
Calling AsyncTask.cancel()
DOES trigger onCancelled()
in the AsyncTask
, but for some reason by the time that method is called, the View has already been destroyed and thus cancelling the dialog is failing.
调用AsyncTask.cancel()
DOES触发onCancelled()
的AsyncTask
,但由于某些原因通过该方法被调用的时候,查看已经被销毁,因此撤销对话框失败。
回答by Kachi
Here is the correct solution to solving this problem:
以下是解决此问题的正确解决方案:
@Override
protected void onDestroy() {
Log.d(TAG, "called onDestroy");
mDialog.dismiss();
super.onDestroy();
}
Instead of blindly catching all exceptions, this solution addresses the root of the problem: trying to dimiss a dialog when the activity used to initialize the dialog has already been finished. Working on my Nexus 4 running KitKat, but should work for all versions of Android.
该解决方案不是盲目地捕获所有异常,而是解决了问题的根源:当用于初始化对话框的活动已经完成时,尝试关闭对话框。在运行 KitKat 的 Nexus 4 上工作,但应该适用于所有版本的 Android。
回答by Hogun
i agree a opinion of 'Damjan'.
if you use many dialogs, should close all dialog in onDestroy() or onStop().
then you may be able to reduce the frequency 'java.lang.IllegalArgumentException: View not attached to window manager' exception occurs.
我同意“Damjan”的意见。
如果您使用多个对话框,应在 onDestroy() 或 onStop() 中关闭所有对话框。
那么您也许可以减少发生“java.lang.IllegalArgumentException: View not attach to window manager”异常的频率。
private boolean mIsDestroyed = false;
private void showDialog() {
closeDialog();
if (mIsDestroyed) {
Log.d(TAG, "called onDestroy() already.");
return;
}
mDialog = new AlertDialog(this)
.setTitle("title")
.setMessage("This is DialogTest")
.setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
}
})
.create();
mDialog.show();
}
private void closeDialog() {
if (mDialog != null) {
mDialog.dismiss();
}
}
@Override
protected void onDestroy() {
Log.d(TAG, "called onDestroy");
mIsDestroyed = true;
closeDialog();
super.onDestroy();
}
but little exceed...
to make it more clear, you prevent to show any dialog after onDestroy called.
i don't use as below. but it's clear.
但很少超过......
为了更清楚,您可以防止在调用 onDestroy 后显示任何对话框。
我不使用如下。但很清楚。
if(_dialog!=null && _dialog.isShowing())
_dialog.dismiss();
good luck!
祝你好运!
回答by Pralabh Jain
Use this.
用这个。
if(_dialog!=null && _dialog.isShowing()) _dialog.dismiss();
@Override protected void onPostExecute(MyResult result) { try { if ((this.mDialog != null) && this.mDialog.isShowing()) { this.mDialog.dismiss(); } } catch (final IllegalArgumentException e) { // Handle or log or ignore } catch (final Exception e) { // Handle or log or ignore } finally { this.mDialog = null; } }
回答by spacebiker
I had the same problem, you can solve it by:
我遇到了同样的问题,您可以通过以下方式解决:
if ((progressDialog != null) && progressDialog.isShowing()) {
progressDialog.dismiss();
progressDialog = null;
}
回答by Amit Patel
First of all do error handling where ever you trying to dismiss the dialog.
首先,在您尝试关闭对话框的地方进行错误处理。
@Override
protected void onStop() {
super.onStop();
if ((progressDialog != null) && progressDialog.isShowing()) {
progressDialog.dismiss();
progressDialog = null;
}
}
If that doesn't fix then dismiss it in onStop() Method of the activity.
如果这没有解决,则在活动的 onStop() 方法中关闭它。
<activity
android:name="MyActivity"
android:configChanges="orientation|screenSize"
android:label="MyActivityName" >
</activity>
回答by Shunt
The activity is declared NOT be recreated by rotation or keyboard slide.
活动声明为不能通过旋转或键盘滑动重新创建。
Just got the same problem. Fix for API level 13 or higer.
From Android docs:
刚刚遇到同样的问题。修复 API 级别 13 或更高。
来自 Android 文档:
Note: If your application targets API level 13 or higher (as declared by the minSdkVersion and targetSdkVersion attributes), then you should also declare the "screenSize" configuration, because it also changes when a device switches between portrait and landscape orientations.
注意:如果您的应用程序面向 API 级别 13 或更高级别(由 minSdkVersion 和 targetSdkVersion 属性声明),那么您还应该声明“screenSize”配置,因为当设备在纵向和横向之间切换时它也会发生变化。
So i've changed my manifest to this:
所以我已经改变了我的清单:
##代码##And now it works fine. Activity is not recreating when i rotate the phone, progress dialog and view stay the same. No error for me.
现在它工作正常。当我旋转手机时,活动不会重新创建,进度对话框和视图保持不变。对我来说没有错误。
回答by Brandon O'Rourke
I think your code is correct unlike the other answer suggested. onPostExecute will run on the UI thread. That's the whole point of AsyncTask - you don't have to worry about calling runOnUiThread or deal with handlers. Furthermore, according to the docs, dismiss() can be safely called from any thread (not sure they made this the exception).
与建议的其他答案不同,我认为您的代码是正确的。onPostExecute 将在 UI 线程上运行。这就是 AsyncTask 的全部意义——您不必担心调用 runOnUiThread 或处理处理程序。此外,根据文档,可以从任何线程安全地调用dismiss()(不确定他们是否将此作为例外)。
Perhaps it's a timing issue where dialog.dismiss() is getting called after the activity is no longer displayed?
也许这是一个时间问题,在不再显示活动后调用 dialog.dismiss() ?
What about testing what happens if you comment out the setOnCancelListener and then exit the activity while the background task is running? Then your onPostExecute will try to dismiss an already dismissed dialog. If the app crashes you can probably just check if the dialog is open before dismissing it.
如果在后台任务运行时注释掉 setOnCancelListener 然后退出活动,那么测试会发生什么?然后您的 onPostExecute 将尝试关闭已关闭的对话框。如果应用程序崩溃,您可以在关闭对话框之前检查对话框是否打开。
I'm having the exact same problem so I'm going to try it out in code.
我遇到了完全相同的问题,所以我将在代码中尝试一下。