Estou recebendo um aviso no meu código que afirma:
Esta classe AsyncTask deve ser estática ou podem ocorrer vazamentos (android.os.AsyncTask anônimo)
O aviso completo é:
Essa classe AsyncTask deve ser estática ou podem ocorrer vazamentos (android.os.AsyncTask anônimo) Um campo estático vazará contextos. Classes internas não estáticas têm uma referência implícita à sua classe externa. Se essa classe externa for, por exemplo, um Fragmento ou Atividade, essa referência significa que o manipulador / carregador / tarefa de longa duração manterá uma referência à atividade que impede a coleta de lixo. Da mesma forma, referências diretas de campo a atividades e fragmentos dessas instâncias de execução mais longa podem causar vazamentos. As classes ViewModel nunca devem apontar para Views ou Contextos que não sejam de aplicativos.
Este é o meu código:
new AsyncTask<Void,Void,Void>(){
@Override
protected Void doInBackground(Void... params) {
runOnUiThread(new Runnable() {
@Override
public void run() {
mAdapter.notifyDataSetChanged();
}
});
return null;
}
}.execute();
Como faço para corrigir isso?
fonte
myActivity.getApplication()
no construtor privado do Singleton, para inicializar as classes RoomDB e outras classes). Meus ViewModels obtêm a instância Singleton como uma referência particular para executar algumas operações no banco de dados. Portanto, os ViewModels importam o pacote Singleton e tambémandroid.app.Application
um delesandroid.app.Activity
. Como "o Singleton" não precisa importar esses ViewModels para funcionar, mesmo assim, podem ocorrer vazamentos de memória?Respostas:
Classes internas não estáticas mantém uma referência à classe que contém. Quando você declara
AsyncTask
como uma classe interna, ela pode durar mais que aActivity
classe que a contém . Isso ocorre devido à referência implícita à classe que o contém. Isso impedirá que a atividade seja coletada como lixo, daí o vazamento de memória.Para resolver seu problema, use a classe aninhada estática em vez da classe anônima, local e interna ou use a classe de nível superior.
fonte
Como usar uma classe AsyncTask interna estática
Para evitar vazamentos, você pode tornar a classe interna estática. O problema disso, porém, é que você não tem mais acesso às visualizações da interface do usuário da atividade ou às variáveis de membro. Você pode passar uma referência ao,
Context
mas então corre o mesmo risco de um vazamento de memória. (O Android não pode coletar a Atividade após o fechamento, se a classe AsyncTask tiver uma forte referência a ela.) A solução é fazer uma referência fraca à Atividade (ou o queContext
você precisar).Notas
AsyncTask
tutoriais por aí ainda não lidam com isso (veja aqui , aqui , aqui e aqui ).AsyncTask
fosse uma classe de nível superior. Uma classe interna estática é basicamente a mesma que uma classe de nível superior em Java.Se você não precisa da Atividade em si, mas ainda deseja que o Contexto (por exemplo, exiba a
Toast
), pode passar uma referência ao contexto do aplicativo. Nesse caso, oAsyncTask
construtor ficaria assim:Kotlin
No Kotlin , não inclua a
inner
palavra - chave da classe interna. Isso o torna estático por padrão.fonte
onPostExecute
método novamente no código acima. Você pode ver que eu atualizei a interface do usuárioTextView
lá. Basta usaractivity.findViewById
para obter uma referência a qualquer elemento da interface do usuário que você precise atualizar.activity.isFinishing()
cheque e possivelmente o substituiria por umfragment.isRemoving()
cheque. Eu não trabalhei muito com fragmentos recentemente, no entanto.AsyncTask
construtor você passará uma referência à sua classe externa. EdoInBackground()
você pode obter uma referência à classe externa comMyOuterClass ref = classReference.get()
. Verifique se hánull
. (2)onPostExecute()
Você está atualizando a interface do usuário apenas com os resultados da tarefa em segundo plano. É como qualquer outra vez que você atualiza a interface do usuário. A verificaçãoactivity.isFinishing()
é apenas para garantir que a atividade ainda não tenha começado a concluir; nesse caso, seria inútil atualizar a interface do usuário.Essa
AsyncTask
classe deve ser estática ou podem ocorrer vazamentos porqueActivity
é destruído,AsyncTask
(ambosstatic
ounon-static
) ainda está em execuçãonon-static
(AsyncTask
), ela terá referência à classe externa (Activity
).Garbage Collected
será liberado. Se um objeto não estiver sendo usado eGarbage Collected
não puder liberá-lo => vazar memória=> Se
AsyncTask
fornon-static
,Activity
não irá liberar evento se for destruído => vazamentoSolução para atualização da interface do usuário após fazer o AsyncTask como classe estática sem vazamento
1) Use
WeakReference
como resposta do @Suragch2) Envie e remova a
Activity
referência a (de)AsyncTask
fonte
onDestroy()
não é garantido que seja chamado sempre