Таймер Android, обновляющий текстовое представление (UI)
Я использую таймер для создания секундомера. Таймер работает, увеличивая целочисленное значение. Затем я хочу отобразить это значение в активности, постоянно обновляя текстовое представление.
Здесь мой код из службы, где я пытаюсь обновить текстовое представление активности:
protected static void startTimer() {
isTimerRunning = true;
timer.scheduleAtFixedRate(new TimerTask() {
public void run() {
elapsedTime += 1; //increase every sec
StopWatch.time.setText(formatIntoHHMMSS(elapsedTime)); //this is the textview
}
}, 0, 1000);
}
Я получил некоторую ошибку об обновлении пользовательского интерфейса в неправильном потоке.
Как я могу настроить свой код для выполнения этой задачи, постоянно обновляя текстовое представление?
Спасибо.
Ответы
Ответ 1
protected static void startTimer() {
isTimerRunning = true;
timer.scheduleAtFixedRate(new TimerTask() {
public void run() {
elapsedTime += 1; //increase every sec
mHandler.obtainMessage(1).sendToTarget();
}
}, 0, 1000);
}
public Handler mHandler = new Handler() {
public void handleMessage(Message msg) {
StopWatch.time.setText(formatIntoHHMMSS(elapsedTime)); //this is the textview
}
};
Над кодом будет работать...
Примечание. Обработчики должны быть созданы в основном потоке, чтобы вы могли изменять содержимое пользовательского интерфейса.
Ответ 2
Вместо обновления Handler
следует обновлять интерфейс каждые X секунд. Вот еще один вопрос, который показывает пример: Повторить задачу с задержкой по времени?
Ваш подход не работает, потому что вы пытаетесь обновить пользовательский интерфейс из потока, отличного от UI. Это не разрешено.
Ответ 3
StopWatch.time.post(new Runnable() {
StopWatch.time.setText(formatIntoHHMMSS(elapsedTime));
});
этот блок кода основан на Handler, но вам не нужно создавать свой собственный экземпляр Handler.
Ответ 4
TimerTask реализует Runnable, что сделает его потоком. Вы не можете обновлять основной поток пользовательского интерфейса непосредственно из другого потока без какой-либо работы.
Одна вещь, которую вы можете сделать, это использовать Async Task для создания таймера и публиковать обновления каждую секунду, которые будут обновлять пользовательский интерфейс.
Ответ 5
Я предполагаю, что StopWatch.time
- это статическая или общедоступная ссылка на ваш TextView. Вместо этого вы должны реализовать BroadcastReceiver для связи между вашим таймером (который выполняется из отдельного потока) и вашим TextView.
Ответ 6
Вы можете использовать следующую утилиту:
/**
* Created by Ofek on 19/08/2015.
*/
public class TaskScheduler extends Handler {
private ArrayMap<Runnable,Runnable> tasks = new ArrayMap<>();
public void scheduleAtFixedRate(final Runnable task,long delay,final long period) {
Runnable runnable = new Runnable() {
@Override
public void run() {
task.run();
postDelayed(this, period);
}
};
tasks.put(task, runnable);
postDelayed(runnable, delay);
}
public void scheduleAtFixedRate(final Runnable task,final long period) {
Runnable runnable = new Runnable() {
@Override
public void run() {
task.run();
postDelayed(this, period);
}
};
tasks.put(task, runnable);
runnable.run();
}
public void stop(Runnable task) {
Runnable removed = tasks.remove(task);
if (removed!=null) removeCallbacks(removed);
}
}
Затем в любом месте кода, который запускается в потоке пользовательского интерфейса, вы можете использовать его просто так:
TaskScheduler timer = new TaskScheduler();
timer.scheduleAtFixedRate(new Runnable() {
@Override
public void run() {
time.setText(simpleDateFormat.format(GamePlay.instance().getLevelTime()));
}
},1000);
Ответ 7
вы можете использовать Handler.
этот код увеличивать счетчик каждую секунду и показывать и обновлять значение счетчика на textView.
public class MainActivity extends Activity {
private Handler handler = new Handler();
private TextView textView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
textView = (TextView) findViewById(R.id.text);
startTimer();
}
int i = 0;
Runnable runnable = new Runnable() {
@Override
public void run() {
i++;
textView.setText("counter:" + i);
startTimer();
}
};
public void startTimer() {
handler.postDelayed(runnable, 1000);
}
public void cancelTimer() {
handler.removeCallbacks(runnable);
}
@Override
protected void onStop() {
super.onStop();
handler.removeCallbacks(runnable);
}
}
Ответ 8
timer.schedule(new TimerTask() {
@Override
public void run() {
//your actions
}
},1*1000);//1 sec