Edited at

AndroidでTimerを使わずHandlerだけでお手軽に定期実行してあげる


UIスレッドの処理をTimerを使わずHandlerだけで簡単定期実行したい

『1秒間隔で定期的に何かの処理を行う』という実装を行う際、パッと思いつくのはTimerとTimerTaskを使った以下のような実装。

ただ、その際TimerTask.run()の中で実行されるコードはTimerのThreadなので、

UIパーツへの操作など、UIスレッドで実行が必要な操作をするにはHandlerを使う必要があります。


課題

そうなると、

1. UIスレッドがTimerを実行

2. TimerスレッドがUIスレッドに返す

3. UIスレッドでdoSomething実行

みたいな、ちょっとわかりづらい処理になってしまいます。

コードだとこんな感じが必要になります。

(ネストが深いですが、処理のループがわかりやすいので、そのまま。)


Before


final Handler handler = new Handler();
TimerTask task = new TimerTask() {
int count = 0;
@Override
public void run() {
// Timerのスレッド
handler.post(new Runnable() {
@Override
public void run() {
// UIスレッド
if (count > 5) { // 5回実行したら終了
cancel();
}
doSomething(); // なにかやる
count++;
}
});
}
};
Timer t = new Timer();
t.scheduleAtFixedRate(task, 0, 1000);


対策

TimerとTimerTaskがほとんど何もやってない感じなので、その2クラスを消したいです。

HandlerのpostDelayedを使うと、Timer・TimerTaskを削除して、定期実行することができるようになります。


After


final Handler handler = new Handler();
final Runnable r = new Runnable() {
int count = 0;
@Override
public void run() {
// UIスレッド
count++;
if (count > 5) { // 5回実行したら終了
return;
}
doSomething(); // 何かやる
handler.postDelayed(this, 1000);
}
};
handler.post(r);

キャンセルしたいときは

handler.removeCallbacks(r);

で、runnableとの関係を切ってあげればOKです。

割と直感的なコードになりました。

この程度であればお手軽にUIスレッドでも定期実行できそうです。


参考

TIMER(TASK) = BAD! DO IT THE ANDROID WAY: USE A HANDLER