Andorid歌詞秀設計思路(1)SafetyTimer – Android移動開發技術文章_手機開發 Android移動開發教學課程

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); 
    } 

 
作者“道法自然”

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。