Minha atividade está tentando criar um AlertDialog que requer um contexto como parâmetro. Isso funciona como esperado se eu usar:
AlertDialog.Builder builder = new AlertDialog.Builder(this);
No entanto, desconfio de usar "this" como um contexto devido ao potencial de vazamento de memória quando a Activity é destruída e recriada, mesmo durante algo simples como uma rotação de tela. Em uma postagem relacionada no blog do desenvolvedor do Android :
Existem duas maneiras fáceis de evitar vazamentos de memória relacionados ao contexto. O mais óbvio é evitar escapar do contexto fora de seu próprio escopo. O exemplo acima mostrou o caso de uma referência estática, mas as classes internas e sua referência implícita à classe externa podem ser igualmente perigosas. A segunda solução é usar o contexto do aplicativo. Esse contexto permanecerá enquanto seu aplicativo estiver ativo e não depende do ciclo de vida das atividades. Se você planeja manter objetos de vida longa que precisam de um contexto, lembre-se do objeto do aplicativo. Você pode obtê-lo facilmente chamando Context.getApplicationContext () ou Activity.getApplication ().
Mas para o AlertDialog()
nem getApplicationContext()
ou getApplication()
é aceitável como um contexto, pois lança a exceção:
"Não foi possível adicionar a janela - o token nulo não é para um aplicativo"
por referências: 1 , 2 , 3 , etc.
Então, isso realmente deve ser considerado um "bug", uma vez que somos oficialmente aconselhados a usar Activity.getApplication()
e ainda assim não funciona como anunciado?
Jim
Respostas:
Em vez de
getApplicationContext()
, basta usarActivityName.this
.fonte
Listener
aulas são muitas vezes anonymous-interior, eu só tendem a fazerfinal Context ctx = this;
e eu estou longe;)Usar
this
não funcionou para mim, masMyActivityName.this
funcionou. Espero que isso ajude quem não conseguiuthis
trabalhar.fonte
this
de dentro de uma classe interna. Se você deseja fazer referência à instância de uma classe externa, deve especificar isso, como faz comOuterClass.this
. Apenas usarthis
sempre faz referência à instância da classe mais interna.Você pode continuar usando
getApplicationContext()
, mas antes de usar, adicione este sinalizador:dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT)
e o erro não será exibido.Adicione a seguinte permissão ao seu manifesto:
fonte
Você identificou corretamente o problema quando disse "... para o AlertDialog (), nem o getApplicationContext () nem o getApplication () são aceitáveis como um contexto, pois gera a exceção: 'Não é possível adicionar o token de janela nulo uma aplicação'"
Para criar um Diálogo, você precisa de um Contexto de Atividade ou de Contexto de Serviço , não de Contexto de Aplicativo (getApplicationContext () e getApplication () retornam um Contexto de Aplicativo).
Veja como você obtém o Contexto de Atividade :
(1) Em uma atividade ou serviço:
AlertDialog.Builder builder = new AlertDialog.Builder(this);
(2) Em um fragmento:
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
O vazamento de memória não é um problema intrínseco à referência "this", que é a referência de um objeto para si mesma (ou seja, referência à memória alocada real para armazenar os dados do objeto). Isso acontece com qualquer memória alocada para a qual o Garbage Collector (GC) não consegue liberar depois que a memória alocada ultrapassa sua vida útil.
Na maioria das vezes, quando uma variável sai do escopo, a memória é recuperada pelo GC. No entanto, vazamentos de memória podem ocorrer quando a referência a um objeto mantido por uma variável, digamos "x", persiste mesmo depois que o objeto ultrapassa sua vida útil. A memória alocada será, portanto, perdida enquanto "x" mantiver uma referência a ela, porque o GC não liberará a memória enquanto essa memória ainda estiver sendo referenciada. Às vezes, vazamentos de memória não são aparentes devido a uma cadeia de referências à memória alocada. Nesse caso, o GC não liberará a memória até que todas as referências a essa memória tenham sido removidas.
Para evitar vazamentos de memória, verifique seu código quanto a erros lógicos que fazem com que a memória alocada seja referenciada indefinidamente por "this" (ou outras referências). Lembre-se de verificar também as referências em cadeia. Aqui estão algumas ferramentas que você pode usar para ajudá-lo a analisar o uso da memória e encontrar esses vazamentos de memória traquinas:
Controle de missão JRockit
JProbe
YourKit
AD4J
fonte
Sua caixa de diálogo não deve ser um "objeto de longa duração que precise de um contexto". A documentação é confusa. Basicamente, se você fizer algo como:
(observe a estática )
Então, em uma atividade em algum lugar que você fez
Você provavelmente vazaria a atividade original durante uma rotação ou similar que destruiria a atividade. (A menos que você limpe o onDestroy, mas nesse caso você provavelmente não tornaria o objeto Dialog estático)
Para algumas estruturas de dados, faria sentido torná-las estáticas e baseadas no contexto do aplicativo, mas geralmente não para itens relacionados à interface do usuário, como diálogos. Então, algo como isto:
Está bom e não deve vazar a atividade, pois o mDialog seria liberado com a atividade, pois não é estático.
fonte
Eu tive que enviar meu contexto através de um construtor em um adaptador personalizado exibido em um fragmento e tive esse problema com getApplicationContext (). Eu o resolvi com:
this.getActivity().getWindow().getContext()
noonCreate
retorno de chamada dos fragmentos .fonte
em Atividade, basta usar:
no fragmento:
fonte
Em
Activity
no clique do botão que mostra uma caixa de diálogoTrabalhou para mim.
fonte
***** versão kotlin *****
Você deve passar em
this@YourActivity
vez deapplicationContext
oubaseContext
fonte
Pequeno hack: você pode evitar destruir a sua actividade por GC (você não deve fazê-lo, mas pode ajudar em algumas situações Não se esqueça de set.
contextForDialog
Paranull
quando já não é necessário):fonte
Se você estiver usando um fragmento e usando a mensagem AlertDialog / Toast, use getActivity () no parâmetro context.
como isso
fonte
Basta usar o seguinte:
PARA USUÁRIOS JAVA
Caso você esteja usando atividade ->
AlertDialog.Builder builder = new AlertDialog.Builder(this);
OU
AlertDialog.Builder builder = new AlertDialog.Builder(your_activity.this);
Caso você esteja usando fragmento ->
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
PARA USUÁRIOS KOTLIN
Caso você esteja usando atividade ->
val builder = AlertDialog.Builder(this)
OU
val builder = AlertDialog.Builder(this@your_activity.this)
Caso você esteja usando fragmento ->
val builder = AlertDialog.Builder(activity!!)
fonte
adicionando
e
"android.permission.SYSTEM_ALERT_WINDOW"/>
em manifestoTrabalha para mim agora. Depois de fechar e abrir o aplicativo, deu-me o erro naquele momento.
fonte
Eu estava usando
ProgressDialog
um fragmento e estava recebendo esse erro ao passargetActivity().getApplicationContext()
como o parâmetro construtor. Mudá-lo paragetActivity().getBaseContext()
também não funcionou.A solução que funcionou para mim foi passar
getActivity()
; ieprogressDialog = new ProgressDialog(getActivity());
fonte
Usar
MyDialog md = new MyDialog(MyActivity.this.getParent());
fonte
Se você estiver fora da atividade, precisará usar em sua função "NameOfMyActivity.this" como atividade de atividade, exemplo:
fonte
Se você estiver usando um fragmento e uma
AlertDialog / Toast
mensagem, usegetActivity()
no parâmetro contextTrabalhou para mim.
Felicidades!
fonte
Tente usar o contexto de uma atividade que estará sob o diálogo. Mas tenha cuidado ao usar a palavra-chave "this", pois ela não funcionará sempre.
Por exemplo, se você tiver TabActivity como host com duas guias, e cada guia for outra atividade, e se tentar criar um diálogo a partir de uma das guias (atividades) e se usar "this", receberá uma exceção. O diálogo de caso deve ser conectado à atividade do host que hospeda tudo e é visível. (você pode dizer o contexto da atividade pai mais visível)
Não encontrei essas informações em nenhum documento, apenas tentando. Esta é a minha solução sem antecedentes sólidos. Se alguém com melhor conhecimento, sinta-se à vontade para comentar.
fonte
Para futuros leitores, isso deve ajudar:
fonte
No meu caso, trabalho:
fonte
Ou outra possibilidade é criar o Diálogo da seguinte maneira:
fonte
Acho que também pode acontecer se você estiver tentando mostrar uma caixa de diálogo a partir de um thread que não seja o principal thread da interface do usuário.
Use
runOnUiThread()
nesse caso.fonte
Tente
getParent()
no argumento do contexto de contexto como novoAlertDialog.Builder(getParent());
Espero que funcione, funcionou para mim.fonte
Depois de dar uma olhada na API, você pode passar a caixa de diálogo sua atividade ou getActivity se estiver em um fragmento e limpá-la à força com dialog.dismiss () nos métodos de retorno para evitar vazamentos.
Embora não esteja explicitamente declarado em nenhum lugar que eu conheça, parece que você retornou a caixa de diálogo no OnClickHandlers apenas para fazer isso.
fonte
Se o seu Diálogo estiver criando no adaptador:
Passe a atividade ao construtor do adaptador:
Receba no adaptador:
Agora você pode usar no seu Builder
fonte
Aqui está como eu resolvi o mesmo erro para o meu aplicativo:
Adicionando a seguinte linha após criar a caixa de diálogo:
Você não precisará adquirir um contexto. Isso é particularmente útil se você estiver exibindo outra caixa de diálogo sobre a caixa de diálogo atual atual. Ou quando não é conveniente obter um contexto.
Espero que isso possa ajudá-lo no desenvolvimento de aplicativos.
David
fonte
fonte