Timertask или обработчик

104

Допустим, я хочу выполнять какое-то действие каждые 10 секунд, и не обязательно обновлять представление.

Вопрос в том, что лучше (я имею в виду более эффективное и действенное) использовать таймер с timertask, как здесь:

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

или просто обработчик с задержкой

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

Также я был бы признателен, если бы вы могли объяснить, когда использовать какой подход и почему один из них более эффективен, чем другой (если это действительно так).

Keysersoze
источник
2
Я читал много сообщений о неправильном поведении TimerTasks. Я бы посоветовал держаться от них подальше и использовать подход handler / postDelayed.
Sound Conception
1
Я бы предпочел метод Handler-postDelay - у вас больше контроля, и вы планируете его изнутри
Михаил
1
Вот отличный источник для Timer vs. Handler
CodyF
TimerTask - это фоновая задача, поэтому вы не можете обновлять пользовательский интерфейс. Просто говорю ...
Юша Алеайуб
1
у меня сработало .. спасибо
jyotsna

Ответы:

97

Handlerлучше чем TimerTask.

И Java, TimerTaskи Android Handlerпозволяют планировать отложенные и повторяющиеся задачи в фоновых потоках. Однако в литературе настоятельно рекомендуется использовать Handlerover TimerTaskв Android (см. Здесь , здесь , здесь , здесь , здесь и здесь ).

Некоторые из сообщенных проблем с TimerTask включают:

  • Не удается обновить поток пользовательского интерфейса
  • Утечки памяти
  • Ненадежный (не всегда работает)
  • Долгосрочные задачи могут помешать следующему запланированному событию

пример

Лучший источник всех видов Android-примеров, которые я видел, - это Codepath . Вот Handlerпример повторяющейся задачи.

// 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);

Связанный

Suragch
источник
6
@Reek Нет, GC должен об этом позаботиться. Но вам нужно позаботиться о runnable, опубликованном для отложенного выполнения. В приведенном выше примере используемый runnable является экземпляром внутреннего класса, поэтому содержит неявную ссылку на содержащий класс (который может быть действием). Runnable будет оставаться в очереди сообщений связанного цикла обработчика до следующего времени выполнения, которое может наступить после того, как контекст станет недействительным и может привести к утечке содержащего его экземпляра класса. Вы можете удалить такие ссылки, используя mHandler.removeCallbacks(runnableCode)в подходящее время (например, onStop()для занятия).
bitbybit
7
Лучший способ представить ссылки !!! (см. здесь, здесь, здесь, здесь, здесь и здесь).
iRavi iVooda
а что, если я захочу использовать это внутри ViewModel? не против идеала не иметь там андроид?
desgraci
@desgraci, я не использовал ViewModel, но из документации я вижу только, что в нем говорится, что ViewModel не должен обращаться к иерархии представлений или содержать ссылку на Activity или Fragment. Я не вижу ничего запрещающего иметь "Android-вещи" вообще.
Suragch
На сегодняшний день эти ссылки для меня устарели и недостаточно информативны, чтобы их принимать во внимание. Эти 4 перечисленных недостатка реальны только в том случае, если вы плохо программируете свой код. TimerTasks по-прежнему очень хороший выбор, если вы хотите периодически запускать что-то в фоновом режиме и, в конечном итоге, запускать что-то в UIThread, если применяется какое-либо условие.
Дэвид
18

Есть некоторые недостатки использования таймера

Он создает только один поток для выполнения задач, и если задача занимает слишком много времени для выполнения, страдают другие задачи. Он не обрабатывает исключения, создаваемые задачами, и поток просто завершается, что влияет на другие запланированные задачи, и они никогда не запускаются

Скопировано с:

TimerTask vs Thread.sleep vs Handler postDelayed - наиболее точно вызывать функцию каждые N миллисекунд?

Правина
источник
6
так что насчет одноразовой задачи? похоже, что для этого лучше использовать Timer, потому что у вас нет накладных расходов на очередь сообщений?
Майкл
2
Думаю, мы никогда не узнаем
Денни
7

Котлинская версия принятого ответа:

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
источник