J'utilise une minuterie pour créer un chronomètre. Le minuteur fonctionne en augmentant une valeur entière. Je souhaite ensuite afficher cette valeur dans l'activité en mettant constamment à jour une vue de texte.
Voici le code du service où j'essaie de mettre à jour la vue de texte de l'activité:
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);
}
J'ai eu une sorte d'erreur sur la mise à jour de l'interface utilisateur dans le mauvais fil.
Comment puis-je adapter mon code pour accomplir cette tâche de mise à jour constante de la vue texte?
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
}
};
Le code ci-dessus fonctionnera ...
Remarque: Les gestionnaires doivent être créés dans votre thread principal pour que vous puissiez modifier le contenu de l'interface utilisateur.
Utilisez plutôt Handler
pour mettre à jour l'interface utilisateur toutes les X secondes. Voici une autre question qui montre un exemple: Répéter une tâche avec un délai?
Votre approche ne fonctionne pas car vous essayez de mettre à jour une interface utilisateur à partir d'un thread non-UI. Ceci n'est pas autorisé.
StopWatch.time.post(new Runnable() {
StopWatch.time.setText(formatIntoHHMMSS(elapsedTime));
});
ce bloc de code est basé sur Handler mais vous n'avez pas besoin de créer votre propre instance Handler.
TimerTask implémente Runnable, ce qui en ferait un thread. Vous ne pouvez pas mettre à jour le thread d'interface utilisateur principal directement à partir d'un thread différent sans aucun travail. Une chose à faire est d’utiliser Async Task pour créer le minuteur et publier une mise à jour toutes les secondes pour mettre à jour l’UI.
Je suppose que StopWatch.time
est une référence statique ou publique à votre TextView. Au lieu de cela, vous devez implémenter un BroadcastReceiver pour communiquer entre votre minuterie (qui s'exécute à partir d'un thread séparé) et votre TextView.
Vous pouvez utiliser l'utilitaire suivant:
/**
* 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);
}
}
Ensuite, n'importe où dans le code exécuté par le thread d'interface utilisateur, vous pouvez l'utiliser simplement comme ceci:
TaskScheduler timer = new TaskScheduler();
timer.scheduleAtFixedRate(new Runnable() {
@Override
public void run() {
time.setText(simpleDateFormat.format(GamePlay.instance().getLevelTime()));
}
},1000);
vous pouvez utiliser Handler.
ce code augmente un compteur toutes les secondes et show et met à jour la valeur du compteur sur un 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);
}
}