Erro: BinderProxy @ 45d459c0 não é válido; sua atividade está em execução?

143

O que é esse erro ... Eu não encontrei nenhuma discussão sobre esse erro na comunidade stackoverflow Detalhada: -

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
fonte
verifique este link: Android - [Exibindo caixas de diálogo a partir de threads de plano de fundo] ( dimitar.me/android-displaying-dialogs-from-background-threads )
Naveen
Seu link é semelhante à resposta aceita, mas é muito melhor que seja esperado. Obrigado por isso
LuckyMalaka

Respostas:

343

Provavelmente, isso está acontecendo porque você está tentando mostrar um diálogo após a execução de um encadeamento em segundo plano, enquanto a Atividade está sendo destruída.

Eu estava vendo esse erro relatado de vez em quando em alguns dos meus aplicativos quando a atividade que chamava a caixa de diálogo estava terminando por algum motivo ou outro quando tentava mostrar uma caixa de diálogo. Aqui está o que resolveu para mim:

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

Eu tenho usado isso para solucionar o problema nas versões mais antigas do Android há vários anos e não vi o acidente desde então.

DiscDev
fonte
1
Isso realmente faz o truque! mas existe uma maneira de abrir a caixa de diálogo mesmo se isso acontecer? Não tenho muita certeza de como gerenciar o diálogo quando isso acontecer. Alguma sugestão? Desde já, obrigado!
Carla Urrea Stabile
@CarlaStabile hi! A única maneira de pensar em mostrar uma caixa de diálogo quando isso acontecer seria se você pudesse obter um Contexto válido para uma atividade que não está terminando - isso dependeria de onde você está chamando esse código e se você tiver uma maneira de recuperar um contexto de outra atividade não finalizada.
DiscDev 23/06
8
Graças um milhão! Para mim, a falha (com mensagem de erro acima) aconteceria quando eu pressionasse o botão Voltar, antes da caixa de diálogo aparecer. Portanto, o código continuaria e tentaria mostrá-lo, mesmo que eu estivesse em uma atividade diferente. Mas isso parou o acidente e eu fui para a nova atividade com facilidade!
Azurespot 10/11/2015
1
Existem muitas perguntas semelhantes, mas em nenhuma delas foi sugerido isso. Pessoalmente, essa foi a única solução correta para o meu cenário.
fillobotto
qual é a versão do kotlin para isso? isFinishing () será suficiente?
Alok Rajasukumaran
12

Eu enfrentei o mesmo problema e usei o código proposto pelo DiscDev acima com pequenas alterações da seguinte maneira:

if (!MainActivity.this.isFinishing()){
    alertDialog.show();
}
Hamza Polat
fonte
Eu mudei porque (Activity) a média do contexto era MainActivity.this para o meu caso. Você também está certo sobre o link do perfil do usuário, mas achei que você pode encontrá-lo acima.
Hamza Polat
4

se a caixa de diálogo estiver solucionando esse problema por causa do encadeamento, execute-o no encadeamento da interface do usuário da seguinte maneira: -

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

            }
        });
Rahul Rao
fonte
2

Este erro ocorre quando você está mostrando a caixa de diálogo para um contexto que não existe mais.

Antes de ligar, .show()verifique se a atividade / contexto não está terminando

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

Eu encontrei esse erro quando eu tinha um countDownTimerno meu aplicativo. Ele tinha um método chamado GameOver no meu aplicativo como

public void onFinish() {
     GameOver();
}

mas na verdade o jogo poderia terminar antes que o tempo acabasse devido a um clique errado do usuário (era um jogo de clique). Então, quando eu estava olhando para a caixa de diálogo Game Over após, por exemplo, 20 segundos, esqueci de cancelar e, countDownTimerassim que o tempo acabou, a caixa de diálogo apareceu novamente. Ou caiu com o erro acima por algum motivo.

erdomester
fonte
1

A correção para isso é bem simples. Apenas teste se a Atividade está passando por sua fase de acabamento antes de exibir o Diálogo:

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

veja mais aqui

Diego Venâncio
fonte
1

No meu caso, o problema era que ela Contextera mantida como uma referência fraca na classe que se estende Handler. Então eu estava passando Messenger, que envolve o manipulador, através de um Intentpara um Service. Eu fazia isso toda vez que a atividade aparecia na tela no onResume()método.

Então, como você entende, o Messenger foi serializado junto com seus campos (incluindo o contexto), porque é a única maneira de passar objetos usando Intent - para serializá-los. No momento em que o Messenger foi passado para o serviço, a atividade em si ainda não estava pronta para mostrar caixas de diálogo, pois está em outro estado (sendo dito em Currículo (), que é absolutamente diferente de quando a atividade já está na tela). Portanto, quando o messenger foi desserializado, o contexto ainda estava no estado de retomada, enquanto a atividade já estava na tela. Além disso, a desserialização aloca memória para um novo objeto, que é completamente diferente do original.

A solução é apenas vincular ao serviço toda vez que você precisar e retornar um fichário com um método como 'setMessenger (Messenger messenger)' e chamá-lo quando estiver vinculado ao serviço.

Turkhan Badalov
fonte
1

Eu resolvo esse problema usando WeakReference<Activity>como contexto. O acidente nunca mais apareceu. Aqui está um código de exemplo no Kotlin:

Classe do gerenciador de diálogo:

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 você mostra a caixa de diálogo assim:

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

Se você deseja ser super protegido contra falhas. Em vez de builder.create().show()usar:

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

Este é o safeShowmétodo:

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

Este é um método semelhante que você pode usar para descartar com segurança a caixa de diálogo:

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
fonte
0

Que tal criar uma nova instância da caixa de diálogo que você deseja chamar? Na verdade, acabei de encontrar o mesmo problema, e é isso que faço. então, em vez de:

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

que tal agora?

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

então, em vez de apenas verificar se é seguro ou não mostrar a caixa de diálogo, acho que é muito mais seguro se apenas criarmos uma nova instância para mostrar a caixa de diálogo.

Como eu, no meu caso, tentei criar uma instância (de um Fragment onCreate ) e chamar a instância dessas caixas de diálogo em outro conteúdo do adapterList e isso resultará em "sua atividade está sendo executada" - erro . Eu pensei que era porque eu apenas criei uma instância (de onCreate) e ela será destruída, então, quando tentei chamá-la de outro adapterList , chamei o diálogo da instância antiga.

Não tenho certeza se minha solução é compatível com memória ou não, porque ainda não tentei criar um perfil, mas funciona (bem, certamente, é seguro se você não criar muitas instâncias)

Dan
fonte