388 Stimmen

Wie kann man einen Runnable Thread in Android in bestimmten Intervallen ausführen?

Ich habe eine Anwendung entwickelt, die einen Text in bestimmten Abständen auf dem Bildschirm des Android-Emulators anzeigt. Ich verwende die Handler Klasse. Hier ist ein Ausschnitt aus meinem Code:

handler = new Handler();
Runnable r = new Runnable() {
    public void run() {
        tv.append("Hello World");               
    }
};
handler.postDelayed(r, 1000);

Wenn ich diese Anwendung ausführe, wird der Text nur einmal angezeigt. Warum?

131 Stimmen

Ich kann mich nie daran erinnern, wie man einen Runnable macht, also besuche ich immer Ihren Beitrag darüber, wie man es macht :))

1 Stimmen

Lambdas sind jetzt der Weg zu gehen die meiste Zeit ;)

576voto

alex2k8 Punkte 41000

Die einfache Lösung für Ihr Beispiel lautet:

handler = new Handler();

final Runnable r = new Runnable() {
    public void run() {
        tv.append("Hello World");
        handler.postDelayed(this, 1000);
    }
};

handler.postDelayed(r, 1000);

Oder wir können zum Beispiel ein normales Gewinde verwenden (mit Original-Läufer):

Thread thread = new Thread() {
    @Override
    public void run() {
        try {
            while(true) {
                sleep(1000);
                handler.post(this);
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
};

thread.start();

Sie können Ihr runnable-Objekt einfach als einen Befehl betrachten, der zur Ausführung an die Nachrichtenwarteschlange gesendet werden kann, und handler als ein Hilfsobjekt, das zum Senden dieses Befehls verwendet wird.

Weitere Einzelheiten finden Sie hier http://developer.Android.com/reference/Android/os/Handler.html

0 Stimmen

Alex, ich habe einen kleinen Zweifel, jetzt läuft der Thread perfekt und zeigt den Text kontinuierlich an, wenn ich das stoppen möchte, was muss ich tun? bitte helfen Sie mir.

11 Stimmen

Sie können die boolesche Variable _stop definieren und sie auf 'true' setzen, wenn Sie anhalten wollen. Und ändern Sie 'while(true)' in 'while(!_stop)', oder wenn das erste Beispiel verwendet wird, ändern Sie einfach in 'if(!_stop) handler.postDelayed(this, 1000)'.

1 Stimmen

Wenn Sie sicher sein wollen, dass der Handler an den Hauptthread angehängt wird, sollten Sie ihn wie folgt initialisieren: handler = new Handler(Looper.getMainLooper());

55voto

user2212515 Punkte 1180
new Handler().postDelayed(new Runnable() {
    public void run() {
        // do something...              
    }
}, 100);

2 Stimmen

Wenn Sie sicher sein wollen, dass der Handler an den Hauptthread angehängt wird, sollten Sie ihn wie folgt initialisieren: new Handler(Looper.getMainLooper());

1 Stimmen

Ist diese Lösung nicht gleichbedeutend mit dem ursprünglichen Beitrag? Sie würde die Runnable nur einmal nach 100 Millisekunden ausführen.

40voto

NguyenDat Punkte 4109

Ich denke, dass die erste Lösung von Alex2k8 verbessert werden kann, um jede Sekunde korrekt zu aktualisieren

1. ursprünglicher Code:

public void run() {
    tv.append("Hello World");
    handler.postDelayed(this, 1000);
}

2.Analyse

  • Bei den oben genannten Kosten wird davon ausgegangen, dass tv.append("Hello Word") Kosten T Millisekunden, nach der Anzeige 500 mal verzögerte Zeit ist 500*T Millisekunden
  • Bei längerem Betrieb wird die Verzögerung zunehmen

3. Lösung

Um das zu vermeiden, ändern Sie einfach die Reihenfolge von postDelayed(), um Verzögerungen zu vermeiden:

public void run() {
    handler.postDelayed(this, 1000);
    tv.append("Hello World");
}

6 Stimmen

-Sie gehen davon aus, dass die Aufgabe, die Sie in run() ausführen, bei jedem Durchlauf einen konstanten Betrag kostet. Wenn es sich um eine Operation mit dynamischen Daten handeln würde (was in der Regel der Fall ist), würden Sie am Ende mehr als ein run() auf einmal ausführen. Aus diesem Grund wird postDelayed normalerweise am Ende platziert.

1 Stimmen

@Jay Leider liegen Sie falsch. Ein Handler ist mit einem einzelnen Thread (und einem Looper, der die Ausführungsmethode dieses Threads ist) + einer MessageQueue verbunden. Jedes Mal, wenn Sie eine Nachricht senden, stellen Sie sie in die Warteschlange, und wenn der Looper das nächste Mal die Warteschlange überprüft, führt er die Ausführungsmethode des von Ihnen gesendeten Runnable aus. Da dies alles in nur einem Thread geschieht, kann nicht mehr als einer gleichzeitig ausgeführt werden. Indem man die postDelayed-Methode zuerst ausführt, kommt man näher an 1000ms pro Ausführung heran, da intern die aktuelle Zeit + 1000 als Ausführungszeit verwendet wird. Wenn Sie Code vor dem post setzen Sie zusätzliche Verzögerung hinzufügen.

1 Stimmen

@zapl danke für den Tipp mit dem Handler, ich bin davon ausgegangen, dass er mehrere Runnables und damit mehrere Threads ausführen würde. Intern jedoch wird eine Bedingung wie if ((currenttime - lastruntime)>1000) gut funktionieren, wenn Laufdauern kleiner oder gleich 1000ms sind, aber wenn dies überschritten wird, wird der Timer sicherlich in nicht linearen Intervallen auftreten, die vollständig von der Ausführungszeit der Run-Methode abhängen (daher mein Punkt auf unvorhersehbaren Rechenaufwand)

31voto

Zar E Ahmer Punkte 32557

Für Wiederholungsaufgaben können Sie verwenden

new Timer().scheduleAtFixedRate(task, runAfterADelayForFirstTime, repeaingTimeInterval);

nennen Sie es wie

new Timer().scheduleAtFixedRate(new TimerTask() {
            @Override
            public void run() {

            }
        },500,1000);

Der obige Code wird das erste Mal ausgeführt, nachdem halbe Sekunde(500) und wiederholt sich nach jedem Sekunde(1000)

Donde

Aufgabe ist die auszuführende Methode

nach die Zeit bis zur ersten Ausführung

( Intervall die Zeit für die Wiederholung der Ausführung)

Zweitens

Und Sie können auch Folgendes verwenden CountDownTimer wenn Sie eine Aufgabe mehrmals ausführen möchten.

    new CountDownTimer(40000, 1000) { //40000 milli seconds is total time, 1000 milli seconds is time interval

     public void onTick(long millisUntilFinished) {
      }
      public void onFinish() {
     }
    }.start();

//Above codes run 40 times after each second

Und Sie können es auch mit runnable tun. erstellen Sie eine runnable Methode wie

Runnable runnable = new Runnable()
    {
        @Override
        public void run()
        {

        }
    };

Und nennen Sie es auf diese beiden Arten

new Handler().postDelayed(runnable, 500 );//where 500 is delayMillis  // to work on mainThread

OR

new Thread(runnable).start();//to work in Background

0 Stimmen

Wie kann ich bei Option Nr. 3 pausieren/fortfahren und auch dauerhaft anhalten?

0 Stimmen

Eine Instanz von Handler erstellen wie Handler handler = new Handler() und sie entfernen wie handler.removeCallbacksAndMessages(null);

25voto

iTech Punkte 17714

Ich glaube, für diesen typischen Fall, d.h. um etwas mit einem festen Intervall laufen zu lassen, Timer besser geeignet ist. Hier ist ein einfaches Beispiel:

myTimer = new Timer();
myTimer.schedule(new TimerTask() {          
@Override
public void run() {
    // If you want to modify a view in your Activity
    MyActivity.this.runOnUiThread(new Runnable()
        public void run(){
            tv.append("Hello World");
        });
    }
}, 1000, 1000); // initial delay 1 second, interval 1 second

Verwendung von Timer hat nur wenige Vorteile:

  • Die Anfangsverzögerung und das Intervall können einfach in der schedule Funktionsargumente
  • Der Timer kann durch einfachen Aufruf von myTimer.cancel()
  • Wenn Sie nur einen Thread laufen lassen wollen, denken Sie daran, die myTimer.cancel() avant Planung eines neuen Timers (wenn myTimer nicht null ist)

7 Stimmen

Ich glaube nicht, dass ein Timer besser geeignet ist, da er den Lebenszyklus von Android nicht berücksichtigt. Wenn Sie pausieren und fortsetzen, gibt es keine Garantie, dass der Timer korrekt ausgeführt wird. Ich würde argumentieren, dass ein runnable die bessere Wahl ist.

1 Stimmen

Bedeutet das, dass, wenn eine Anwendung in den Hintergrund gestellt wird, ein Handler angehalten wird? und wenn er den Fokus wiedererlangt, wird er (mehr oder weniger) fortgesetzt, als ob nichts geschehen wäre?

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X