Timertask ou Handler

103

Digamos que eu queira realizar alguma ação a cada 10 segundos e não necessariamente precise atualizar a visualização.

A questão é: é melhor (quero dizer mais eficiente e eficaz) usar o temporizador com o timertask como aqui:

final Handler handler = new Handler();

TimerTask timertask = new TimerTask() {
    @Override
    public void run() {
        handler.post(new Runnable() {
            public void run() {
               <some task>
            }
        });
    }
};
timer = new Timer();
timer.schedule(timertask, 0, 15000);
}

ou apenas um manipulador com pós-atraso

final Handler handler = new Handler(); 
final Runnable r = new Runnable()
{
    public void run() 
    {
        <some task>
    }
};
handler.postDelayed(r, 15000);

Eu também ficaria muito grato se você pudesse explicar quando usar qual abordagem e por que um deles é mais eficiente do que outro (se realmente for).

keysersoze
fonte
2
Eu li muitos posts sobre comportamento irregular de TimerTasks. Meu conselho seria ficar longe deles e usar a abordagem de manipulador / pós-atraso.
Sound Conception
1
Eu prefiro o método Handler-postDelay - você tem mais controle e o programa de dentro
mihail
1
Aqui está uma ótima fonte para Timer vs. Handler
CodyF
TimerTask é uma tarefa em segundo plano, portanto, você não pode atualizar a IU. Apenas dizendo ...
Yousha Aleayoub
1
funcionou para mim
jyotsna

Respostas:

96

Handleré melhor do que TimerTask.

O Java TimerTaske o Android Handlerpermitem que você agende tarefas atrasadas e repetidas em threads de fundo. No entanto, a literatura recomenda esmagadoramente o uso de Handlerover TimerTaskno Android (veja aqui , aqui , aqui , aqui , aqui e aqui ).

Alguns dos problemas relatados com TimerTask incluem:

  • Não é possível atualizar o UI thread
  • Perda de memória
  • Não confiável (nem sempre funciona)
  • Tarefas de longa duração podem interferir no próximo evento agendado

Exemplo

A melhor fonte para todos os tipos de exemplos Android que vi está no Codepath . Aqui está um Handlerexemplo de uma tarefa repetitiva.

// Create the Handler object (on the main thread by default)
Handler handler = new Handler();
// Define the code block to be executed
private Runnable runnableCode = new Runnable() {
    @Override
    public void run() {
      // Do something here on the main thread
      Log.d("Handlers", "Called on main thread");
      // Repeat this the same runnable code block again another 2 seconds
      handler.postDelayed(runnableCode, 2000);
    }
};
// Start the initial runnable task by posting through the handler
handler.post(runnableCode);

Relacionados

Suragch
fonte
6
@Reek Não, GC deve cuidar disso. Mas você precisa cuidar do executável postado para execução atrasada. No exemplo acima, o executável usado é uma instância de classe interna, portanto, mantém uma referência implícita à classe contida (que pode ser uma atividade). O executável permanecerá na fila de mensagens do looper associado ao manipulador até seu próximo tempo de execução, que pode ser após o contexto ser inválido e pode vazar a instância da classe que o contém. Você pode limpar essas referências usando mHandler.removeCallbacks(runnableCode)no momento apropriado (por exemplo, onStop()para uma atividade).
bitbybit
7
Melhor forma de apresentar referências de sempre !!! (veja aqui, aqui, aqui, aqui, aqui e aqui).
iRavi iVooda
e se eu quiser usar isso dentro de um ViewModel? não é contra o ideal de não ter coisas andróides lá?
desgraci
@desgraci, não usei um ViewModel, mas pela documentação, vejo apenas que diz que o ViewModel não deve acessar a hierarquia de visualização ou conter uma referência à Activity ou Fragment. Não vejo nada que proíba ter "coisas Android" em geral.
Suragch
A partir de hoje, essas referências estão desatualizadas e não são informativas o suficiente para serem levadas em consideração. Essas 4 desvantagens listadas são reais apenas se você programar seu código incorretamente. TimerTasks ainda são uma escolha muito boa se você deseja executar algo em segundo plano periodicamente e, eventualmente, executar algo no UIThread se alguma condição se aplicar.
David,
18

Existem algumas desvantagens de usar o temporizador

Ele cria apenas um único thread para executar as tarefas e se uma tarefa demorar muito para ser executada, outras tarefas sofrem. Ele não lida com exceções lançadas por tarefas e o thread apenas termina, o que afeta outras tarefas agendadas e elas nunca são executadas

Copiado de:

TimerTask vs Thread.sleep vs Handler postDelayed - mais preciso para chamar a função a cada N milissegundos?

Praveena
fonte
6
então, que tal uma tarefa única? parece que talvez o Timer seja melhor para isso porque você não tem a sobrecarga da fila de mensagens?
Michael
2
Acho que nunca saberemos
Denny
6

Versão Kotlin da resposta aceita:

val handler = Handler()

val runnableCode = object : Runnable {
    override fun run() {
       Log.d("Handlers", "Called on main thread")
       handler.postDelayed(this, 2000)
    }
}

handler.post(runnableCode)
sma6871
fonte