Хронометр Android, сохраняет состояние времени (и продолжает отсчет в фоновом режиме)

#android #android-activity #android-service #android-lifecycle #chronometer

#Android #android-активность #android-сервис #android-жизненный цикл #хронометр

Вопрос:

У меня есть таймер, который отсчитывает время с момента, когда пользователь сталкивается с этим действием

В настоящее время я использую хронометр, установленный во время onCreate (первоначально запускается только при выполнении определенных условий). Но мне нужно, чтобы хронометр продолжал считать вверх, пока приложение и все его представления не будут закрыты (для этого у меня есть функция «Выход»).

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

Я не нашел интуитивно понятного способа сохранить состояние хронометра или отсчет в фоновом режиме самостоятельно (или, возможно, самостоятельно отслеживать время и визуально обновлять хронометр в другой момент времени)

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

любая информация об известном подходе к этой проблеме будет оценена!

Это еще более сложно, потому что это действие в tabhost’е, а tabhosts вызывают как onPause, так и onResume каждый раз, когда вы загружаете представление, поэтому это нарушает функции жизненного цикла.

Ответ №1:

Существует несколько способов сохранения времени. Самый простой, который я нашел, — сохранить время в Intent, которое использовалось для создания исходного activity via getIntent().putExtra("START_TIME", floatvalue) . Вы можете получить значение с getIntent().getFloatExtra("START_TIME", 0f) помощью . Выполнение этого способа имеет ряд преимуществ:

  • Это не нарушает жизненный цикл активности и не требует контекста.
  • Его можно легко передавать между другими действиями и приложениями.
  • Он сохраняется среди пауз и остановок.
  • Для этого не требуются специальные прослушиватели.
  • Он не создает никаких новых объектов (намерение используется для создания действия в первый раз).

Это решение отлично подходит для сохранения активности с вкладками или в диалоговых окнах и т. Д. У него есть некоторые ограничения, если оставить приложение для более интенсивного использования памяти, но только если ваша активность будет уничтожена (из-за памяти).

Комментарии:

1. Это метод, который я использую в нескольких своих приложениях под названием Intent Recycling. У меня есть пара статей об этом и другие методы, связанные с намерениями.

Ответ №2:

Из-за моего Tabhost нельзя было полагаться на функции жизненного цикла.

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

  tabHost.setOnTabChangedListener(new OnTabChangeListener(){

        @Override
        public void onTabChanged(String arg0) {
            // TODO Auto-generated method stub
            if(arg0.contentEquals("homeGroup"))
            {
                //store time in centralhelper.java
                                    //stopWatch is of type Chronometer
                                    //stopWatchLastTime is of type Long and is initially set to zero. Chronometer uses milliseconds to determine time, will never be zero after set
                CentralHelper.stopWatchLastTime = CentralHelper.stopWatch.getBase();
            }
        }

    });
  

Когда загружается представление моей домашней группы, вызывается функция onResume(), здесь есть условие для получения времени, с которого хронометр возобновит отсчет. Несмотря на то, что tabhost будет вызывать как onPause(), так и onResume() при КАЖДОЙ загрузке вне обычных функций жизненного цикла, они все равно вызываются перед onCreate()

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

    //update Chronometer with time stored in tabchangelistener
    if(CentralHelper.stopWatchLastTime!=0)
        CentralHelper.stopWatch.setBase(CentralHelper.stopWatchLastTime);
}
  

это позволило мне выполнить аналогичную проверку в onCreate ()

     if(CentralHelper.stopWatchLastTime!=0)
    {

        CentralHelper.stopWatch.start(); //this is where it resumes counting from the base set in onResume()
    }
    else
    {
        CentralHelper.stopWatch.start();
        CentralHelper.stopWatch.setBase(SystemClock.elapsedRealtime());
    }
  

Ответ №3:

Когда вы переключаетесь на другое действие, предыдущее действие приостанавливается (onPause, as и так далее, в прикрепленном изображении), Когда вы возвращаетесь к действию, оно возобновляется, но иногда, когда у dalvik заканчивается память, ваш объект Activity может быть удален при отображении ton.

Если вы сохраняете данные своего приложения в экземпляре Activity, вы можете случайно их потерять, пожалуйста, ознакомьтесь с этим жизненным циклом Activity http://developer.android.com/reference/android/app/Activity.html

введите описание изображения здесь

Комментарии:

1. Я знаком с этим, теперь у вас есть решение, как сохранить время хронометра? Возможно, перенесите его в другой поток или сохраните время в sharedpreferences другим способом восстановить его позже

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

Ответ №4:

Этот подход протестирован, и он работает очень хорошо. Попробуйте это:

Возьмите логическую переменную volatile, которая будет управлять вашим потоком (запуск / остановка). Сделайте три текстовых представления, часовое, минимальное и секундное текстовые представления и полностью удалите хронометр. Обновите свой пользовательский интерфейс, используя Handler запись следующего кода.

 public void timeUpdate()
{
    timerThread = new Thread(new Runnable() {

        @Override
        public void run() {
            while(continueThread){
                Date newDate = new Date();
                if(((newDate.getTime()) - date.getTime()) > 1000){
                    secondCounter = secondCounter 1;
                    mHandlerUpdateSec.post(mUpdateSec);
                    System.out.println("Inside the Theread ..." secondCounter);
                    if(secondCounter > 59){
                        minuteCounter = minuteCounter   1;
                        mHandlerUpdateMinute.post(mUpdateMinute);
                        secondCounter = 0;
                        if(minuteCounter > 59){
                            hourCounter = hourCounter   1;
                            mHandlerUpdateHour.post(mUpdateHour);
                            minuteCounter = 0;
                        }
                    }
                }
                try{
                    timerThread.sleep(1000);
                }catch (Exception e) {
                    // TODO: handle exception
                }
            }
        }
    });
    timerThread.start();
}
  

continueThread является логической изменчивой переменной. Установка значения false остановит поток. TimerThread является экземпляром thread . Есть три счетчика: счетчики часов, минут и секунд, которые выдадут вам последние значения времени. Обработчики обновляются следующим образом.

 final Handler mHandlerUpdateSec = new Handler();
final Runnable mUpdateSec = new Runnable() {
    public void run() {
        String temp = ""   secondCounter;
        System.out.println("Temp second counter length: "   temp.length());
        if(temp.length() == 1)
            secTextView.setText("0"   secondCounter);
        else
            secTextView.setText(""   secondCounter);
    }
};
final Handler mHandlerUpdateMinute = new Handler();
final Runnable mUpdateMinute= new Runnable() {
    public void run() {
        String temp = ""   minuteCounter;
        System.out.println("Temp second counter length: "   temp.length());
        if(temp.length() == 1)
            minTextView.setText("0"   minuteCounter);
        else
            minTextView.setText(""   minuteCounter);
    }
};
final Handler mHandlerUpdateHour = new Handler();
final Runnable mUpdateHour = new Runnable() {
    public void run() {
        String temp = ""   hourCounter;
        System.out.println("Temp second counter length: "   temp.length());
        if(temp.length() == 1)
            hourTextView.setText("0"   hourCounter);
        else
            hourTextView.setText(""   hourCounter);
    }
};
  

Теперь, когда вы хотите запустить таймер, установите для continueThread значение true и вызовите timeUpdate() . Чтобы остановить его, просто выполните continueThread = false . Чтобы снова запустить поток, установите для continueThread значение true и снова вызовите timeUpdate() . Убедитесь, что вы соответствующим образом обновляете счетчики при запуске / остановке таймера.

Комментарии:

1. Отлично! Просто быстрое изменение. При изменении textviews я изменил условие if на if(secondCounter < 10) [и счетчик минут / счетчик часов]. Таким образом, вам не понадобится новая строка и новая строка. length () каждую секунду, минуту и час. Я думаю, что это может дать хороший толчок производительности. Кроме того, я адаптировал его для использования EventBus, поэтому я могу использовать это без привязки к textviews.

Ответ №5:

Вы можете сохранить время начала в sharedpreferences (или файле и т. Д.) И установить свой подсчет на основе этого (вместо того, чтобы начинать с 0) В onResume().

Вашему пользовательскому интерфейсу могут потребоваться некоторые изменения, чтобы учесть тот факт, что вам придется сбросить время начала, поскольку теоретически оно может считаться вечно.

Комментарии:

1. Это то, что я пытался сделать, но мои функции жизненного цикла также выходят из строя. (моя активность вызывает onPause (), когда я ухожу от нее, И когда она возобновляется…. Я даже пробовал onStop(), и он вызывается оба раза)