Fehler: BinderProxy @ 45d459c0 ist ungültig. Läuft Ihre Aktivität?

143

Was ist dieser Fehler? Ich habe keine Diskussion zu diesem Fehler in der Stackoverflow-Community gefunden. Detailliert: -

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)
VISHAL DAGA
quelle
Überprüfen Sie diesen Link: Android - [ Anzeigen von Dialogen aus Hintergrund-Threads] ( dimitar.me/android-displaying-dialogs-from-background-threads )
Naveen
Ihr Link ähnelt der akzeptierten Antwort, ist aber viel besser erklärt. Vielen Dank dafür
LuckyMalaka

Antworten:

343

Dies geschieht höchstwahrscheinlich, weil Sie versuchen, nach der Ausführung eines Hintergrundthreads ein Dialogfeld anzuzeigen, während die Aktivität zerstört wird.

Dieser Fehler wurde gelegentlich von einigen meiner Apps gemeldet, als die Aktivität, die den Dialog aufruft, aus irgendeinem Grund beendet wurde, als versucht wurde, einen Dialog anzuzeigen. Folgendes hat es für mich gelöst:

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

Ich benutze dies seit einigen Jahren, um das Problem bei älteren Android-Versionen zu umgehen, und habe den Absturz seitdem nicht mehr gesehen.

DiscDev
quelle
1
Das macht tatsächlich den Trick! Aber gibt es eine Möglichkeit, den Dialog zu öffnen, auch wenn dies passiert? Ich bin mir nicht sicher, wie ich den Dialog verwalten soll, wenn dies passiert. Irgendwelche Vorschläge? Danke im Voraus!
Carla Urrea Stabile
@ CarlaStabile Hallo! Ich kann mir nur vorstellen, in diesem Fall einen Dialog anzuzeigen, wenn Sie einen gültigen Kontext für eine Aktivität erhalten, die noch nicht abgeschlossen ist. Dies hängt davon ab, wo Sie diesen Code aufrufen und ob Sie eine Möglichkeit haben, einen abzurufen Kontext aus einer anderen, nicht abschließenden Aktivität.
DiscDev
8
Tausend Dank! Für mich würde der Absturz (mit der obigen Fehlermeldung) auftreten, wenn ich die Zurück-Taste drückte, bevor das Dialogfeld angezeigt wurde. Der Code würde also fortgesetzt und versuchen, ihn anzuzeigen, obwohl ich mich in einer anderen Aktivität befand. Aber dies stoppte den Absturz und ich ging mit Leichtigkeit zur neuen Aktivität!
Azurespot
1
Es gibt viele ähnliche Fragen, aber in keiner von ihnen wurde dies vorgeschlagen. Persönlich war dies die einzig richtige Lösung für mein Szenario.
Fillobotto
Was ist die Kotlin-Version dafür? wird isFinishing () ausreichen?
Alok Rajasukumaran
12

Ich hatte das gleiche Problem und verwendete den von DiscDev oben vorgeschlagenen Code mit geringfügigen Änderungen wie folgt:

if (!MainActivity.this.isFinishing()){
    alertDialog.show();
}
Hamza Polat
quelle
Ich habe mich geändert, weil (Aktivitäts-) Kontextmittel MainActivity war. Dies ist für meinen Fall. Sie haben auch Recht mit dem Benutzerprofil-Link, aber ich dachte, dass Sie ihn oben finden können.
Hamza Polat
4

Wenn der Dialog dieses Problem aufgrund des Threads löst, sollten Sie dies auf dem UI-Thread folgendermaßen ausführen: -

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

            }
        });
Rahul Rao
quelle
2

Dieser Fehler tritt auf, wenn Sie das Dialogfeld für einen nicht mehr vorhandenen Kontext anzeigen.

.show()Überprüfen Sie vor dem Aufruf, ob die Aktivität / der Kontext nicht beendet ist

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

Ich bin auf diesen Fehler gestoßen, als ich einen countDownTimerin meiner App hatte. Es gab eine Methode, die GameOver in meiner App als aufrief

public void onFinish() {
     GameOver();
}

Tatsächlich konnte das Spiel jedoch aufgrund eines falschen Klicks des Benutzers vor Ablauf der Zeit beendet sein (es war ein Klickspiel). Als ich nach z. B. 20 Sekunden das Dialogfeld "Spielende" betrachtete, vergaß ich countDownTimer, das Dialogfeld abzubrechen. Sobald die Zeit abgelaufen war, wurde das Dialogfeld erneut angezeigt. Oder aus irgendeinem Grund mit dem obigen Fehler abgestürzt.

erdomester
quelle
1

Die Lösung dafür ist ziemlich einfach. Testen Sie einfach, ob die Aktivität ihre Abschlussphase durchläuft, bevor Sie den Dialog anzeigen:

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

Sehen Sie hier mehr

Diego Venâncio
quelle
1

In meinem Fall bestand das Problem darin, dass Contextes als schwache Referenz in der erweiterten Klasse beibehalten wurde Handler. Dann ging ich vorbei Messenger, das wickelt den Handler durch ein Intentzu ein Service. Ich tat dies jedes Mal, wenn die Aktivität in der onResume()Methode auf dem Bildschirm erschien .

Wie Sie verstehen, wurde Messenger zusammen mit seinen Feldern (einschließlich Kontext) serialisiert, da dies die einzige Möglichkeit ist, Objekte mit Intent- zu serialisieren. Zu dem Zeitpunkt, als Messenger an den Dienst übergeben wurde, war die Aktivität selbst noch nicht bereit, Dialoge anzuzeigen, da sie sich in einem anderen Zustand befindet (inResume () heißt das absolut anders, als wenn die Aktivität bereits auf dem Bildschirm angezeigt wird). Als der Messenger deserialisiert wurde, befand sich der Kontext noch im Wiederaufnahmezustand, während die Aktivität tatsächlich bereits auf dem Bildschirm angezeigt wurde. Darüber hinaus weist die Deserialisierung Speicher für ein neues Objekt zu, das sich vollständig vom ursprünglichen unterscheidet.

Die Lösung besteht darin, jedes Mal, wenn Sie ihn benötigen, an den Dienst zu binden und einen Ordner mit einer Methode wie "setMessenger (Messenger Messenger)" zurückzugeben und aufzurufen, wenn Sie an den Dienst gebunden sind.

Turkhan Badalov
quelle
1

Ich löse dieses Problem, indem ich es WeakReference<Activity>als Kontext verwende. Der Absturz ist nie wieder aufgetreten. Hier ist ein Beispielcode in Kotlin:

Dialog Manager Klasse:

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

}

Und Sie zeigen den Dialog folgendermaßen:

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

Wenn Sie vor Abstürzen geschützt sein wollen. Anstelle von builder.create().show()Verwendung:

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

Dies ist die safeShowMethode:

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

Dies ist eine ähnliche Methode, mit der Sie den Dialog sicher schließen können:

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
                    }
                }
            }
        }
    }
Ivo Stoyanov
quelle
0

Wie wäre es mit einer neuen Instanz dieses Dialogfelds, das Sie aufrufen möchten? Ich bin gerade auf das gleiche Problem gestoßen, und genau das mache ich. also eher als:

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

Wie wäre es damit?

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

Anstatt nur zu überprüfen, ob es sicher ist oder nicht, den Dialog anzuzeigen, ist es meiner Meinung nach viel sicherer, wenn wir nur eine neue Instanz erstellen , um den Dialog anzuzeigen.

Wie ich habe ich in meinem Fall versucht, eine Instanz (aus einem Fragment onCreate ) zu erstellen und die Instanz dieses Dialogfelds in einem anderen Inhalt von adapterList aufzurufen. Dies führt zu dem Fehler " Läuft Ihre Aktivität ? " . Ich dachte, das lag daran, dass ich nur eine Instanz (aus onCreate) erstelle und sie dann zerstört wird. Als ich versuchte, sie von einer anderen Adapterliste aus aufzurufen, rief ich den Dialog von einer alten Instanz aus auf.

Ich bin nicht sicher, ob meine Lösung speicherfreundlich ist oder nicht, da ich nicht versucht habe, sie zu profilieren, aber sie funktioniert (sicher ist es sicher, wenn Sie nicht zu viele Instanzen erstellen).

Dan
quelle