728x90

 

해당 에러 로그

 

Fatal Exception: android.view.WindowManager$BadTokenException

 

 

Fatal Exception: android.view.WindowManager$BadTokenException: Unable to add window -- token android.os.BinderProxy@66e8c4 is not valid; is your activity running?
       at android.view.ViewRootImpl.setView(ViewRootImpl.java:1056)
       at android.view.WindowManagerGlobal.addView(WindowManagerGlobal.java:381)
       at android.view.WindowManagerImpl.addView(WindowManagerImpl.java:93)
       at android.app.Dialog.show(Dialog.java:470)
       at 에러난 액티비티.onRequestComplete(ProductionManagementActivityRe.java:406)
       at android.os.AsyncTask$InternalHandler.handleMessage(AsyncTask.java:715)
       at android.os.Handler.dispatchMessage(Handler.java:106)
       at android.os.Looper.loop(Looper.java:214)
       at android.app.ActivityThread.main(ActivityThread.java:7063)
       at java.lang.reflect.Method.invoke(Method.java)
       at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)
       at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:964)

 

 

원인1:

BadTokenException이 발생한 원인을 파악하기 위해 오류를 재현하던 중, 같은 코드라도 쓰레드 위치나 라이프 사이클 상의 시점에 따라 간헐적으로 발생하는 것을 발견했다. 쓰레드 위치는 Main Thread가 아닌 Background Thread에서, 주로 AsyncTask의 onPostExecute() 메소드에서 다이얼로그 창을 통해 사용자에게  무엇인가를 알려주려고 시도하는 경우 간헐적으로 발생한다. 발생하는 시점은 Background Thread의 작업이 모두 종료되기 전에 뒤로가기 버튼을 누르거나 명시적으로 finish()메소드를 호출할 때이다. BadTokenException의 이유를 한문장으로 정리하면 , 예외 메시지에 ”is your activity running?” 이라고 명시되어 있듯 종료된 Activity의 context를 인자로 다이얼로그 창을 표시하려고 할 때 발생한다. 다이얼로그 창을 표시할 Activity가 없기 때문에 안드로이드 런타임이 나쁜 토큰(Bad Token1))이라는 예외를 던진다.

 

해결방법1:

해당 UI들을 사용할 때, Activity가 종료되었는 지를 확인하면된다. 만약 종료되었다면 다이얼로그 창을 열지 않으면 그만이다. 다음과 같이 isFinishing() 메소드를 사용하면 Activity의 종료 여부를 확인할 수 있다.

if (! ThisActivity.this.isFinishing()) {
    AlertDialog.builder dialog  = new AlertDialog.builder(ThisActivity.this);
    dialog.setTitle(status);
    dialog.setMessage(message);
    dialog.show();
}

 

원인2: 아래와 같이 activity 하위에 fragment가 있고, 그 중 한 곳에서 dialog를 사용할 때,

AlertDialog.Builder alertDialog = new AlertDialog.Builder(activity);

getActvitiy()가 아니라, activity로 했을 경우

 

 

해결방법2:

activity 일때와 fragment 일때 구분 해서 parameter 값을 넣어주는게 좋은거 같음

activity 대신에 getActivity() 로 하기

final AlertDialog.Builder alertDialog = new AlertDialog.Builder(getActivity());

 

 

원인3: (그런데 위의 2가지 케이스와 달리) 액티비티가 아닌 곳에서 발생한다면? 위 방법을 사용 할 수 없다. 참으로 희한하게도 context는 분명 들어 있는데 다이얼로그를 띄우면 죽는다. 액티비티를 종료 한 것도 아닌데... 보통 해당 프리퍼런스에서 다이얼로그를 띄운뒤 앱을 back키로 디스트로(destroy)이 한 뒤 다시 들어와서 해당 프리퍼런스의 다이얼로그를 띄우면 100% 죽는다. 이 경우에는 context를 static으로 만들어 주면 해결 된다. 


 

 

Reference

https://blog.sangyoung.me/2016/12/28/BadTokenException/

https://cishome.tistory.com/71

https://comoi.io/164

 

728x90

+ Recent posts