wake-up-neo.com

Java TimerTask ununterbrochen anhalten/stoppen und starten/fortsetzen?

Ich habe eine einfache Frage zu Java TimerTask. Wie kann ich zwei TimerTask-Tasks basierend auf einer bestimmten Bedingung anhalten/fortsetzen? Zum Beispiel habe ich zwei Timer, die untereinander laufen. Wenn eine bestimmte Bedingung innerhalb der Aufgabe des ersten Zeitgebers erfüllt wurde, stoppt der erste Zeitgeber und startet den zweiten Zeitgeber, und dasselbe geschieht, wenn eine bestimmte Bedingung innerhalb der Aufgabe des zweiten Zeitgebers erfüllt wurde. Die folgende Klasse zeigt genau was ich meine:

public class TimerTest {
    Timer timer1;
    Timer timer2;
    volatile boolean a = false;

    public TimerTest() {
        timer1 = new Timer();
        timer2 = new Timer();     
    }

    public void runStart() {
        timer1.scheduleAtFixedRate(new Task1(), 0, 1000);
    }

    class Task1 extends TimerTask {
        public void run() {
            System.out.println("Checking a");
            a = SomeClass.getSomeStaticValue();

            if (a) {
                // Pause/stop timer1, start/resume timer2 for 5 seconds
                timer2.schedule(new Task2(), 5000);
            }
        }
    }

    class Task2 extends TimerTask{
        public void run() {
            System.out.println("Checking a");
            a = SomeClass.getSomeStaticValue();

            if (!a) {
                // Pause/stop timer2, back to timer1
                timer1.scheduleAtFixedRate(new Task1(), 0, 1000);
            }

            // Do something...
        }
    }

    public static void main(String args[]) {
        TimerTest tt = new TimerTest();
        tt.runStart();      
    }
}

Meine Frage ist also: Wie halte ich timer1 an, während timer2 ausgeführt wird, und umgekehrt, während timer2 ausgeführt wird? Leistung und Timing sind mein Hauptanliegen, da dies in einem anderen laufenden Thread implementiert werden muss. Übrigens versuche ich, diese gleichzeitigen Timer auf Android zu implementieren. 

Danke für Ihre Hilfe!

18
Faiz

Von TimerTask.cancel() :

Beachten Sie, dass Sie diese Methode von .__ aufrufen. innerhalb der Laufmethode eines sich wiederholenden Zeitgeberaufgabe garantiert absolut, dass Die Timer-Task wird nicht erneut ausgeführt.

Einmal abgesagt, läuft es nicht mehr. Sie sollten stattdessen die modernere ScheduledExecutorService (von Java 5+) verwenden.

Edit: Das grundlegende Konstrukt ist:

ScheduledExecutorService exec = Executors.newSingleThreadScheduledExecutor();
exec.scheduleAtFixedRate(runnable, 0, 1000, TimeUnit.MILLISECONDS);

aber wenn man sich die Sache anschaut, gibt es keine Möglichkeit, diese Aufgabe abzubrechen, wenn sie einmal gestartet wurde, ohne den Dienst herunterzufahren, was etwas seltsam ist.

TimerTask ist in diesem Fall möglicherweise einfacher, aber Sie müssen eine neue Instanz erstellen, wenn Sie eine starten. Es kann nicht wiederverwendet werden.

Alternativ können Sie jede Aufgabe als separaten Übergangsdienst kapseln:

final ScheduledExecutorService exec = Executors.newSingleThreadScheduledExecutor();
Runnable task1 = new Runnable() {
  public void run() {
    a++;
    if (a == 3) {
      exec.shutdown();
      exec = Executors.newSingleThreadScheduledExecutor();
      exec.scheduleAtFixedRate(task2, 0, 1000, TimeUnit.MILLISECONDS)
    }
  }
};
exec.scheduleAtFixedRate(task1, 0, 1000, TimeUnit.MILLISECONDS);
25
cletus

die einfachste Lösung, die ich gefunden habe: Fügen Sie einfach einen booleschen Code in den Laufcode der Timer-Task ein:

timer.schedule( new TimerTask() {
    public void run() {
       if(!paused){
           //do your thing
       }
    }
 }, 0, 1000 );
15
Song Keang

Wenn Sie bereits einen Timer abgebrochen haben, können Sie ihn nicht erneut starten, sondern müssen einen neuen erstellen. 

Sehen Sie diese Antwort , sie enthält ein Video und den Quellcode, wie ich etwas Ähnliches gemacht habe.

Grundsätzlich gibt es zwei Methoden: pause und resume

In der Pause:

public void pause() {
    this.timer.cancel();
}

Zusammenfassend:

public void resume() {
    this.timer = new Timer();
    this.timer.schedule( aTask, 0, 1000 );
}

Das macht die Wahrnehmung von Pause/Fortsetzen.

Wenn Ihre Timer je nach Status der Anwendung unterschiedliche Aktionen ausführen, können Sie das StatePattern verwenden.

Faust definieren einen abstrakten Zustand:

abstract class TaskState  {
    public void run();
    public TaskState next();
}

Und geben Sie so viele Zustände an, wie Sie möchten. Der Schlüssel ist, dass ein Zustand Sie zu einem anderen führt. 

class InitialState extends TaskState {
    public void run() {
        System.out.println( "starting...");
    }
    public TaskState next() {
         return new FinalState();
    }
 }
 class FinalState extends TaskState  {
     public void run() {
         System.out.println("Finishing...");
     }
     public TaskState next(){
         return new InitialState();
    }
 }

Und dann ändern Sie den Status in Ihrem Timer.

Timer timer = new Timer();
TaskState state = new InitialState();

timer.schedule( new TimerTask() {
     public void run() {
          this.state.run();
          if( shouldChangeState() ) {
              this.state = this.state.next();
           }
     }
 }, 0, 1000 );

Wenn Sie dasselbe aber zu unterschiedlichen Raten durchführen möchten, sollten Sie das TimingFramework verwenden. Es ist etwas komplexer, aber lassen Sie uns coole Animationen machen, indem Sie das Malen bestimmter Komponenten mit unterschiedlichen Raten durchführen lassen (anstatt linear zu sein). 

6
OscarRyz

Überprüfen Sie Ihren Quellcode. Hier sind die Änderungen (die meine vorherige Antwort ziemlich gut bestätigen)

In Aufgabe1:

// Stop timer1 and start timer2
timer1.cancel();
timer2 = new Timer(); // <-- just insert this line
timer2.scheduleAtFixedRate(new Task2(), 0, 1000);

und in task2:

// Stop timer2 and start timer1
timer2.cancel();
timer1 = new Timer(); // <-- just insert this other
timer1.scheduleAtFixedRate(new Task1(), 0, 1000);

Es läuft auf meiner Maschine:

Es klappt! http://img687.imageshack.us/img687/9954/capturadepantalla201001m.png

4
OscarRyz

Meiner Meinung nach ist dies etwas falsch. Wenn Ihr Code Zeitgarantien benötigt, können Sie den Timer sowieso nicht verwenden und möchten dies auch nicht. "Diese Klasse bietet keine Echtzeitgarantien: Sie plant Aufgaben mit der Object.wait (long) -Methode."

Die Antwort, IMHO, ist, dass Sie Ihre Timer nicht anhalten und erneut starten möchten. Sie möchten lediglich verhindern, dass ihre Laufmethoden ihre Geschäfte machen. Und das ist einfach: Sie packen sie einfach in eine if-Anweisung ein. Der Schalter ist an, sie laufen, der Schalter ist aus, sie vermissen diesen Zyklus.

Edit: Die Frage hat sich wesentlich von dem verändert, was sie ursprünglich war, aber ich lasse diese Antwort, falls sie jemandem hilft. Mein Punkt ist: Wenn es Ihnen egal ist, wann Ihr Ereignis in der N-Millisekunden-Spanne ausgelöst wird (nur, dass es nicht alle N Millisekunden eintritt), können Sie einfach Bedingungsparameter für die Laufmethoden verwenden. Dies ist in der Tat ein sehr häufiger Fall, insbesondere wenn N weniger als 1 Sekunde beträgt.

4
Dan Rosenstark

Android kann eine bereits einmal geplante TimerTask nicht wiederverwenden. Es ist daher notwendig, sowohl den Timer als auch die TimerTask erneut zu bestätigen, zum Beispiel in einem Fragment:

private Timer timer;
private TimerTask timerTask;

public void onResume ()
{
    super.onResume();

    timer = new Timer();
    timerTask = new MyTimerTask();
    timer.schedule(timerTask, 0, 1000);
}

public void onPause ()
{
    super.onPause();
    timer.cancel(); // Renders Timer unusable for further schedule() calls.
}
3

Ich kann einen Timer und eine Aufgabe mit folgendem Code stoppen:

    if(null != timer)
    {

        timer.cancel();
        Log.i(LOG_TAG,"Number of cancelled tasks purged: " + timer.purge());
        timer = null;
    }

    if(task != null)
    {
        Log.i(LOG_TAG,"Tracking cancellation status: " + task.cancel());
        task = null;
    }
0
Vaibhav Agrawal
    Timer timer1;
    private boolean videoCompleteCDR=false;
    private boolean isVideoPlaying=false;   
    int videoTime=0;
    private int DEFAULT_VIDEO_PLAY_TIME = 30;  

    @Override
    public View onCreate(){
       isVideoPlaying = true; //when server response is successfully
    }


    @Override
    public void onPause() {
        super.onPause();

        if(isVideoPlaying ) {
            if(this.timer1 !=null) {
                this.timer1.cancel();
            }
        }
    }
    @Override
    public void onResume() {
        super.onResume();
        if(isVideoPlaying  && !videoCompleteCDR) {
            callTimerTask();
        }
    }

    @Override
    public void onHiddenChanged(boolean hidden) {
        super.onHiddenChanged(hidden);
        if (!hidden) {
            printLog( "GameFragment  visible ");
            if(isVideoPlaying  && !videoCompleteCDR) {
                callTimerTask();
            }

        } else {
            printLog("GameFragment in visible ");
            if(isVideoPlaying) {
                if(this.timer1 !=null) {
                    this.timer1.cancel();
                }
            }
        }
    }

    private void callTimerTask() {
        // TODO Timer for auto sliding
        printLog( "callTimerTask Start" );
        timer1 = new Timer();
        timer1.schedule(new TimerTask() {
            @Override
            public void run() {
                if (getActivity() != null) {
                    getActivity().runOnUiThread(new Runnable() {
                        @Override
                        public void run() {
                            if (getActivity() == null) {
                                return;
                            }
                            videoTime++;
                            if(DEFAULT_VIDEO_PLAY_TIME ==videoTime){
                                videoCompleteCDR=true;
                                Log.e("KeshavTimer", "callTimerTask videoCompleteCDR called.... " +videoTime);
                                destroyTimer();
                            }
                            Log.e("KeshavTimer", "callTimerTask videoTime " +videoTime);
                        }
                    });
                } else {
                    printLog("callTimerTask getActivity is null ");
                }
            }
        }, 1000, 1000);
        // TODO  300, 2000;
    }


    private void destroyTimer(){
        this.timer1.cancel();
    }
0
Keshav Gera