Возобновление CountdownTimer после ротации

У меня есть CountdownTimer, который отсчитывает от 60 секунд. Этот CountdownTimer работает, устанавливая textView на оставшиеся миллисекунды, но всякий раз, когда я поворачиваю свое устройство, CountdownTimer сбрасывается.

Я знаю, что это происходит, потому что Activity перезапускается при ротации. Поэтому я попытался сохранить время, оставшееся в пакете, а затем восстановить его после перезапуска Activity.

long transferValue;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_playtimemode);

    Log.d("Debug", "onCreate: " + transferValue);

    long setTime = 60000;
    long difference = setTime - transferValue;

    new CountDownTimer(difference, 1000) {

        public void onTick(long millisUntilFinished) {
            millisUntilFinishedToSave = millisUntilFinished;
            tvCountdown.setText("" + millisUntilFinished / 1000);
        }

        public void onFinish() {
            tvCountdown.setText("done!");
        }
    }.start();

}

@Override
protected void onSaveInstanceState(Bundle outState) {
    super.onSaveInstanceState(outState);
    outState.putLong("millisKey", millisUntilFinishedToSave);

}

@Override
protected void onRestoreInstanceState(Bundle savedInstanceState) {
    super.onRestoreInstanceState(savedInstanceState);
    transferValue = savedInstanceState.getLong("millisKey");
    Log.d("Debug", "onRestoreInstanceState(): " + transferValue);
}

Однако это не работает. Я инициализирую transferValue в верхней части этого кода (следовательно, он возвращает 0), но как еще я могу сохранить данные из saveInstanceState в CountdownTimer?

07-06 20:21:30.038: D/Debug(28995): onCreate: 0
07-06 20:21:30.043: D/Debug(28995): onRestoreInstanceState(): 55994

person simon.vandel    schedule 06.07.2012    source источник


Ответы (3)


Я бы дал вашему таймеру собственную нить. Ваш таймер останавливается, потому что он находится в потоке пользовательского интерфейса (как вы сказали), и когда пользовательский интерфейс перерисовывает действие, оно повторно инициализируется. Все длительные процессы должны иметь свой собственный поток. Эмпирическое правило: выходите из потока пользовательского интерфейса как можно скорее.

Вот пример использования Сервиса. Эта служба запускается при вызове и остается в памяти независимо от изменения ориентации экрана или даже изменения фокуса активности.

Вот услуга:

public class Timer extends Service {

    @Override
    public IBinder onBind(Intent i) {
        return null;
    }
    @Override
    public int onStartCommand(Intent i, int flags, int startId) {
        // Put your timer code here
    }
}

Вам нужно будет добавить эту строку в свой манифест (где-то между тегами открытия/закрытия приложения):

<service android:name=".Timer" />

Затем вы можете запустить службу в любое время, используя это (важно отметить, что вы можете запускать ее снова и снова, рекурсивные вызовы не создают новую службу):

startService(new Intent(this, Timer.class));
person user1449018    schedule 06.07.2012
comment
Можете ли вы дать мне фрагмент кода для этого? Таймер должен остановить обратный отсчет, когда начнется вращение, а затем возобновить его, когда вращение закончится. Это возможно? - person simon.vandel; 06.07.2012
comment
Реализация Мэтта Уэстлейка более компактна, так вы сэкономите место. Однако, если у вас будет несколько таймеров или вам нужно получить доступ к значениям в другом классе, воспользуйтесь моим ответом. Я отредактирую свой пост, чтобы показать код. - person user1449018; 06.07.2012
comment
Остерегайтесь этого распространенного недоразумения — Service выполняется в основном потоке пользовательского интерфейса, а не в фоновом потоке. - person Richard Le Mesurier; 25.03.2014

Используйте System.currentTimeMillis, чтобы получить текущее системное время, затем добавьте 60000 миллисекунд ко времени и сохраните его как конечное время. Затем в любое время, когда вам нужно что-то изменить, просто сравните System.currentTimeMillis с EndTime.

Endtime = System.currentTimeMillis + 60000;

затем на каждом экземпляре

TimeRemaining = Endtime - System.currentTimeMillis
person Matt Westlake    schedule 06.07.2012
comment
Так что я не использую обратный отсчет Timer? - person simon.vandel; 06.07.2012
comment
Этот ответ не получил должного признания. я люблю это - person Florian Walther; 13.01.2018

Принятый ответ делает вещь очень сложной. Вы можете сделать это более простым способом. Проблема в вашем коде заключается в том, что Activity создается при ротации (см. Жизненный цикл Activity), так же как и экземпляр CountdownTimer.

Я мог бы написать весь код примера, но здесь есть хороший ответ от @Drew: Справочник по Android Innerclass TextView при возобновлении активности

person spacebiker    schedule 10.06.2015