[android] Android View가 창 관리자에 연결되지 않았습니다.

다음 예외 중 일부가 있습니다.

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)

나는 그것을 봤고 그것이 팝업과 화면을 돌리는 것과 관련이 있음을 보았지만 내 코드에 대한 참조는 없습니다.

질문은 다음과 같습니다.

  1. 이 문제가 언제 발생하는지 정확히 알 수있는 방법이 있습니까?
  2. 화면을 돌리는 것 외에이 오류를 유발하는 다른 이벤트 나 조치가 있습니까?
  3. 이런 일이 발생하지 않도록 어떻게 방지합니까?


답변

화면 방향 변경에서 진행률 대화 상자가있는 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();
   }
}


답변

이 문제와 싸운 후 마침내이 해결 방법으로 끝납니다.

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

때로는이 문제에 대한 더 나은 해결책이 없다면 좋은 예외 처리가 잘 작동합니다.


답변

Activity주위에 물체 가있는 경우 다음 isDestroyed()방법을 사용할 수 있습니다 .

Activity activity;

// ...

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

AsyncTask여러 장소에서 사용 하는 비 익명 서브 클래스가 있다면 좋습니다.


답변

대화 상자를 만들고 숨기는 사용자 정의 정적 클래스를 사용하고 있습니다. 이 클래스는 하나의 활동뿐만 아니라 다른 활동에서도 사용되고 있습니다. 이제 당신이 묘사 한 문제도 나에게 나타 났고 나는 해결책을 찾기 위해 밤새 머물렀다 ..

마지막으로 해결책을 제시합니다!

대화 상자를 표시하거나 닫고 싶은데 터치하기 위해 대화를 시작한 활동을 모르는 경우 다음 코드가 적합합니다.

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


            }
        }

 }


답변

위의 솔루션은 나를 위해 작동하지 않았습니다. 그래서 제가 한 것은 ProgressDialog전 세계적으로 취한 다음 이것을 내 활동에 추가하는 것입니다.

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

활동이 파괴되면 ProgressDialog도 파괴됩니다.


답변

질문 1) :

오류 메시지가 코드의 어떤 줄이 문제를 일으키는 지 알려주지 않는 것 같다는 점을 고려할 때 중단 점을 사용하여 추적 할 수 있습니다. 중단 점은 프로그램이 특정 코드 줄에 도달하면 프로그램 실행을 일시 중지합니다. 중요한 위치에 중단 점을 추가하여 충돌을 일으키는 코드 줄을 확인할 수 있습니다. 예를 들어 프로그램이 setContentView () 행에서 충돌하는 경우 여기에 중단 점을 넣을 수 있습니다. 프로그램이 실행되면 해당 줄을 실행하기 전에 일시 중지됩니다. 재개로 인해 다음 중단 점에 도달하기 전에 프로그램이 중단되면 프로그램을 종료 한 줄이 두 중단 점 사이에 있다는 것을 알 수 있습니다.

Eclipse를 사용하는 경우 중단 점을 추가하는 것은 쉽습니다. 코드 바로 왼쪽 여백을 마우스 오른쪽 버튼으로 클릭하고 “Toggle breakpoint”를 선택합니다. 그런 다음 일반 실행 버튼 옆에있는 녹색 곤충 모양의 버튼 인 디버그 모드에서 애플리케이션을 실행해야합니다. 프로그램이 중단 점에 도달하면 Eclipse는 디버그 퍼스펙티브로 전환하고 대기중인 라인을 표시합니다. 프로그램 실행을 다시 시작하려면 일반 ‘재생’처럼 보이지만 삼각형 왼쪽에 세로 막대가있는 ‘다시 시작’버튼을 찾으십시오.

또한 애플리케이션을 Log.d ( “My application”, “여기에 로그 행이있는 위치를 알려주는 정보”)로 채우면 Eclipse의 LogCat 창에 메시지가 게시됩니다. 해당 창을 찾을 수없는 경우 창->보기 표시-> 기타 …-> Android-> LogCat을 사용하여 엽니 다.

도움이 되었기를 바랍니다.


답변

해당 활동의 매니페스트에 다음을 추가했습니다.

android:configChanges="keyboardHidden|orientation|screenLayout"