Errore: BinderProxy @ 45d459c0 non è valido; la tua attività è attiva?


143

Che cos'è questo errore ... Non ho trovato alcuna discussione su questo errore nella comunità di StackOverflow Dettagliata: -

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)

controlla questo link: Android - [Visualizzazione di finestre di dialogo da discussioni in background] ( dimitar.me/android-displaying-dialogs-from-background-threads )
Naveen

Il tuo link è simile alla risposta accettata, ma è molto più efficace. Grazie per questo
LuckyMalaka,


Risposte:


343

Molto probabilmente ciò accade perché stai cercando di mostrare una finestra di dialogo dopo l'esecuzione di un thread in background, mentre l'attività viene distrutta.

Stavo vedendo questo errore segnalato di tanto in tanto da alcune delle mie app quando l'attività che chiamava la finestra di dialogo stava finendo per un motivo o per l'altro quando ha provato a mostrare una finestra di dialogo. Ecco cosa mi ha risolto:

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

Sto usando questo per aggirare il problema sulle versioni precedenti di Android da diversi anni ormai, e da allora non ho più visto il crash.


1
Questo in realtà fa il trucco! ma c'è un modo per aprire la finestra di dialogo anche se ciò accade? Non sono davvero sicuro di come gestire la finestra di dialogo quando ciò accade. Eventuali suggerimenti? Grazie in anticipo!
Carla Urrea Stabile,

@CarlaStabile ciao! L'unico modo in cui posso pensare di mostrare una finestra di dialogo quando ciò accade sarebbe se puoi ottenere un contesto valido per un'attività che non sta finendo - dipenderà da dove stai chiamando questo codice e se hai un modo per recuperare un contesto da un'altra attività non finita.
DiscDev,

8
Grazie mille! Per me, l'incidente (con il messaggio di errore sopra) si sarebbe verificato quando ho premuto il pulsante Indietro, prima che la finestra di dialogo mostrasse. Quindi il codice continuerebbe e proverebbe a mostrarlo, anche se ero in un'altra attività. Ma questo ha fermato l'incidente e sono andato alla nuova attività con facilità!
Azurespot,

1
Ci sono molte domande simili, ma in nessuna di esse è stato suggerito questo. Personalmente questa era l'unica soluzione corretta per il mio scenario.
fillobotto,

qual è la versione di kotlin per questo? isFinishing () sarà sufficiente?
Alok Rajasukumaran,

12

Ho riscontrato lo stesso problema e ho usato il codice proposto da DiscDev sopra con lievi modifiche come segue:

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

ho cambiato perché la media del contesto (Activity) era MainActivity.questo per il mio caso. Inoltre hai ragione sul link del profilo utente, ma ho pensato che lo puoi trovare sopra.
Hamza Polat,

4

se la finestra di dialogo sta risolvendo questo problema a causa del thread, dovresti farlo in questo modo sul thread dell'interfaccia utente: -

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

            }
        });

2

Questo errore si verifica quando si visualizza la finestra di dialogo per un contesto che non esiste più.

Prima di chiamare .show()verificare che l'attività / il contesto non finisca

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

1

Ho riscontrato questo errore quando avevo un countDownTimernella mia app. Aveva un metodo per chiamare GameOver nella mia app come

public void onFinish() {
     GameOver();
}

ma in realtà il gioco potrebbe essere finito prima che il tempo fosse scaduto a causa di un clic sbagliato dell'utente (era un gioco di clic). Quindi, quando stavo guardando la finestra di dialogo Game Over dopo, ad esempio, 20 secondi, ho dimenticato di annullare l'operazione countDownTimer, una volta scaduto il tempo, la finestra di dialogo è riapparsa. O si è bloccato con l'errore sopra riportato per qualche motivo.


1

La soluzione è piuttosto semplice. Basta verificare se l'attività sta attraversando la sua fase finale prima di visualizzare la finestra di dialogo:

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

vedi di più qui


1

Nel mio caso, il problema era che Contextera mantenuto come un riferimento debole nella classe che si estende Handler. Poi stavo passando Messenger, che avvolge il gestore, attraverso una Intenta Service. Lo stavo facendo ogni volta che l'attività appariva sullo schermo con onResume()metodo.

Quindi, come capisci, Messenger è stato serializzato insieme ai suoi campi (incluso il contesto), perché è l'unico modo per passare oggetti usando Intent- per serializzarli. In quel momento in cui Messenger è stato passato al servizio, l'attività stessa non era ancora pronta per mostrare i dialoghi poiché si trova in un altro stato (detto su Resume (), che è assolutamente diverso da quando l'attività è già sullo schermo). Quindi, quando il messaggero era deserializzato, il contesto era ancora allo stato di ripresa, mentre l'attività era effettivamente già sullo schermo. Inoltre, la deserializzazione alloca la memoria per il nuovo oggetto, che è completamente diverso da quello originale.

La soluzione è solo quella di associarsi al servizio ogni volta che ne hai bisogno e restituire un raccoglitore che ha un metodo come 'setMessenger (Messenger messenger)' e chiamarlo, quando sei vincolato al servizio.


1

Risolvo questo problema usando WeakReference<Activity>come contesto. L'incidente non è mai più apparso. Ecco un codice di esempio in Kotlin:

Classe gestore dialoghi:

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

}

E mostri la finestra di dialogo in questo modo:

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

Se vuoi essere super-duper protetto dagli arresti anomali. Invece di builder.create().show()usare:

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

Questo è il safeShowmetodo:

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

Questo è un metodo simile che potresti usare per chiudere in sicurezza la finestra di dialogo:

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

che ne dici di creare una nuova istanza di quella finestra di dialogo che vuoi chiamare? In realtà ho appena incontrato lo stesso problema, ed è quello che faccio. quindi piuttosto che:

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

cosa ne pensi di questo?

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

quindi piuttosto che controllare è sicuro o non mostrare la finestra di dialogo, penso che sia molto più sicuro se creiamo semplicemente una nuova istanza per mostrare la finestra di dialogo.

Come me, nel mio caso ho provato a creare un'istanza (da un frammento su creazione ) e chiamare l'istanza di quelle finestre di dialogo in un altro contenuto di adapterList e questo si tradurrà in "è la tua attività in esecuzione" - errore . Ho pensato che fosse perché ho appena creato un'istanza (da onCreate) e poi è stata distrutta, quindi quando ho provato a chiamarla da un altro AdapterList ho chiamato la finestra di dialogo dalla vecchia istanza.

Non sono sicuro che la mia soluzione sia compatibile con la memoria o meno, perché non ho provato a profilarla, ma funziona (sicuramente, è sicuro se non crei troppe istanze)

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.