Na programação Android comum, o Handler é frequentemente usado ao executar operações assíncronas e processar resultados retornados. Normalmente nosso código é implementado assim.
Copie o código do código da seguinte forma:
classe pública SampleActivity estende atividade {
manipulador final privado mLeakyHandler = new Handler() {
@Substituir
public void handleMessage(mensagem de mensagem) {
// ...
}
}
}
No entanto, na verdade, o código acima pode causar vazamentos de memória. Ao usar a ferramenta Android lint, você receberá esse aviso.
Copie o código do código da seguinte forma:
No Android, as classes Handler devem ser estáticas ou podem ocorrer vazamentos. As mensagens enfileiradas no MessageQueue do thread do aplicativo também retêm seu manipulador de destino. Se o Handler for uma classe interna, sua classe externa também será retida. declare o Handler como uma classe estática aninhada com um WeakReference para sua classe externa
Vendo isso, você ainda pode estar confuso. Onde no código pode causar um vazamento de memória e como isso pode causar um vazamento de memória? Então vamos analisar lentamente.
1. Quando um aplicativo Android é iniciado, uma instância do Looper é criada automaticamente para ser usada pelo thread principal do aplicativo. A principal tarefa do Looper é processar os objetos de mensagem na fila de mensagens, um por um. No Android, todos os eventos da estrutura Android (como chamadas de método de ciclo de vida de atividade e cliques em botões, etc.) são colocados em mensagens e, em seguida, adicionados à fila de mensagens para serem processadas pelo Looper, e o Looper é responsável por processá-los um por um. O ciclo de vida do Looper no thread principal é tão longo quanto o da aplicação atual.
2. Quando um Handler é inicializado no thread principal e enviamos uma mensagem direcionada a este Handler para a fila de mensagens processadas pelo Looper, a mensagem realmente enviada já contém uma referência a uma instância do Handler Somente desta forma o Looper está processando Somente quando este. mensagem é recebida pode Handler#handleMessage(Message) ser chamado para completar o processamento correto da mensagem.
3. Em Java, classes internas não estáticas e classes internas anônimas mantêm implicitamente referências às suas classes externas. Classes internas estáticas não contêm referências a classes externas. Para obter mais informações sobre isso, consulte Chat Java: modificador privado "inválido"
É verdade que o exemplo de código acima é um pouco difícil de detectar o vazamento de memória, então o exemplo a seguir é muito óbvio
Copie o código do código da seguinte forma:
classe pública SampleActivity estende atividade {
manipulador final privado mLeakyHandler = new Handler() {
@Substituir
public void handleMessage(mensagem de mensagem) {
// ...
}
}
@Substituir
protegido void onCreate (pacote salvoInstanceState) {
super.onCreate(savedInstanceState);
// Posta uma mensagem e atrasa sua execução por 10 minutos.
mLeakyHandler.postDelayed(new Runnable() {
@Substituir
public void run() { /* ... */ }
}, 1000*60*10);
// Volta para a atividade anterior.
terminar();
}
}
Analisando o código acima, quando executamos o método final da atividade, a mensagem atrasada existirá na fila de mensagens do thread principal por 10 minutos antes de ser processada, e esta mensagem contém uma referência ao Handler, e o Handler é uma instância anônima de a classe interna contém uma referência à SampleActivity externa, portanto, isso faz com que a SampleActivity não possa ser reciclada. Como resultado, muitos recursos mantidos pela SampleActivity não podem ser reciclados. Isso é o que geralmente chamamos de vazamento de memória.
Observe que o novo Runnable acima também é implementado por uma classe interna anônima. Ele também contém uma referência a SampleActivity e evita que SampleActivity seja reciclada.
Para resolver esse problema, a ideia não é usar classes internas não estáticas. Ao herdar o Handler, coloque-o em um arquivo de classe separado ou use uma classe interna estática. Como a classe interna estática não contém uma referência à classe externa, ela não causará vazamentos de memória na instância da classe externa. Quando você precisar chamar uma Activity externa em uma classe interna estática, podemos usar referências fracas para lidar com isso. Além disso, Runnable também precisa ser definido como um atributo de membro estático. Nota: Uma instância de classe interna anônima estática não contém uma referência à classe externa. O código que não causará vazamentos de memória após a modificação é o seguinte:
Copie o código do código da seguinte forma:
classe pública SampleActivity estende atividade {
/**
* Instâncias de classes internas estáticas não possuem um valor implícito
* referência à sua classe externa.
*/
classe estática privada MyHandler estende Handler {
private final WeakReference<SampleActivity> mActivity;
public MyHandler(atividade de atividade de amostra) {
mActivity = new WeakReference<SampleActivity>(atividade);
}
@Substituir
public void handleMessage(mensagem de mensagem) {
Atividade SampleActivity = mActivity.get();
if (atividade! = nulo) {
// ...
}
}
}
private final MyHandler mHandler = new MyHandler(este);
/**
* Instâncias de classes anônimas não possuem um valor implícito
* referência à sua classe externa quando são "estáticos".
*/
private static final Runnable sRunnable = new Runnable() {
@Substituir
public void run() { /* ... */ }
};
@Substituir
protegido void onCreate (pacote salvoInstanceState) {
super.onCreate(savedInstanceState);
// Posta uma mensagem e atrasa sua execução por 10 minutos.
mHandler.postDelayed(sRunnable, 1000 * 60 * 10);
// Volta para a atividade anterior.
terminar();
}
}
Na verdade, muitos vazamentos de memória no Android são causados pelo uso de classes internas não estáticas em Activity, conforme mencionado neste artigo, portanto, devemos prestar atenção especial ao usar classes internas não estáticas em sua instância. o objeto retido for maior que seu objeto de classe externa, isso poderá causar vazamentos de memória. Pessoalmente, costumo usar a classe estática do artigo e os métodos de referência fracos para resolver esse problema.