<< Android-Note
TimerTaskの止め方
Timerを使って定期的に何かを実行したいときはTimerTaskを使うことが多いです。
TimerTaskを使っていると実行した後に処理を中断できないという問題で悩むことが多いので正しい(?)使い方をメモしておきます。
例えば100ミリ秒ごとにカウントして時間を表示するようなコードを書きました。
public class MainActivity extends Activity { Timer timer = new Timer(); long timeInMills = 0; Button countStartButton; Button countStopButton; TextView countText; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); countStartButton = (Button) findViewById(R.id.countStartButton); countStopButton = (Button) findViewById(R.id.countStopButton); countText = (TextView) findViewById(R.id.countText); countStartButton.setOnClickListener() { public void onClick(View v) { timer.scheduleAtFixedRate(new TimerTask() { public void run() { timeInMills += 100; countText.setText(Long.toString(timeInMills) + "mill seconds"); } }, 0, 100); } } countStopButton.setOnClickListener() { public void onClick(View v) { timeInMills = 0; timer.cancel(); } } } }
上のはTimerTaskをcancelしても永遠に動き続けてしまう失敗例です。
正しくは次のようにします。
public class MainActivity extends Activity { Timer timer = new Timer(); long timeInMills = 0; Button countStartButton; Button countStopButton; TextView countText; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); countStartButton = (Button) findViewById(R.id.countStartButton); countStopButton = (Button) findViewById(R.id.countStopButton); countText = (TextView) findViewById(R.id.countText); countStartButton.setOnClickListener() { public void onClick(View v) { if(timer == null){ timer = new Timer(); timer.scheduleAtFixedRate(new TimerTask() { public void run() { timeInMills += 100; countText.setText(Long.toString(timeInMills) + "mill seconds"); } }, 0, 100); } } } countStopButton.setOnClickListener() { public void onClick(View v) { timeInMills = 0; if(timer != null){ timer.cancel(); timer = null; } } } } }
Timerはインスタンスの再利用ができないのでカウントを再開するたびに新しいTimerオブジェクトを作る必要があります。
また、TimerTaskを定期的に実行するにはscheduleとscheduleAtFixedRateの2つのメソッドがあり、どっちも役割が同じように見えて実は次の違いがあります。
- schedule
直前に実行したタスクを基準にして次のタスクを実行
- scheduleAtFixedRate
一番初めに実行したタスクを基準にして(実行間隔×現在の実行回数)ミリ秒後にタスクを実行
もしタスクをscheduleの場合は直前のタスクに依存してしまうので、正確にカウントするにはscheduleAtFixedRateを使った方が良いみたいです。
© Kaz