Тимертаск або Обробник


103

Скажімо, я хочу виконувати якусь дію кожні 10 секунд, і це не обов'язково оновлювати перегляд.

Питання: чи краще (я маю на увазі ефективніше та ефективніше) використовувати таймер із тимчасовим завданням, як тут:

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

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


2
Я читав багато публікацій про нерегулярну поведінку TimerTasks. Моя порада буде уникати їх і скористатися підходом обробника / postDelayed.
Концепція звуку

1
Я вважаю за краще метод Handler-postDelay - у вас більше контролю, і ви плануєте його зсередини
mihail

1
Ось чудове джерело для Таймера проти
Хендлера

TimerTask - це фонове завдання, тому не можна оновити інтерфейс користувача. Просто кажу…
Yousha Aleayoub

1
працював на мене .. дякую
jyotsna

Відповіді:


96

Handlerкраще, ніж TimerTask.

І Java, TimerTaskі Android Handlerдозволяють планувати затримки та повторювані завдання на фонових потоках. Однак в літературі в переважній більшості випадків рекомендує використовувати Handlerбільш 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);

Пов'язані


6
@Reek Ні, GC повинен подбати про це. Але вам потрібно подбати про розбіжність, розміщену для затримки виконання. У наведеному вище прикладі використовуваний виконується екземпляр внутрішнього класу, тому міститься неявна посилання на клас, що містить (що може бути активністю). Виконання залишатиметься у черзі повідомлення асоційованої петлі повідомлення обробника до наступного часу його виконання, який може бути після недійсного контексту та може витікати, що містить екземпляр класу. Ви можете очистити такі посилання, скориставшись mHandler.removeCallbacks(runnableCode)у відповідний час (наприклад, onStop()для діяльності).
бітбіт

7
Найкращий спосіб подання посилань будь-коли !!! (див. тут, тут, тут, тут, тут і тут).
iRavi iVooda

і що, якщо я хочу використовувати це всередині ViewModel? не проти ідеалу не мати там андроїд речей?
desgraci

@desgraci, я не використовував ViewModel, але з документації я бачу лише те, що в ньому написано, що ViewModel не повинен отримувати доступ до ієрархії перегляду або містити посилання на активність або фрагмент. Я взагалі не бачу нічого забороняти мати "речі Android".
Сурагч

На сьогоднішній день ці посилання на мене застаріли і недостатньо інформативні, щоб їх можна було врахувати. Ці 4 перелічені недоліки реальні лише в тому випадку, якщо ви погано програмуєте код. TimerTasks - це все ще дуже хороший вибір, якщо ви хочете періодично запускати щось у фоновому режимі і в кінцевому підсумку запускати щось на UIThread, якщо застосовується певна умова.
Девід

18

Є деякі недоліки використання таймера

Він створює лише одну нитку для виконання завдань, і якщо завдання запускається занадто довго, інші завдання страждають. Він не обробляє винятки, кинуті завданнями, а потік просто припиняється, що впливає на інші заплановані завдання, і вони ніколи не виконуються

Скопійовано з:

TimerTask vs Thread.sleep vs Handler postDelayed - найточніша функція виклику кожні N мілісекунд?


6
так що ж робити з одним ударом завдання? це здається, що, можливо, Таймер краще для цього, тому що у вас немає накладних очей черги повідомлень?
Майкл

2
Напевно, ми ніколи не дізнаємось
Denny

6

Котлінова версія прийнятої відповіді:

val handler = Handler()

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

handler.post(runnableCode)
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.