android视图没有附加到窗口管理器

时间:2010-02-08 20:35:14

标签: android exception

我遇到以下一些例外情况:

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.access$700(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)

我用google搜索它,看到它与弹出窗口和转动屏幕有关,但没有引用我的代码。

问题是:

  1. 有没有办法找出答案 确切地说就是这个问题 发生?
  2. 除了转动屏幕外,还有其他事件或操作会触发此错误吗?
  3. 如何防止这种情况发生?

13 个答案:

答案 0 :(得分:158)

我遇到了这个问题,在屏幕方向改变时,活动在AsyncTask完成之前完成,进度对话框已完成。我似乎通过将对话框设置为null onPause()然后在解除之前在AsyncTask中检查它来解决此问题。

@Override
public void onPause() {
    super.onPause();

    if ((mDialog != null) && mDialog.isShowing())
        mDialog.dismiss();
    mDialog = null;
}

...在我的AsyncTask中:

protected void onPreExecute() {
    mDialog = ProgressDialog.show(mContext, "", "Saving changes...",
            true);
}

protected void onPostExecute(Object result) {
   if ((mDialog != null) && mDialog.isShowing()) { 
        mDialog.dismiss();
   }
}

答案 1 :(得分:9)

在与这个问题斗争之后,我最终得到了这个解决方法:

[math]::Round($Product1)[System.Midpoint.Rounding]::AwayFromZero) = Read-Host "Enter the price of your product: "

有时,如果没有更好的解决方案来解决此问题,那么良好的异常处理效果会很好。

答案 2 :(得分:4)

如果您有Activity个对象,可以使用isDestroyed()方法:

Activity activity;

// ...

if (!activity.isDestroyed()) {
    // ...
}

如果您在不同的地方使用非匿名AsyncTask子类,这很好。

答案 3 :(得分:2)

我将以下内容添加到该活动的清单

android:configChanges="keyboardHidden|orientation|screenLayout"

答案 4 :(得分:2)

我正在使用自定义静态类来制作并隐藏对话框。 其他活动也在使用这个课程,而不仅仅是一个活动。 现在你所描述的问题也出现在我面前,我一夜之间找到了解决方案..

最后,我向您介绍解决方案!

如果您想显示或关闭对话框而您不知道哪个活动启动了对话框以便触摸它,那么以下代码适合您..

 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;
                    }
                }


            }
        } 

 }

答案 5 :(得分:0)

问题1):

考虑到错误消息似乎没有说明代码的哪一行导致了问题,您可以使用断点来追踪它。当程序到达特定的代码行时,断点会暂停程序的执行。通过向关键位置添加断点,您可以确定导致崩溃的代码行。例如,如果你的程序在setContentView()行崩溃,你可以在那里放置一个断点。程序运行时,它会在运行该行之前暂停。如果然后恢复导致程序在到达下一个断点之前崩溃,那么您就知道杀死程序的行是在两个断点之间。

如果您正在使用Eclipse,则可以轻松添加断点。右键单击代码左侧的边距,然后选择“切换断点”。然后,您需要在调试模式下运行应用程序,该按钮看起来像正常运行按钮旁边的绿色昆虫。当程序遇到断点时,Eclipse将切换到调试透视图并向您显示它正在等待的行。要重新启动程序,请查找“恢复”按钮,该按钮看起来像普通的“播放”,但在三角形的左侧有一个垂直条。

您还可以使用Log.d(“我的应用程序”,“此处的一些信息告诉您日志行的位置”)填充您的应用程序,然后在Eclipse的LogCat窗口中发布消息。如果找不到该窗口,请使用Window打开它 - >显示视图 - >其他...... - > Android - > logcat中。

希望有所帮助!

答案 6 :(得分:0)

或者只是你可以添加

protected void onPreExecute() {
    mDialog = ProgressDialog.show(mContext, "", "Saving changes...", true, false);
}

会使ProgressDialog无法取消

答案 7 :(得分:0)

根据windowManager的代码(链接here),当您尝试更新的视图(可能属于对话框,但不是必需的)不再附加到真实根目录时窗户。

正如其他人所建议的那样,您应该在对话框上执行特殊操作之前检查活动的状态。

这是相关代码,这是问题的原因(从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;
        }
    }

答案 8 :(得分:0)

我的问题是通过在我的Android上运行屏幕旋转来解决的,这导致我的问题现在完美无缺

答案 9 :(得分:0)

另一个选择是在对话框通过覆盖对话框上的onAttachedToWindow()附加到窗口之前启动异步任务,这样总是可以允许。

答案 10 :(得分:0)

以上解决方案对我不起作用。所以我所做的是将ProgressDialog作为全局,然后将其添加到我的活动

@Override
    protected void onDestroy() {
        if (progressDialog != null && progressDialog.isShowing())
            progressDialog.dismiss();
        super.onDestroy();
    }

以便在活动被销毁的情况下,ProgressDialog也将被销毁。

答案 11 :(得分:-2)

为什么不尝试捕捉,像这样:

protected void onPostExecute(Object result) {
        try {
            if ((mDialog != null) && mDialog.isShowing()) {
                mDialog.dismiss();
            }
        } catch (Exception ex) {
            Log.e(TAG, ex.getMessage(), ex);
        }
    }

答案 12 :(得分:-3)

当您在清单中声明活动时,您需要android:configChanges =“orientation”

示例:

<activity android:theme="@android:style/Theme.Light.NoTitleBar" android:configChanges="orientation"  android:label="traducción" android:name=".PantallaTraductorAppActivity"></activity>