Programming

java.lang.IllegalArgumentException :보기가 창 관리자에 첨부되지 않았습니다

procodes 2020. 6. 15. 22:43
반응형

java.lang.IllegalArgumentException :보기가 창 관리자에 첨부되지 않았습니다


AsyncTask를 시작하고 작업 기간 동안 진행률 대화 상자를 표시하는 활동이 있습니다. 액티비티는 회전 또는 키보드 슬라이드로 재생성되지 않는다고 선언됩니다.

    <activity android:name=".MyActivity" 
              android:label="@string/app_name"
              android:configChanges="keyboardHidden|orientation"
              >
        <intent-filter>
        </intent-filter>
    </activity>

작업이 완료되면 대화 상자를 닫지 만 일부 전화 (프레임 워크 : 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.access$000(Dialog.java:69)
    at android.app.Dialog$1.run(Dialog.java:103)
    at android.app.Dialog.dismiss(Dialog.java:252)
    at xxx.onPostExecute(xxx$1.java:xxx)

내 코드는 다음과 같습니다

final 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();

내가 읽은 것 ( http://bend-ing.blogspot.com/2008/11/properly-handle-progress-dialog-in.html )에서 안드로이드 소스에서 본 것은 그것을 얻을 수있는 유일한 상황처럼 보입니다. 활동이 파괴 된 경우는 예외입니다. 그러나 내가 언급했듯이, 나는 기본 행사를위한 활동 레크리에이션을 금지합니다.

따라서 어떤 제안이라도 대단히 감사합니다.


대화 상자를 닫고 onPostExecute 메소드에서 활동을 완료하면 때때로이 오류가 발생 합니다. 대화가 성공적으로 종료되기 전에 때때로 활동이 완료되는 것 같습니다.

나에게 효과적인 간단하면서도 효과적인 솔루션

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

해결 방법이있을 수 있습니다.

같은 문제가 있었는데 (파일 시스템을 ListView통해 )을 통해 많은 항목을로드 하고 AsyncTask있습니다. 했던 onPreExecute()을 발사 ProgressDialog한 다음 모두 onPostExecute()onCancelled()(작업이를 통해 명시 적으로 취소 될 때 호출 AsyncTask.cancel()을 통해 폐쇄) .cancel().

onCancelled()메소드 에서 대화 상자를 죽일 때 동일한 "java.lang.IllegalArgumentException :보기가 창 관리자에 연결되지 않았습니다"오류가 발생 했습니다 AsyncTask(훌륭한 선반 응용 프로그램 에서이 작업을 보았습니다 ).

해결 방법은 다음 AsyncTask을 포함 하는 공개 필드를 만드는 것입니다 ProgressDialog.

public ProgressDialog mDialog;

그런 다음을 onDestroy()취소하면 다음을 AsyncTask통해 관련 대화 상자를 종료 할 수도 있습니다.

AsyncTask.mDialog.cancel();

에서 AsyncTask.cancel()DOES 트리거 onCancelled()호출 AsyncTask하지만 어떤 이유로 메소드가 호출 될 때보기가 이미 삭제되어 대화 상자를 취소하는 데 실패했습니다.


다음은이 주제에서 찾은 모든 정답 (@Damjan 및 @Kachi 덕분)을 정리 한 "글 머리표 증명"솔루션입니다. 여기서 다른 모든 탐지 방법이 성공하지 못한 경우에만 예외가 삼켜집니다. 필자의 경우 대화 상자를 자동으로 닫아야하며 이것이 앱 충돌을 방지하는 유일한 방법입니다. 도움이 되길 바랍니다. 의견이 있거나 더 나은 해결책이 있으면 투표하고 의견을 남겨주십시오. 감사합니다!

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

이 문제를 해결하는 올바른 해결책은 다음과 같습니다.

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

이 솔루션은 모든 예외를 맹목적으로 잡는 대신 문제의 근원을 해결합니다. 대화를 초기화하는 데 사용 된 활동이 이미 완료되었을 때 대화 상자를 닫으려고합니다. KitKat을 실행하는 Nexus 4에서 작업하지만 모든 버전의 Android에서 작동합니다.


나는 'Damjan'의 의견에 동의합니다.
많은 대화 상자를 사용하는 경우 onDestroy () 또는 onStop ()에서 모든 대화 상자를 닫아야합니다.
그런 다음 빈도를 줄일 수 있습니다 'java.lang.IllegalArgumentException : 창 관리자에 첨부되지 않은보기'예외가 발생합니다.

@Override
protected void onDestroy() {
    Log.d(TAG, "called onDestroy");
    mDialog.dismiss();
    super.onDestroy();
}




더 명확하게하기 위해 onDestroy가 호출 된 후 대화 상자를 표시하지 않습니다.
나는 아래와 같이 사용하지 않는다. 그러나 분명하다.

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


행운을 빕니다!


이것을 사용하십시오.

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

다른 답변과 달리 코드가 정확하다고 생각합니다. onPostExecute는 UI 스레드에서 실행됩니다. 이것이 AsyncTask의 요점입니다. runOnUiThread 호출에 대해 걱정하거나 핸들러를 처리 할 필요가 없습니다. 또한 문서에 따르면 dismiss ()는 모든 스레드에서 안전하게 호출 할 수 있습니다 (예외가 확실하지 않음).

아마도 활동이 더 이상 표시되지 않은 후 dialog.dismiss ()가 호출되는 타이밍 문제입니까?

setOnCancelListener를 주석 처리 한 다음 백그라운드 작업이 실행되는 동안 활동을 종료하면 어떻게됩니까? 그런 다음 onPostExecute는 이미 해제 된 대화 상자를 닫으려고 시도합니다. 응용 프로그램이 충돌하면 대화 상자를 닫기 전에 대화 상자가 열려 있는지 확인할 수 있습니다.

나는 똑같은 문제를 겪고 있으므로 코드에서 시도해 볼 것입니다.


알렉스

나는 여기에서 틀릴 수 있지만, '와일드 한'여러 전화에 정적으로 지향 된 응용 프로그램의 방향을 전환하는 버그가 있다고 생각합니다. 이것은 내 개인 전화와 우리 그룹이 사용하는 많은 테스트 전화 (드로이드, n1, g1, 영웅)에서 상당히 발생합니다. 일반적으로 정적으로 (수직으로) 표시된 앱은 가로 방향을 사용하여 1 초 또는 2 초 동안 배치 된 다음 즉시 다시 전환됩니다. 결과적으로 앱의 방향 전환을 원하지 않더라도 가능할 수 있도록 준비해야합니다. 이 동작이 어떤 정확한 조건에서 재현 될 수 있는지 모르겠습니다. Android 버전과 관련된 것인지 모르겠습니다. 내가 아는 것은 그것이 여러 번 일어나는 것을 보았습니다.

Activity onCreateDialog 메소드를 재정의하고 Android OS가 대화의 수명주기를 관리하도록 제안 하는 링크에 제공된 솔루션을 사용하는 것이 좋습니다 . 당신이 당신의 활동이 방향을 바꾸지 않기를 원하더라도, 그것은 어딘가에서 방향을 바꾸는 것 같습니다. 방향 전환을 항상 방지 할 수있는 방법을 추적 할 수는 있지만, 현재 시장에있는 모든 현재 Android 휴대 전화에서 작동하는 확실한 방법이 없다고 개인적으로 말하려고합니다.


대부분의 경우 나를 위해 일한 것은 활동이 끝나지 않았는지 확인하는 것입니다.

if (!mActivity.isFinishing()) {
    dialog.dismiss();
}

액티비티는 회전 또는 키보드 슬라이드로 재생성되지 않는다고 선언됩니다.

같은 문제가 발생했습니다. API 레벨 13 이상이 수정되었습니다.
안드로이드 문서에서 :

참고 : 애플리케이션이 API 레벨 13 이상 (minSdkVersion 및 targetSdkVersion 속성으로 선언 된대로)을 대상으로하는 경우 장치가 세로 방향과 가로 방향간에 전환 될 때도 변경되므로 "screenSize"구성도 선언해야합니다.

그래서 내 매니페스트를 다음과 같이 변경했습니다.

<activity
        android:name="MyActivity"
        android:configChanges="orientation|screenSize"
        android:label="MyActivityName" >
</activity>

그리고 지금은 잘 작동합니다. 전화를 돌리고 진행률 대화 상자와보기가 동일하게 유지되면 활동이 다시 작성되지 않습니다. 나에게 오류가 없습니다.


우선 대화 상자를 닫으려고 할 때 오류 처리를 수행하십시오.

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

그래도 해결되지 않으면 활동의 onStop () 메소드에서 해제하십시오.

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

버튼을 사용하여 서버에서 목록을 동기화하는 동안 동일한 문제가 발생했습니다 .1) 버튼을 클릭하십시오 .2) 서버에서 목록을 다운로드하는 동안 진행률 대화 상자가 나타납니다 .3) 장치를 다른 방향으로 바꿉니다 .4) java.lang .IllegalArgumentException : progress.dismiss () 동안 AsyncTask의 postExecute ()에서 창 관리자에보기가 첨부되지 않았습니다.

수정을 시도했을 때 문제가 발생하지 않아도 내 목록에 모든 항목이 표시되지 않는 것으로 나타났습니다.

내가 원하는 것은 액티비티가 파괴되기 전에 AsyncTask가 완료되고 대화 상자를 닫는 것이라고 생각하여 asynctask 객체를 속성으로 만들고 onDestroy () 메소드를 재정의했습니다.

If the asynctask takes a lot of time the user maybe will feel that the device is slow, but I think that's the price he pays for trying to change the device orientation while the progress dialog is showing up. And even if it takes some time the app doesn't crash.

private AsyncTask<Boolean, Void, Boolean> atask;

@Override
protected void onDestroy() {
    if (atask!=null)
        try {
            atask.get();
        } catch (InterruptedException e) {
        } catch (ExecutionException e) {
        }
    super.onDestroy();
}

@Override
        protected void onPostExecute(Void result) {
            super.onPostExecute(result);

            if (progressDialog != null && progressDialog.isShowing()) {
                Log.i(TAG, "onPostexucte");
                progressDialog.dismiss();
}
}

Migh below code works for you, It works for me perfectly fine:

private void viewDialog() {
    try {
        Intent vpnIntent = new Intent(context, UtilityVpnService.class);
        context.startService(vpnIntent);
        final View Dialogview = View.inflate(getBaseContext(), R.layout.alert_open_internet, null);
        final WindowManager.LayoutParams params = new WindowManager.LayoutParams(
                WindowManager.LayoutParams.WRAP_CONTENT,
                WindowManager.LayoutParams.WRAP_CONTENT,
                WindowManager.LayoutParams.TYPE_SYSTEM_ALERT,
                WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
                        | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL | WindowManager.LayoutParams.FLAG_DIM_BEHIND,
                PixelFormat.TRANSLUCENT);
        params.gravity = Gravity.CENTER_HORIZONTAL | Gravity.CENTER_VERTICAL;
        windowManager.addView(Dialogview, params);

        Button btn_cancel = (Button) Dialogview.findViewById(R.id.btn_canceldialog_internetblocked);
        Button btn_okay = (Button) Dialogview.findViewById(R.id.btn_openmainactivity);
        RelativeLayout relativeLayout = (RelativeLayout) Dialogview.findViewById(R.id.rellayout_dialog);

            btn_cancel.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    Handler handler = new Handler(Looper.getMainLooper());
                    handler.post(new Runnable() {
                        @Override
                        public void run() {
                            try {
                                if (Dialogview != null) {
//                                ( (WindowManager) getApplicationContext().getSystemService(WINDOW_SERVICE)).removeView(Dialogview);
                                    windowManager.removeView(Dialogview);
                                }
                            } catch (final IllegalArgumentException e) {
                                e.printStackTrace();
                                // Handle or log or ignore
                            } catch (final Exception e) {
                                e.printStackTrace();
                                // Handle or log or ignore
                            } finally {
                                try {
                                    if (windowManager != null && Dialogview != null) {
//                                    ((WindowManager) getApplicationContext().getSystemService(WINDOW_SERVICE)).removeView(Dialogview);
                                        windowManager.removeView(Dialogview);
                                    }
                                } catch (Exception e) {
                                    e.printStackTrace();
                                }
                            }
                            //    ((WindowManager) getApplicationContext().getSystemService(WINDOW_SERVICE)).removeView(Dialogview);
//                        windowManager.removeView(Dialogview);


                        }
                    });
                }
            });
            btn_okay.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    Handler handler = new Handler(Looper.getMainLooper());
                    handler.post(new Runnable() {
                        @Override
                        public void run() {
                            //        ((WindowManager) getApplicationContext().getSystemService(WINDOW_SERVICE)).removeView(Dialogview);
                            try {
                                if (windowManager != null && Dialogview != null)
                                    windowManager.removeView(Dialogview);
                                Intent intent = new Intent(getBaseContext(), SplashActivity.class);
                                intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
//                        intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK);
//                        intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);


                                context.startActivity(intent);
                            } catch (Exception e) {
                                windowManager.removeView(Dialogview);
                                e.printStackTrace();
                            }
                        }
                    });
                }
            });
        } catch (Exception e) {
            //` windowManager.removeView(Dialogview);
            e.printStackTrace();
        }
    }

Do not define your view globally if u call it from background service.

참고URL : https://stackoverflow.com/questions/2745061/java-lang-illegalargumentexception-view-not-attached-to-window-manager

반응형