#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(), и он вызывается оба раза)