android View未附加到窗口管理器
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/2224676/
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
android View not attached to window manager
提问by Daniel Benedykt
I am having some of the following exceptions:
我有以下一些例外情况:
java.lang.IllegalArgumentException: View not attached to window manager
at android.view.WindowManagerImpl.findViewLocked(WindowManagerImpl.java:355)
at android.view.WindowManagerImpl.updateViewLayout(WindowManagerImpl.java:191)
at android.view.Window$LocalWindowManager.updateViewLayout(Window.java:428)
at android.app.Dialog.onWindowAttributesChanged(Dialog.java:596)
at android.view.Window.setDefaultWindowFormat(Window.java:1013)
at com.android.internal.policy.impl.PhoneWindow.access0(PhoneWindow.java:86)
at com.android.internal.policy.impl.PhoneWindow$DecorView.drawableChanged(PhoneWindow.java:1951)
at com.android.internal.policy.impl.PhoneWindow$DecorView.fitSystemWindows(PhoneWindow.java:1889)
at android.view.ViewRoot.performTraversals(ViewRoot.java:727)
at android.view.ViewRoot.handleMessage(ViewRoot.java:1633)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:123)
at android.app.ActivityThread.main(ActivityThread.java:4338)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:521)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:860)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:618)
at dalvik.system.NativeStart.main(Native Method)
I have googled it and see that it has something to do with popups and turning the screen, but there is no reference to my code.
我用谷歌搜索它,发现它与弹出窗口和转动屏幕有关,但没有参考我的代码。
The questions are:
问题是:
- is there a way to find out exactly when this issue is happening?
- other than turning the screen, is there another event or action that triggers this error?
- how do I prevent this to happen?
- 有没有办法准确找出这个问题何时发生?
- 除了转动屏幕之外,是否还有其他事件或操作会触发此错误?
- 我如何防止这种情况发生?
回答by johnnyblizzard
I had this issue where on a screen orientation change, the activity finished before the AsyncTask with the progress dialog completed. I seemed to resolve this by setting the dialog to null onPause()
and then checking this in the AsyncTask before dismissing.
我遇到了这个问题,在屏幕方向改变时,活动在 AsyncTask 完成之前完成,进度对话框完成。我似乎通过将对话框设置为空来解决这个问题onPause()
,然后在关闭之前在 AsyncTask 中检查它。
@Override
public void onPause() {
super.onPause();
if ((mDialog != null) && mDialog.isShowing())
mDialog.dismiss();
mDialog = null;
}
... in my AsyncTask:
...在我的 AsyncTask 中:
protected void onPreExecute() {
mDialog = ProgressDialog.show(mContext, "", "Saving changes...",
true);
}
protected void onPostExecute(Object result) {
if ((mDialog != null) && mDialog.isShowing()) {
mDialog.dismiss();
}
}
回答by blueware
After a fight with this issue, I finally end up with this workaround:
经过与这个问题的斗争,我终于得到了这个解决方法:
/**
* Dismiss {@link ProgressDialog} with check for nullability and SDK version
*
* @param dialog instance of {@link ProgressDialog} to dismiss
*/
public void dismissProgressDialog(ProgressDialog dialog) {
if (dialog != null && 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 (!((Activity) context).isFinishing() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
if (!((Activity) context).isDestroyed()) {
dismissWithExceptionHandling(dialog);
}
} else {
// Api < 17. Unfortunately cannot check for isDestroyed()
dismissWithExceptionHandling(dialog);
}
}
} else
// if the Context used wasn't an Activity, then dismiss it too
dismissWithExceptionHandling(dialog);
}
dialog = null;
}
}
/**
* Dismiss {@link ProgressDialog} with try catch
*
* @param dialog instance of {@link ProgressDialog} to dismiss
*/
public void dismissWithExceptionHandling(ProgressDialog dialog) {
try {
dialog.dismiss();
} catch (final IllegalArgumentException e) {
// Do nothing.
} catch (final Exception e) {
// Do nothing.
} finally {
dialog = null;
}
}
Sometimes, good exception handling works well if there wasn't a better solution for this issue.
有时,如果此问题没有更好的解决方案,则良好的异常处理效果会很好。
回答by shawkinaw
If you have an Activity
object hanging around, you can use the isDestroyed()
method:
如果你有一个Activity
对象挂在身边,你可以使用这个isDestroyed()
方法:
Activity activity;
// ...
if (!activity.isDestroyed()) {
// ...
}
This is nice if you have a non-anonymous AsyncTask
subclass that you use in various places.
如果您有一个AsyncTask
在不同地方使用的非匿名子类,这很好。
回答by aimiliano
I am using a custom static class which makes- shows and hides a dialog. this class is being used by other activities too not only one activiy. Now the problem you described also appeared to me and i have stayed overnight to find a solution..
我正在使用一个自定义静态类,它可以显示和隐藏一个对话框。这个类也被其他活动使用,而不仅仅是一个活动。现在你描述的问题也出现在我身上,我已经过夜寻找解决方案。
Finally i present you the solution!
最后我给你介绍解决方案!
if you want to show or dismiss a dialog and you dont know which activity initiated the dialog in order to touch it then the following code is for you..
如果您想显示或关闭对话框,并且您不知道哪个活动启动了对话框以触摸它,那么以下代码适合您..
static class CustomDialog{
public static void initDialog(){
...
//init code
...
}
public static void showDialog(){
...
//init code for show dialog
...
}
/****This is your Dismiss dialog code :D*******/
public static void dismissProgressDialog(Context context) {
//Can't touch other View of other Activiy..
//http://stackoverflow.com/questions/23458162/dismiss-progress-dialog-in-another-activity-android
if ( (progressdialog != null) && progressdialog.isShowing()) {
//is it the same context from the caller ?
Log.w("ProgressDIalog dismiss", "the dialog is from"+progressdialog.getContext());
Class caller_context= context.getClass();
Activity call_Act = (Activity)context;
Class progress_context= progressdialog.getContext().getClass();
Boolean is_act= ( (progressdialog.getContext()) instanceof Activity )?true:false;
Boolean is_ctw= ( (progressdialog.getContext()) instanceof ContextThemeWrapper )?true:false;
if (is_ctw) {
ContextThemeWrapper cthw=(ContextThemeWrapper) progressdialog.getContext();
Boolean is_same_acivity_with_Caller= ((Activity)(cthw).getBaseContext() == call_Act )?true:false;
if (is_same_acivity_with_Caller){
progressdialog.dismiss();
progressdialog = null;
}
else {
Log.e("ProgressDIalog dismiss", "the dialog is NOT from the same context! Can't touch.."+((Activity)(cthw).getBaseContext()).getClass());
progressdialog = null;
}
}
}
}
}
回答by Kishan Solanki
Above solution didn't work for me. So what I did is take ProgressDialog
as globally and then add this to my activity
以上解决方案对我不起作用。所以我所做的是将其ProgressDialog
视为全局然后将其添加到我的活动中
@Override
protected void onDestroy() {
if (progressDialog != null && progressDialog.isShowing())
progressDialog.dismiss();
super.onDestroy();
}
so that in case if activity is destroyed then the ProgressDialog will also be destroy.
这样,如果活动被销毁,那么 ProgressDialog 也将被销毁。
回答by Steve Haley
For question 1):
对于问题 1):
Considering that the error message doesn't seem to say which line of your code is causing the trouble, you can track it down by using breakpoints. Breakpoints pause the execution of the program when the program gets to specific lines of code. By adding breakpoints to critical locations, you can determine which line of code causes the crash. For example, if your program is crashing at a setContentView() line, you could put a breakpoint there. When the program runs, it will pause before running that line. If then resuming causes the program to crash before reaching the next breakpoint, you then know that the line that killed the program was between the two breakpoints.
考虑到错误消息似乎没有说明是哪一行代码导致了问题,您可以使用断点进行跟踪。当程序到达特定的代码行时,断点会暂停程序的执行。通过在关键位置添加断点,您可以确定导致崩溃的代码行。例如,如果您的程序在 setContentView() 行崩溃,您可以在那里放置一个断点。当程序运行时,它会在运行该行之前暂停。如果然后恢复导致程序在到达下一个断点之前崩溃,那么您就会知道杀死程序的行位于两个断点之间。
Adding breakpoints is easy if you're using Eclipse. Right click in the margin just to the left of your code and select "Toggle breakpoint". You then need to run your application in debug mode, the button that looks like a green insect next to the normal run button. When the program hits a breakpoint, Eclipse will switch to the debug perspective and show you the line it is waiting at. To start the program running again, look for the 'Resume' button, which looks like a normal 'Play' but with a vertical bar to the left of the triangle.
如果您使用 Eclipse,添加断点很容易。右键单击代码左侧的边距,然后选择“切换断点”。然后您需要在调试模式下运行您的应用程序,该按钮看起来像正常运行按钮旁边的绿色昆虫。当程序遇到断点时,Eclipse 将切换到调试透视图并显示它正在等待的行。要重新开始运行程序,请查找“继续”按钮,它看起来像一个普通的“播放”按钮,但三角形左侧有一个垂直条。
You can also fill your application with Log.d("My application", "Some information here that tells you where the log line is"), which then posts messages in Eclipse's LogCat window. If you can't find that window, open it up with Window -> Show View -> Other... -> Android -> LogCat.
您还可以使用 Log.d("My application", "Some information here that tell you the log line is") 来填充您的应用程序,然后在 Eclipse 的 LogCat 窗口中发布消息。如果找不到该窗口,请使用 Window -> Show View -> Other... -> Android -> LogCat 打开它。
Hope that helps!
希望有帮助!
回答by Rickey
I added the following to the manifest for that activity
我在该活动的清单中添加了以下内容
android:configChanges="keyboardHidden|orientation|screenLayout"
回答by Sarith Vasu
Or Simply you Can add
或者干脆你可以添加
protected void onPreExecute() {
mDialog = ProgressDialog.show(mContext, "", "Saving changes...", true, false);
}
which will make the ProgressDialog
to not cancel-able
这将使ProgressDialog
无法取消
回答by android developer
according to the code of the windowManager (link here), this occurs when the view you are trying to update (which probably belongs to a dialog, but not necessary) is no longer attached to the real root of the windows.
根据 windowManager 的代码(链接here),当您尝试更新的视图(可能属于对话框,但不是必需的)不再附加到窗口的真正根时,就会发生这种情况。
as others have suggested, you should check the status of the activity before performing special operations on your dialogs.
正如其他人所建议的那样,您应该在对对话框执行特殊操作之前检查活动的状态。
here's the relavant code, which is the cause to the problem (copied from Android source code) :
这是相关代码,这是问题的原因(从Android源代码复制):
public void updateViewLayout(View view, ViewGroup.LayoutParams params) {
if (!(params instanceof WindowManager.LayoutParams)) {
throw new IllegalArgumentException("Params must be WindowManager.LayoutParams");
}
final WindowManager.LayoutParams wparams
= (WindowManager.LayoutParams)params;
view.setLayoutParams(wparams);
synchronized (this) {
int index = findViewLocked(view, true);
ViewRootImpl root = mRoots[index];
mParams[index] = wparams;
root.setLayoutParams(wparams, false);
}
}
private int findViewLocked(View view, boolean required) {
synchronized (this) {
final int count = mViews != null ? mViews.length : 0;
for (int i=0; i<count; i++) {
if (mViews[i] == view) {
return i;
}
}
if (required) {
throw new IllegalArgumentException(
"View not attached to window manager");
}
return -1;
}
}
回答by Roger
My problem was solved by uhlocking the screen rotation on my android the app which was causing me a problem now works perfectly
我的问题是通过在我的 android 上锁定屏幕旋转来解决的,导致我出现问题的应用程序现在可以完美运行