分享

Andorid歌词秀设计思路(1)SafetyTimer

 五谷杂味 2011-09-11

Android中使用Timer时需要同时访问TimerTask,Handle等类,手续繁杂而且是真正想做的事淹没在手续化的代码中。本文介绍 了的SafetyTimer类隐藏了TimerTask,Handle等类,并通过Observer设计模式为用户提供简单,低耦合的实现方式。

首先看一下SafetyTimer在整个软件中的位置。

有点偏,不过没有关系。

让我们开始。

关于Android定时器的使用,网上有很多例子。一般来讲是这样的。

  1. public class TestTimerextends Activity {   
  2.     Timer timer = new Timer();    
  3.     Handler handler = new Handler(){   
  4.         public void handleMessage(Message msg) {   
  5.             switch (msg.what) {       
  6.             case 1:       
  7.                 setTitle("hear me?");        //这里才是要做的事情。  
  8.                 break;        
  9.             }        
  10.             super.handleMessage(msg);   
  11.         }    
  12.     };    
  13.     TimerTask task = new TimerTask(){   
  14.         public void run() {   
  15.             Message message = new Message();       
  16.             message.what = 1;        
  17.             handler.sendMessage(message);      
  18.         }    
  19.     };    
  20.     public void onCreate(Bundle savedInstanceState) {   
  21.         super.onCreate(savedInstanceState);   
  22.         setContentView(R.layout.main);    
  23.         timer.schedule(task,10000);    //启动定时器  
  24.     }    
  25. }    

之所以要这么麻烦的原因是TimerTask的run方法是在一个独立的Task里执行的,和我们的用用不在一个上下文中,所以不能直接在 TimerTask的run方法中执行我们希望定期执行的代码。

作为解决这个问题的方案之一,引入了Handler类,先由TimerTask调用Handler.sendMessage(多任务安全)向 Handler发消息(在这个地方,其实什么消息都可以),Android先可以保证,等到Handler.handleMessage的时候,就已经是 和应用在同一个上下文里了。

以下是参考资料

看起来挺累的吧,要找到我们真正想做的事还真是不容易。但是又不得不看。有没有办法把这件事弄的漂亮一点呢,有。

方法1:利用类的继承

首先写一个如下的基类,基本上例子中的代码相同,只是在定义了一个没有内容的OnTimer方法留给派生类实现。

  1. public class TemplateMethodTimer {  
  2.     private Timer mTimer = null;  
  3.     private Handler mHandler = null;  
  4.     private TimerTask mTask = null;   
  5.           
  6.     //TemplateMethod接口定义,具体动作有派生类时装。  
  7.     public void OnTimer(){  
  8.           
  9.     }  
  10.               
  11.     //启动定时器  
  12.     public void startTimer(long interval){  
  13.         mHandler = new Handler(){    
  14.              public void handleMessage(Message msg) {    
  15.                  OnTimer();  //调用模板方法。  
  16.                  super.handleMessage(msg);  
  17.              }  
  18.         };    
  19.         mTask = new TimerTask(){    
  20.             public void run() {    
  21.                  Message message = new Message();        
  22.                  message.what = 0;          //anything is ok.  
  23.                  mHandler.sendMessage(message);   
  24.              }    
  25.         };    
  26.         mTimer = new Timer();  
  27.         mTimer.schedule(mTask, 0, interval);  
  28.     }  
  29.       
  30.     //停止Timer动作  
  31.     //释放获得的资源。  
  32.     public void stopTimer(){  
  33.         mTimer.cancel();  
  34.         mTimer.purge();  
  35.         mTimer = null;  
  36.         mHandler = null;  
  37.         mTask = null;  
  38.     }  

有了这个类我们就可以相下面这样先定义一个派生类并提供OnTimer方法的实现。

  1. class MyTimer extends TemplateMethodTimer{  
  2.         public void OnTimer(){  
  3.             Log.i(TAG, "MyTimer.OnTimer");  
  4.         }  
  5.     } 

然后创建一个定时器并进行启动停止操作

  1. MyTimer mMt = new MyTimer(); 
  2. mMt.startTimer(500);
  3. mMt.stopTimer();

当然在JAVA中我们可以向下面这样创建Timer

  1. TemplateMethodTimer mTt = new TemplateMethodTimer(){  
  2.         public void OnTimer(){  
  3.             Log.i(TAG, "TestTimer.OnTimer");  
  4.         }  
  5.     }; 

本质上是一样的代码。

方法2:利用类的Observer设计模式,这时Timer类是这样的。

  1. public class ObserverTimer {  
  2.     private Timer mTimer = null;  
  3.     private Handler mHandler = null;  
  4.     private TimerTask mTask = null;   
  5.     private OnTimeListener mListener = null;  
  6.     private static final String TAG = new String("SafetyTimer");  
  7.       
  8.     //Observer接口定义  
  9.     public interface OnTimeListener{  
  10.         public void OnTimer();  
  11.     }  
  12.       
  13.     //创建定时器并指定Observer  
  14.     public void setListener(OnTimeListener listener){  
  15.         mListener = listener;  
  16.     }  
  17.       
  18.     //启动定时器  
  19.     public void startTimer(int interval){  
  20.         mHandler = new Handler(){    
  21.              public void handleMessage(Message msg) {    
  22.                  if(mListener != null){  
  23.                      mListener.OnTimer();  
  24.                      Log.i(TAG, "mListener.OnTimer()");  
  25.                  }  
  26.                  super.handleMessage(msg);  
  27.              }  
  28.         };    
  29.         mTask = new TimerTask(){    
  30.             public void run() {    
  31.                  Message message = new Message();        
  32.                  message.what = 0;          //anything is ok.  
  33.                  mHandler.sendMessage(message);   
  34.              }    
  35.         };    
  36.         mTimer = new Timer();  
  37.         mTimer.schedule(mTask, 0, interval);  
  38.     }  
  39.       
  40.     //停止Timer动作  
  41.     //释放获得的资源。  
  42.     public void stopTimer(){  
  43.         mTimer.cancel();  
  44.         mTimer.purge();  
  45.         mTimer = null;  
  46.         mHandler = null;  
  47.         mTask = null;  
  48.         Log.i(TAG, "stopTimer()");  
  49.     }  

这段代码与方法一的不同点在于。

1.没有定义供覆盖的方法但是定义了一个OnTimerListener类。
2.增加了OnTimerListener类型的数据成员mListener并提供设定它的接口。
3.在Handler的消息处理中没有调用自己的方法(也没有)而是调用设定好的mListener.OnTimer()
 
有了这个ObserverTimer类,我们就可以像下面这样创建和使用Timer了。
 
  1. ObserverTimer mOt = new ObserverTimer();  
  2. mOt.setListener(new ObserverTimer.OnTimeListener() {
       @Override
       public void OnTimer() {
        Log.i(TAG, "ObserverTimer.OnTimer");
       }
    });  
  3. mOt.startTimer(1000);  
  4. mOt.stopTimer(); 

是不是好多了。这样的代码在Android里到处都是,关键是我们自己做的代码会不会做成这样的。

用法好像区别不大,那么哪个个方法更好些呢?

方法1是定义了,一个不知道自己应该干什么的基类,然后通过派生类实现做某某事的Timer。抽象的是Timer。

方法2是定义的一个专门响应Timer的Listener基类,通过Listener的派生类实现具体的功能工作。抽象的要做的事,应该说更接近本 质吧。即使是从功利的角度来看也可以看出Listener是可以动态登录和删除,比较灵活。当然更不用说如果对Obersever稍加改造,可以实现多个 对象响应Timer事件了。

不言自明了吧。

通过本文,我们可以看到通过Observer设计模式封装,隐藏复杂的Timer处理的方法。这样下一个再用Timer的人,就不必再走一次别人已 经走过的路而把节约下来的时间用在其他需要挑战的地方。这样做其实没有什么难度,但是实际工作中会这么做的恐怕还真就不多。无论如何请相信:这看似不大的 一步,会从根本上改变我们的程序结构的。

在Android歌词秀(http://craftsman1970.blog.51cto.com/3522772/659482) 中用到的SaftyTimer类,就是用方法二实现的,供参考。

我们通过SaftyTimer封装了灰色的Timer,TimerTask,Handler的功能然后通过定义 SaftyTimer:OnTimeListener为利用者提供实现所需功能的途径。

 下面是时序图 

从图中可以很清楚的看到从LayerPlayerService出发的调用中除了生成新对象的2条线以外,只有 StartTimer,OnTimer,StopTimer三条线。而SaftyTimer右侧的调用则相对会复杂很多。这就是封装的效果。

以下是源代码

  1. package LyricPlayer.xwg;  
  2.  
  3. import java.util.Timer;  
  4. import java.util.TimerTask;  
  5.  
  6. import android.os.Handler;  
  7. import android.os.Message;  
  8. import android.util.Log;  
  9.  
  10. public class SafetyTimer {  
  11.     private Timer mTimer = null;  
  12.     private Handler mHandler = null;  
  13.     private TimerTask mTask = null;   
  14.     private OnTimeListener mListener = null;  
  15.     private long mInterval = 0; //in milliseconds  
  16.     private static final String TAG = new String("SafetyTimer");  
  17.       
  18.     //Observer接口定义  
  19.     public interface OnTimeListener{  
  20.         public void OnTimer();  
  21.     }  
  22.       
  23.     //创建定时器并指定Observer  
  24.     public SafetyTimer(long interval, OnTimeListener listener){  
  25.         mInterval = interval;  
  26.         mListener = listener;  
  27.     }  
  28.       
  29.     //启动定时器  
  30.     public void startTimer(){  
  31.         mHandler = new Handler(){    
  32.              public void handleMessage(Message msg) {    
  33.                  if(mListener != null){  
  34.                      mListener.OnTimer();  
  35.                      Log.i(TAG, "mListener.OnTimer()");  
  36.                  }  
  37.                  super.handleMessage(msg);  
  38.              }  
  39.         };    
  40.         mTask = new TimerTask(){    
  41.             public void run() {    
  42.                  Message message = new Message();        
  43.                  message.what = 0;          //anything is ok.  
  44.                  mHandler.sendMessage(message);   
  45.              }    
  46.         };    
  47.         mTimer = new Timer();  
  48.         mTimer.schedule(mTask, 0, mInterval);  
  49.     }  
  50.       
  51.     //停止Timer动作  
  52.     //释放获得的资源。  
  53.     public void stopTimer(){  
  54.         mTimer.cancel();  
  55.         mTimer.purge();  
  56.         mTimer = null;  
  57.         mHandler = null;  
  58.         mTask = null;  
  59.         Log.i(TAG, "stopTimer()");  
  60.     }  
  61.       
  62.     //Timer是否处于工作状态。  
  63.     public boolean isRunging(){  
  64.         return (mTimer != null);  
  65.     }  
  66. }  

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多