Timertask oder Handler

103

Angenommen, ich möchte alle 10 Sekunden eine Aktion ausführen und muss die Ansicht nicht unbedingt aktualisieren.

Die Frage ist: Ist es besser (ich meine effizienter und effektiver), Timer mit Zeitaufgabe wie hier zu verwenden:

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

oder nur ein Handler mit Nachverzögerung

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

Ich wäre auch dankbar, wenn Sie erklären könnten, wann welcher Ansatz zu verwenden ist und warum einer von ihnen effizienter ist als der andere (wenn dies tatsächlich der Fall ist).

Keysersoze
quelle
2
Ich habe viele Beiträge über unregelmäßiges Verhalten von TimerTasks gelesen. Mein Rat wäre, sich von ihnen fernzuhalten und den Handler / PostDelayed-Ansatz zu verwenden.
Sound Conception
1
Ich würde die Handler-postDelay-Methode bevorzugen - Sie haben mehr Kontrolle und planen sie von innen
mihail
1
Hier ist eine großartige Quelle für Timer vs. Handler
CodyF
TimerTask ist eine Hintergrundaufgabe, daher können Sie die Benutzeroberfläche nicht aktualisieren.
Ich sage
1
arbeitete für mich
danke

Antworten:

95

Handlerist besser als TimerTask.

Mit Java TimerTaskund Android Handlerkönnen Sie verzögerte und wiederholte Aufgaben in Hintergrund-Threads planen. In der Literatur wird jedoch überwiegend die Verwendung von HandlerOver TimerTaskin Android empfohlen (siehe hier , hier , hier , hier , hier und hier ).

Einige der gemeldeten Probleme mit TimerTask sind:

  • Der UI-Thread kann nicht aktualisiert werden
  • Speicherlecks
  • Unzuverlässig (funktioniert nicht immer)
  • Lang laufende Aufgaben können das nächste geplante Ereignis stören

Beispiel

Die beste Quelle für alle Arten von Android-Beispielen, die ich gesehen habe, ist Codepath . Hier ist ein HandlerBeispiel für eine sich wiederholende Aufgabe.

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

verbunden

Suragch
quelle
6
@Reek Nein, GC sollte sich darum kümmern. Sie müssen sich jedoch um die Ausführung kümmern, die für eine verzögerte Ausführung veröffentlicht wurde. Im obigen Beispiel ist die verwendete ausführbare Datei eine Instanz der inneren Klasse und enthält daher einen impliziten Verweis auf die enthaltende Klasse (die möglicherweise eine Aktivität ist). Die ausführbare Datei bleibt bis zur nächsten Ausführungszeit in der Nachrichtenwarteschlange des zugeordneten Loopers des Handlers, die möglicherweise nach dem ungültigen Kontext liegt und die enthaltende Klasseninstanz verliert. Sie können solche Referenzen löschen, indem Sie sie mHandler.removeCallbacks(runnableCode)zum richtigen Zeitpunkt verwenden (z. B. onStop()für eine Aktivität).
Bitbybit
7
Beste Art, Referenzen zu präsentieren !!! (siehe hier, hier, hier, hier, hier und hier).
iRavi iVooda
und was ist, wenn ich das in einem ViewModel verwenden möchte? ist nicht gegen das Ideal, keine Android-Sachen dort zu haben?
Desgraci
@desgraci, ich habe kein ViewModel verwendet, aber aus der Dokumentation geht nur hervor, dass das ViewModel nicht auf die Ansichtshierarchie zugreifen oder einen Verweis auf die Aktivität oder das Fragment enthalten sollte. Ich sehe nichts, was es verbietet, "Android-Dinge" im Allgemeinen zu haben.
Suragch
Bis heute sind diese Verweise für mich veraltet und nicht informativ genug, um berücksichtigt zu werden. Diese 4 aufgeführten Nachteile sind nur dann real, wenn Sie Ihren Code schlecht programmieren. TimerTasks sind immer noch eine sehr gute Wahl, wenn Sie regelmäßig etwas im Hintergrund ausführen und schließlich etwas auf dem UIThread ausführen möchten, wenn eine Bedingung erfüllt ist.
David
18

Die Verwendung des Timers hat einige Nachteile

Es wird nur ein einziger Thread zum Ausführen der Aufgaben erstellt. Wenn die Ausführung einer Aufgabe zu lange dauert, leiden andere Aufgaben. Ausnahmen, die von Aufgaben ausgelöst werden, werden nicht behandelt, und der Thread wird nur beendet, was sich auf andere geplante Aufgaben auswirkt und niemals ausgeführt wird

Kopiert von:

TimerTask vs Thread.sleep vs Handler postDelayed - am genauesten, um die Funktion alle N Millisekunden aufzurufen?

Praveena
quelle
6
Was ist also mit einer One-Shot-Aufgabe? Es klingt so, als ob Timer dafür besser ist, weil Sie nicht den Overhead der Nachrichtenwarteschlange haben.
Michael
2
Ich denke, wir werden es nie erfahren
Denny
5

Kotlin-Version der akzeptierten Antwort:

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
quelle