Подтвердить что ты не робот

Пауза/остановка и запуск/возобновление Java TimerTask непрерывно?

У меня есть один простой вопрос относительно Java TimerTask. Как приостановить/возобновить две задачи TimerTask на основе определенного условия? Например, у меня есть два таймера, которые работают между собой. Когда в задаче первого таймера выполняется определенное условие, первый таймер останавливается и запускает второй таймер, и то же самое происходит, когда определенное условие выполняется в задаче второго таймера. В приведенном ниже классе показано, что я имею в виду:

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

Итак, мой вопрос: как приостановить timer1 во время работы timer2 и наоборот, пока выполняется timer2? Производительность и сроки - моя главная проблема, так как это необходимо реализовать в другом потоке. Кстати, я пытаюсь реализовать эти параллельные таймеры на Android.

Спасибо за вашу помощь!

4b9b3361

Ответ 1

Из TimerTask.cancel():

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

Итак, как только он отменен, он больше никогда не запустится. Вам лучше было бы использовать более современный ScheduledExecutorService (из Java 5 +).

Изменить: Основная конструкция:

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

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

TimerTask может быть проще в этом случае, но вам нужно будет создать новый экземпляр при запуске. Его нельзя использовать повторно.

В качестве альтернативы вы можете инкапсулировать каждую задачу как отдельную временную службу:

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

Ответ 2

Самое простое решение, которое я нашел: просто добавьте логическое значение в код запуска в задаче таймера, например:

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

Ответ 3

Если вы уже отменили один таймер, вы не можете его повторно запустить, вам нужно будет создать новый.

См. этот ответ, он содержит видео и исходный код, как я сделал что-то подобное.

В принципе существуют два метода: pause и resume

В паузе:

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

В резюме:

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

Это делает восприятие паузы/возобновления.

Если ваши таймеры выполняют разные действия в зависимости от состояния приложения, вы можете использовать StatePattern

Fist определяет абстрактное состояние:

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

И укажите как можно больше состояний. Ключ в том, что одно государство ведет вас к другому.

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

И затем вы изменяете состояние в своем таймере.

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

Наконец, если вам нужно выполнить одно и то же, но с разной скоростью, вы можете использовать TimingFramework. Это немного сложнее, но позволяет делать классные анимации, позволяя рисовать определенный компонент с разной скоростью (вместо того, чтобы быть линейным)

Ответ 4

Рассматривая ваш исходный код, вот изменения (которые в значительной степени подтверждают мой предыдущий ответ)

В задании 1:

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

и в задании 2:

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

Он работает на моей машине:

it works!

Ответ 5

По-моему, это несколько ошибочно. Если вашему коду нужны временные гарантии, вы не можете использовать Таймер в любом случае и не хотите. "Этот класс не предлагает гарантии в реальном времени: он планирует задачи с использованием метода Object.wait(long)".

Ответ, IMHO, заключается в том, что вы не хотите приостанавливать и перезапускать таймеры. Вы просто хотите подавить свои методы запуска от своего бизнеса. И это просто: вы просто заверните их в оператор if. Коммутатор включен, они работают, выключатель выключен, они пропускают этот цикл.

Изменить: Вопрос существенно изменился с того, что было изначально, но я оставлю этот ответ, если он поможет кому-либо. Я хочу сказать следующее: если вам неинтересно, когда ваше событие срабатывает в течение периода в миллисекундах (только то, что он не ПРЕВЫШАЕТСЯ один раз каждые N миллисекунд), вы можете просто использовать условные обозначения для методов запуска. Это, по сути, очень распространенный случай, особенно когда N меньше 1 секунды.

Ответ 6

Android не будет повторно использовать TimerTask, который уже был запланирован один раз. Поэтому необходимо восстановить как Таймер, так и TimerTask, например, как в фрагменте:

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.
}

Ответ 7

Я могу остановить таймер и задачу, используя следующий код:

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

Ответ 8

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