오류 : BinderProxy @ 45d459c0이 유효하지 않습니다. 활동이 진행 중입니까?


143

이 오류는 무엇입니까 ... 나는 stackoverflow 커뮤니티 에서이 오류에 대한 토론을 찾지 못했습니다. 자세한 :-

10-18 23:53:11.613: ERROR/AndroidRuntime(3197): Uncaught handler: thread main exiting due to uncaught exception
10-18 23:53:11.658: ERROR/AndroidRuntime(3197): android.view.WindowManager$BadTokenException: Unable to add window -- token android.os.BinderProxy@45d459c0 is not valid; is your activity running?
10-18 23:53:11.658: ERROR/AndroidRuntime(3197):     at android.view.ViewRoot.setView(ViewRoot.java:468)
10-18 23:53:11.658: ERROR/AndroidRuntime(3197):     at android.view.WindowManagerImpl.addView(WindowManagerImpl.java:177)
10-18 23:53:11.658: ERROR/AndroidRuntime(3197):     at android.view.WindowManagerImpl.addView(WindowManagerImpl.java:91)
10-18 23:53:11.658: ERROR/AndroidRuntime(3197):     at android.view.Window$LocalWindowManager.addView(Window.java:424)
10-18 23:53:11.658: ERROR/AndroidRuntime(3197):     at android.app.Dialog.show(Dialog.java:239)
10-18 23:53:11.658: ERROR/AndroidRuntime(3197):     at com.vishal.contacte.Locationlistener$MyLocationListener.onLocationChanged(Locationlistener.java:86)
10-18 23:53:11.658: ERROR/AndroidRuntime(3197):     at android.location.LocationManager$ListenerTransport._handleMessage(LocationManager.java:179)
10-18 23:53:11.658: ERROR/AndroidRuntime(3197):     at android.location.LocationManager$ListenerTransport.access$000(LocationManager.java:112)
10-18 23:53:11.658: ERROR/AndroidRuntime(3197):     at android.location.LocationManager$ListenerTransport$1.handleMessage(LocationManager.java:128)
10-18 23:53:11.658: ERROR/AndroidRuntime(3197):     at android.os.Handler.dispatchMessage(Handler.java:99)
10-18 23:53:11.658: ERROR/AndroidRuntime(3197):     at android.os.Looper.loop(Looper.java:123)
10-18 23:53:11.658: ERROR/AndroidRuntime(3197):     at android.app.ActivityThread.main(ActivityThread.java:4363)
10-18 23:53:11.658: ERROR/AndroidRuntime(3197):     at java.lang.reflect.Method.invokeNative(Native Method)
10-18 23:53:11.658: ERROR/AndroidRuntime(3197):     at java.lang.reflect.Method.invoke(Method.java:521)
10-18 23:53:11.658: ERROR/AndroidRuntime(3197):     at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:862)
10-18 23:53:11.658: ERROR/AndroidRuntime(3197):     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:620)
10-18 23:53:11.658: ERROR/AndroidRuntime(3197):     at dalvik.system.NativeStart.main(Native Method)

이 링크를 확인하십시오 : 안드로이드 – [배경 스레드에서 대화 상자 표시] ( dimitar.me/android-displaying-dialogs-from-background-threads )
Naveen

귀하의 링크는 허용 된 답변과 비슷하지만 훨씬 더 좋습니다.
그것에


답변:


343

이것은 활동이 파괴되는 동안 백그라운드 스레드를 실행 한 후 대화 상자를 표시하려고하기 때문에 발생했을 가능성이 큽니다.

대화 상자를 호출하는 활동이 대화 상자를 표시하려고 할 때 어떤 이유로 든 종료 될 때 일부 앱 에서이 오류가 가끔보고되었습니다. 나를 위해 그것을 해결 한 것은 다음과 같습니다.

if(!((Activity) context).isFinishing())
{
    //show dialog
}

나는 이것을 사용하여 몇 년 동안 이전 버전의 Android 에서이 문제를 해결했으며 그 이후로 충돌을 보지 못했습니다.


1
이것은 실제로 트릭을 수행합니다! 그러나 그런 경우에도 대화 상자를 여는 방법이 있습니까? 이 일이 발생할 때 대화 상자를 관리하는 방법을 잘 모르겠습니다. 어떤 제안? 미리 감사드립니다!
칼라 우레아 스태 빌레

@CarlaStabile 안녕하세요! 이것이 일어날 때 대화 상자를 표시한다고 생각할 수있는 유일한 방법은 완료되지 않은 활동에 대한 유효한 컨텍스트를 얻을 수있는 경우입니다.이 코드를 호출하는 위치와 검색 방법에 따라 다릅니다. 다른 비 마무리 활동의 맥락.
DiscDev 2016 년

8
정말 감사합니다! 나에게 대화 상자가 표시되기 전에 뒤로 버튼을 누르면 충돌이 발생했습니다 (위의 오류 메시지 포함). 따라서 다른 활동에 있어도 코드는 계속해서 표시하려고 시도합니다. 그러나 이것은 충돌을 멈추고 쉽게 새로운 활동에 갔다!
Azurespot

1
비슷한 질문이 많이 있지만 그중 누구도 이것을 제안하지 않았습니다. 개인적으로 이것은 내 시나리오에 대한 유일한 올바른 솔루션이었습니다.
fillobotto

이것에 대한 kotlin 버전은 무엇입니까? isFinishing ()으로 충분합니까?
Alok Rajasukumaran

12

나는 같은 문제에 직면하여 DiscDev가 제안한 코드 를 다음과 같이 약간 변경하여 사용했습니다.

if (!MainActivity.this.isFinishing()){
    alertDialog.show();
}

(Activity) 컨텍스트 평균이 MainActivity이기 때문에 변경되었습니다. 또한 당신은 사용자 프로필 링크에 관한 것이지만, 위에서 찾을 수 있다고 생각했습니다.
Hamza Polat

4

대화 상자가 스레드로 인해이 문제를 해결하는 경우 UI 스레드에서 다음과 같이 실행해야합니다.

runOnUiThread(new Runnable() {
            @Override
            public void run() {
                dialog.show();

            }
        });

2

이 오류는 더 이상 존재하지 않는 컨텍스트에 대한 대화 상자를 표시 할 때 발생합니다.

전화하기 전에 .show()활동 / 문맥이 끝나지 않았는지 확인하십시오

if (!(context instanceof Activity && ((Activity) context).isFinishing())) {
    alert.show();
}

1

countDownTimer내 앱에 있을 때이 오류가 발생했습니다 . 내 앱에서 GameOver를 호출하는 메소드가

public void onFinish() {
     GameOver();
}

그러나 실제로 사용자를 잘못 클릭하여 (클릭 게임) 시간이 끝나기 전에 게임이 종료 될 수 있습니다. 예를 들어 20 초 후에 Game Over 대화 상자를 볼 countDownTimer때 시간이 다되면 대화 상자가 다시 나타나지 않도록 취소하는 것을 잊었습니다 . 또는 어떤 이유로 위의 오류와 충돌했습니다.


1

이것에 대한 수정은 매우 간단합니다. 대화 상자를 표시하기 전에 활동이 마무리 단계를 거치고 있는지 테스트하십시오.

  private Handler myHandler = new Handler() {
  @Override
  public void handleMessage(Message msg) {
    switch (msg.what) {
      case DISPLAY_DLG:
        if (!isFinishing()) {
        showDialog(MY_DIALOG);
        }
      break;
    }
  }
};

여기참조


1

내 경우에는 문제는 Context확장하는 클래스에서 약한 참조로 유지되었다는 것 Handler입니다. 그런 다음 Messenger핸들러를 감싸는 을 통과 Intent했습니다 Service. 활동이 화면에 화면에 나타날 때 마다이 작업을 수행했습니다 onResume().

알다시피, 메신저는 필드를 사용하여 객체를 전달하는 유일한 방법이기 때문에-필드를 포함하여 필드와 함께 Intent직렬화되었습니다. 메신저가 서비스에 전달 된 순간에도 활동 자체는 다른 상태 (대화가 이미 화면에있을 때와는 완전히 다른 onResume ())이므로 대화 상자를 표시 할 준비가되지 않았습니다. 따라서 메신저가 직렬화 해제 될 때 컨텍스트는 여전히 재개 상태에있는 반면 활동은 실제로 화면에있었습니다. 또한 역 직렬화는 새 객체에 대한 메모리를 할당합니다. 이는 원래 객체와 완전히 다릅니다.

해결책은 필요할 때마다 서비스에 바인딩하고 'setMessenger (Messenger messenger)'와 같은 메서드가있는 바인더를 반환하고 서비스에 바인딩 될 때 호출하는 것입니다.


1

WeakReference<Activity>컨텍스트 로 사용하여이 문제를 해결합니다 . 충돌은 다시는 나타나지 않았다. 다음은 Kotlin의 샘플 코드입니다.

대화 관리자 클래스 :

class DialogManager {

        fun showAlertDialog(weakActivity: WeakReference<Activity>) {
            val wActivity = weakActivity.get()
            wActivity?.let {
                val builder = AlertDialog.Builder(wActivity, R.style.MyDialogTheme)
                val inflater = wActivity.layoutInflater
                val dialogView = inflater.inflate(R.layout.alert_dialog_info, null)
                builder.setView(dialogView)

                // Set your dialog properties here. E.g. builder.setTitle("MyTitle")

                builder.create().show()
            }
         }

}

그리고 당신은 다음과 같은 대화 상자를 보여줍니다 :

 val dialogManager = DialogManager()
 dialogManager.showAlertDialog(WeakReference<Activity>(this@MainActivity))

충돌로부터 슈퍼 듀퍼 보호를 원할 경우. 사용하는 대신 builder.create().show():

val dialog = builder.create()
safeShow(weakActivity, dialog)

이것이 safeShow방법입니다.

private fun safeShow(weakActivity: WeakReference<Activity>, dialog: AlertDialog?) {
        val wActivity = weakActivity.get()
        if (null != dialog && null != wActivity) {
            // Api >=17
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
                if (!dialog.isShowing && !(wActivity).isFinishing && !wActivity.isDestroyed) {
                    try {
                        dialog.show()
                    } catch (e: Exception) {
                        //Log exception
                    }
                }
            } else {

                // Api < 17. Unfortunately cannot check for isDestroyed()
                if (!dialog.isShowing && !(wActivity).isFinishing) {
                    try {
                        dialog.show()
                    } catch (e: Exception) {
                        //Log exception
                    }
                }
            }
        }
    }

이것은 대화 상자를 안전하게 닫는 데 사용할 수있는 비슷한 방법입니다.

private fun safeDismissAlertDialog(weakActivity: WeakReference<Activity>, dialog: AlertDialog?) {
        val wActivity = weakActivity.get()
        if (null != dialog && null != wActivity) {
            // Api >=17
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
                if (dialog.isShowing && !wActivity.isFinishing && !wActivity.isDestroyed) {
                    try {
                        dialog.dismiss()
                    } catch (e: Exception) {
                        //Log exception
                    }
                }
            } else {

                // Api < 17. Unfortunately cannot check for isDestroyed()
                if (!dialog.isShowing && !(wActivity).isFinishing) {
                    try {
                        dialog.dismiss()
                    } catch (e: Exception) {
                        //Log exception
                    }
                }
            }
        }
    }

0

전화를 걸고 싶은 대화 상자의 새 인스턴스를 만드는 방법은 무엇입니까? 나는 실제로 같은 문제를 만났으며 그것이 내가하는 일입니다. 그래서보다는

if(!((Activity) context).isFinishing())
{
    //show dialog
}

이건 어때요?

 YourDialog mDialog = new YourDialog();
 mDialog1.show(((AppCompatActivity) mContext).getSupportFragmentManager(), "OrderbookDialog");
                        }

대화 상자를 표시하는 것이 안전하지 않은지 확인하는 것이 아니라 대화 상자를 표시하는 새 인스턴스 를 만들면 훨씬 안전하다고 생각합니다 .

나처럼, 내 경우에는 내가 (A에서 하나 개의 인스턴스를 만들려고 조각 에서 onCreate 의 또 다른 내용의 그 대화의 인스턴스)와 전화 adapterList을 하고이 발생합니다 "활동이 실행되는"- 오류 . 나는 하나의 인스턴스 (onCreate에서)를 생성 한 다음 인스턴스가 파괴되어 다른 어댑터 목록 에서 호출하려고 할 때 이전 인스턴스에서 대화 상자 를 호출하기 때문이라고 생각했습니다 .

내 솔루션이 메모리 친화적인지 아닌지 확실하지 않습니다. 프로파일 링을 시도하지 않았지만 작동합니다 (너무 많은 인스턴스를 만들지 않으면 안전합니다)

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.