Android中使用Timer時需要同時訪問TimerTask,Handle等類,手續繁雜而且是真正想做的事淹沒在手續化的代碼中。本文介紹了的SaftyTimer類隱藏了TimerTask,Handle等類,並通過Observer設計模式為使用者提供簡單,低耦合的實現方式。
關於Android定時器的使用,網上有很多例子。一般來講是這樣的。
public class TestTimerextends Activity {
Timer timer = new Timer();
Handler handler = new Handler(){
public void handleMessage(Message msg) {
switch (msg.what) {
case 1:
setTitle("hear me?"); //這裡才是要做的事情。
break;
}
super.handleMessage(msg);
}
};
TimerTask task = new TimerTask(){
public void run() {
Message message = new Message();
message.what = 1;
handler.sendMessage(message);
}
};
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
timer.schedule(task,10000); //啟動定時器
}
}
之所以要這麼麻煩的原因是TimerTask的run方法是在一個獨立的Task裡執行的,和我們的用用不在一個上下文中,所以不能直接在TimerTask的run方法中執行我們希望定期執行的代碼。
作為解決這個問題的方案之一,引入了Handler類,先由TimerTask調用Handler.sendMessage(多任務安全)向Handler發訊息(在這個地方,其實什麼訊息都可以),Android先可以保證,等到Handler.handleMessage的時候,就已經是和應用在同一個上下文裡了。
以下是參考資料
Timer:http://developer.android.com/reference/java/util/Timer.html
TimerTask:http://developer.android.com/reference/java/util/TimerTask.html
Handler:http://developer.android.com/reference/android/os/Handler.html
看起來挺累的吧,要找到我們真正想做的事還真是不容易。但是又不得不看。有沒有辦法把這件事弄的漂亮一點呢,有。
方法1:利用類的繼承
首先寫一個如下的基類,基本上例子中的代碼相同,只是在定義了一個沒有內容的OnTimer方法留給衍生類別實現。
public class TemplateMethodTimer {
private Timer mTimer = null;
private Handler mHandler = null;
private TimerTask mTask = null;
//TemplateMethod介面定義,具體動作有衍生類別時裝。
public void OnTimer(){
}
//啟動定時器
public void startTimer(long interval){
mHandler = new Handler(){
public void handleMessage(Message msg) {
OnTimer(); //調用模板方法。
super.handleMessage(msg);
}
};
mTask = new TimerTask(){
public void run() {
Message message = new Message();
message.what = 0; //anything is ok.
mHandler.sendMessage(message);
}
};
mTimer = new Timer();
mTimer.schedule(mTask, 0, interval);
}
//停止Timer動作
//釋放獲得的資源。
public void stopTimer(){
mTimer.cancel();
mTimer.purge();
mTimer = null;
mHandler = null;
mTask = null;
}
}
有了這個類我們就可以相下面這樣先定義一個衍生類別並提供OnTimer方法的實現。
class MyTimer extends TemplateMethodTimer{
public void OnTimer(){
Log.i(TAG, "MyTimer.OnTimer");
}
}
然後建立一個定時器並進行啟動停止操作
MyTimer mMt = new MyTimer();
mMt.startTimer(500);
mMt.stopTimer();
當然在JAVA中我們可以向下面這樣建立Timer
TemplateMethodTimer mTt = new TemplateMethodTimer(){
public void OnTimer(){
Log.i(TAG, "TestTimer.OnTimer");
}
};
本質上是一樣的代碼。
方法2:利用類的Observer設計模式,這時Timer類是這樣的。
public class ObserverTimer {
private Timer mTimer = null;
private Handler mHandler = null;
private TimerTask mTask = null;
private OnTimeListener mListener = null;
private static final String TAG = new String("SafetyTimer");
//Observer介面定義
public interface OnTimeListener{
public void OnTimer();
}
//建立定時器並指定Observer
public void setListener(OnTimeListener listener){
mListener = listener;
}
//啟動定時器
public void startTimer(int interval){
mHandler = new Handler(){
public void handleMessage(Message msg) {
if(mListener != null){
mListener.OnTimer();
Log.i(TAG, "mListener.OnTimer()");
}
super.handleMessage(msg);
}
};
mTask = new TimerTask(){
public void run() {
Message message = new Message();
message.what = 0; //anything is ok.
mHandler.sendMessage(message);
}
};
mTimer = new Timer();
mTimer.schedule(mTask, 0, interval);
}
//停止Timer動作
//釋放獲得的資源。
public void stopTimer(){
mTimer.cancel();
mTimer.purge();
mTimer = null;
mHandler = null;
mTask = null;
Log.i(TAG, "stopTimer()");
}
}
這段代碼與方法一的不同點在於。
1.沒有定義供覆蓋的方法但是定義了一個OnTimerListener類。
2.增加了OnTimerListener類型的資料成員mListener並提供設定它的介面。
3.在Handler的訊息處理中沒有調用自己的方法(也沒有)而是調用設定好的mListener.OnTimer()
有了這個ObserverTimer類,我們就可以像下面這樣建立和使用Timer了。
ObserverTimer mOt = new ObserverTimer();
mOt.setListener(new ObserverTimer.OnTimeListener() {
@Override
public void OnTimer() {
Log.i(TAG, "ObserverTimer.OnTimer");
}
});
mOt.startTimer(1000);
mOt.stopTimer();
是不是好多了。這樣的代碼在Android裡到處都是,關鍵是我們自己做的代碼會不會做成這樣的。
用法好像區別不大,那麼哪個個方法更好些呢?
方法1是定義了,一個不知道自己應該幹什麼的基類,然後通過衍生類別實現做某某事的Timer。抽象的是Timer。
方法2是定義的一個專門響應Timer的Listener基類,通過Listener的衍生類別實現具體的功能工作。抽象的要做的事,應該說更接近本質吧。即使是從功利的角度來看也可以看出Listener是可以動態登入和刪除,比較靈活。當然更不用說如果對Obersever稍加改造,可以實現多個對象響應Timer事件了。
不言自明了吧。
通過本文,我們可以看到通過Observer設計模式封裝,隱藏複雜的Timer處理的方法。這樣下一個再用Timer的人,就不必再走一次別人已經走過的路而把節約下來的時間用在其他需要挑戰的地方。這樣做其實沒有什麼難度,但是實際工作中會這麼做的恐怕還真就不多。無論如何請相信:這看似不大的一步,會從根本上改變我們的程式結構的。
在Android歌詞秀中用到的SaftyTimer類,就是用方法二實現的,供參考。
我們通過SaftyTimer封裝了灰色的Timer,TimerTask,Handler的功能然後通過定義SaftyTimer:OnTimeListener為利用者提供實現所需功能的途徑。
下面是時序圖
可以很清楚的看到從LayerPlayerService出發的調用中除了產生新對象的2條線以外,只有StartTimer,OnTimer,StopTimer三條線。而SaftyTimer右側的調用則相對會複雜很多。這就是封裝的效果。
以下是原始碼
package LyricPlayer.xwg;
import java.util.Timer;
import java.util.TimerTask;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
public class SafetyTimer {
private Timer mTimer = null;
private Handler mHandler = null;
private TimerTask mTask = null;
private OnTimeListener mListener = null;
private long mInterval = 0; //in milliseconds
private static final String TAG = new String("SafetyTimer");
//Observer介面定義
public interface OnTimeListener{
public void OnTimer();
}
//建立定時器並指定Observer
public SafetyTimer(long interval, OnTimeListener listener){
mInterval = interval;
mListener = listener;
}
//啟動定時器
public void startTimer(){
mHandler = new Handler(){
public void handleMessage(Message msg) {
if(mListener != null){
mListener.OnTimer();
Log.i(TAG, "mListener.OnTimer()");
}
super.handleMessage(msg);
}
};
mTask = new TimerTask(){
public void run() {
Message message = new Message();
message.what = 0; //anything is ok.
mHandler.sendMessage(message);
}
};
mTimer = new Timer();
mTimer.schedule(mTask, 0, mInterval);
}
//停止Timer動作
//釋放獲得的資源。
public void stopTimer(){
mTimer.cancel();
mTimer.purge();
mTimer = null;
mHandler = null;
mTask = null;
Log.i(TAG, "stopTimer()");
}
//Timer是否處於工作狀態。
public boolean isRunging(){
return (mTimer != null);
}
}
作者“道法自然”