2010年10月13日 星期三

在 Android 使用 Timer

有時必須用到簡單的計時排程功能,
以下兩個小範例示範實作 1000 毫秒的 Timer,
兩種方式需注意一點,使用 Timer 方式雖然簡單,
但 TimerTask 是在 Background Thread 被呼叫,
所以無法在 TimerTask 中直接操作 UI Element,
必須委托 main thread 的 handler 協助,

比較直觀的 Timer


import java.util.*;

public class MainActivity extends Activity
{
  Timer timer = new Timer(true);

  @Override
  public void onCreate(Bundle savedInstanceState)
  {
    super.onCreate(savedInstanceState);
    timer.schedule(new MyTimerTask(), 1000, 1000);
  }

  public class MyTimerTask extends TimerTask
  {
    public void run()
    {
    }
  };
}


此外需注意的是當我們要停止這個 Timer 時,我們可以使用以下指令

timer.cancel();
已經被 cancel 後的 timer 無法再次 schedule 必須再重新 new 一個,另外如果發生 TimerTask 已經被使用的 Exception 時,記得看看是不是因為將 TimerTask 宣告為類別成員並重用了,正確的做法是每需要重新 new TimerTask 才對。

利用 Handler 做同樣的事


import android.os.Handler;

public class MainActivity extends Activity
{
  public class MainActivity extends Activity
  private int m_nTime = 0;
  private Handler mHandlerTime = new Handler();

  @Override
  public void onCreate(Bundle savedInstanceState)
  {
    super.onCreate(savedInstanceState);
    mHandlerTime.postDelayed(timerRun, 1000);
  }

  @Override
  public void onDestroy()
  {
    mHandlerTime.removeCallbacks(timerRun);
    super.onDestroy();
  }

  private final Runnable timerRun = new Runnable()
  {
    public void run()
    {
      ++m_nTime; // 經過的秒數 + 1
      mHandlerTime.postDelayed(this, 1000);
      // 若要取消可以寫一個判斷在這決定是否啟動下一次即可
    }
  };
}


8 則留言:

  1. 使用Timer如果遇到修改UI版面時會出現錯誤,藉由Handler的使用就不會出錯。就我的理解是在Android只有主Thread可以修改或是構件UI。

    回覆刪除
  2. http://developer.android.com/reference/java/util/Timer.html
    This document says "Each timer has one thread on which tasks are executed sequentially."


    http://developer.android.com/guide/topics/fundamentals/processes-and-threads.html
    This document says "Do not access the Android UI toolkit from outside the UI thread (main thread), or it can result in undefined and unexpected behavior."


    I think that's why we can not use Timer to access the UI interface.

    回覆刪除
  3. 害人啊,无法使用timer.purge();停止timer。

    static int count = 0;

    public static void main(String[] args) throws IOException
    {
    Timer timer = new Timer(true);

    Calendar calendar = Calendar.getInstance();
    calendar.add(Calendar.SECOND, 1);

    timer.schedule(new TimerTask()
    {

    @Override
    public void run()
    {
    System.out.println(count);
    count++;
    }
    }, calendar.getTime(), 1000);

    BufferedReader streamReader = new BufferedReader(new InputStreamReader(System.in));
    streamReader.readLine();

    timer.purge();

    streamReader.readLine();

    }

    按下回车后timer仍然向控制台输出消息。

    回覆刪除
    回覆
    1. Purge 是清除已取消的 Tasks,
      http://developer.android.com/reference/java/util/Timer.html
      purge()
      Removes all canceled tasks from the task queue.

      刪除
  4. 謝謝幾位的指正,已更新 :)

    回覆刪除
  5. private ing m_nTime = 0;
    是int嗎@@
    我ing宣告出錯

    回覆刪除
  6. 作者已經移除這則留言。

    回覆刪除