Android 開發中常需執行週期性任務(輪詢、心跳、同步)或延遲任務。Timer 提供背景執行緒定時排程,但不能直接更新 UI;Handler 綁定主執行緒 Looper,可安全更新 UI。兩者結合是經典模式。本文系統整理 Timer、Handler、Runnable 的單獨與組合用法。
// 成員變數
private Timer timer = new Timer();
private static final int INTERVAL_MS = 5000;
// 初始化
timer.schedule(new TimerTask() {
@Override public void run() {
// 背景執行緒執行,不可直接操作 View
doBackgroundWork();
}
}, INTERVAL_MS, INTERVAL_MS); // 首次延遲、週期皆 5 秒
private Handler uiHandler = new Handler(Looper.getMainLooper()) {
@Override public void handleMessage(Message msg) {
if (msg.what == 1) {
textView.setText("資料已更新:" + System.currentTimeMillis());
}
}
};
private TimerTask createUITask() {
return new TimerTask() {
@Override public void run() {
// 背景工作
String data = fetchData();
// 送訊息給主執行緒
Message msg = uiHandler.obtainMessage(1, data);
uiHandler.sendMessage(msg);
}
};
}
輕量級週期任務可僅用 Handler 實現,避免額外執行緒開銷:
private Handler handler = new Handler(Looper.getMainLooper());
private Runnable periodicTask = new Runnable() {
@Override public void run() {
updateUI();
handler.postDelayed(this, 2000); // 2 秒後再次執行
}
};
// 啟動
handler.post(periodicTask);
// 停止
handler.removeCallbacks(periodicTask);
enum State { FREE, CONNECTING, CONNECTED, LOGGED_IN, IN_ROOM }
private State state = State.FREE;
private Timer timer = new Timer();
private Handler handler = new Handler(Looper.getMainLooper());
private void startStateMachine() {
timer.schedule(new TimerTask() {
@Override public void run() {
switch (state) {
case FREE:
connect("10.58.1.59", 8906); break;
case CONNECTED:
login("user", "pwd"); break;
case LOGGED_IN:
enterRoom(1); break;
case IN_ROOM:
handler.sendEmptyMessage(1); // 通知 UI 開啟視訊
break;
}
}
}, 0, 3000); // 每 3 秒檢查一次
}
handler = new Handler(Looper.getMainLooper()) {
@Override public void handleMessage(Message msg) {
if (msg.what == 1) startVideoPreview();
}
};
Activity.onDestroy() 呼叫 timer.cancel(),並設 timer = null。WeakReference<Activity>,或使用 Handler(Looper.getMainLooper()) 並在 onDestroy removeCallbacksAndMessages(null)。| 方案 | 優點 | 缺點 | 適用場景 |
|---|---|---|---|
| Timer + Handler | 背景執行緒不阻塞 UI,精確週期 | 兩個物件管理較繁瑣 | 需在背景做耗時運算再更新 UI |
| Handler + Runnable | 單一物件、程式碼簡潔 | 任務在主執行緒執行,耗時操作會卡頓 | 輕量級 UI 週期更新、延遲執行 |
| ScheduledExecutorService | 功能最強、支援取消、固定延遲/固定頻率 | API 較複雜 | 高併發、精確排程、需取消未來任務 |