Android中使用Timer时需要同时访问TimerTask,Handle等类,手续繁杂而且是真正想做的事淹没在手续化的代码中。本文介绍了的SafetyTimer类隐藏了TimerTask,Handle等类,并通过Observer设计模式为用户提供简单,低耦合的实现方式。
首先看一下SafetyTimer在整个软件中的位置。
有点偏,不过没有关系。
让我们开始。
关于Android定时器的使用,网上有很多例子。一般来讲是这样的。
publicclassTestTimerextends Activity {
Timer timer =newTimer();
Handler handler =newHandler(){
publicvoidhandleMessage(Message msg) {
switch(msg.what) {
case1:
setTitle("hear me?");//这里才是要做的事情。
break;
}
super.handleMessage(msg);
}
};
TimerTask task =newTimerTask(){
publicvoidrun() {
Message message =newMessage();
message.what =1;
handler.sendMessage(message);
}
};
publicvoidonCreate(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的时候,就已经是和应用在同一个上下文里了。
以下是参考资料
看起来挺累的吧,要找到我们真正想做的事还真是不容易。但是又不得不看。有没有办法把这件事弄的漂亮一点呢,有。
方法1:利用类的继承
首先写一个如下的基类,基本上例子中的代码相同,只是在定义了一个没有内容的OnTimer方法留给派生类实现。
publicclassTemplateMethodTimer {
privateTimer mTimer =null;
privateHandler mHandler =null;
privateTimerTask mTask =null;
//TemplateMethod接口定义,具体动作有派生类时装。
publicvoidOnTimer(){
}
//启动定时器
publicvoidstartTimer(longinterval){
mHandler =newHandler(){
publicvoidhandleMessage(Message msg) {
OnTimer();//调用模板方法。
super.handleMessage(msg);
}
};
mTask =newTimerTask(){
publicvoidrun() {
Message message =newMessage();
message.what =0;//anything is ok.
mHandler.sendMessage(message);
}
};
mTimer =newTimer();
mTimer.schedule(mTask,0, interval);
}
//停止Timer动作
//释放获得的资源。
publicvoidstopTimer(){
mTimer.cancel();
mTimer.purge();
mTimer =null;
mHandler =null;
mTask =null;
}
}
有了这个类我们就可以相下面这样先定义一个派生类并提供OnTimer方法的实现。
classMyTimerextendsTemplateMethodTimer{
publicvoidOnTimer(){
Log.i(TAG,"MyTimer.OnTimer");
}
}
然后创建一个定时器并进行启动停止操作
MyTimer mMt =newMyTimer();
mMt.startTimer(500);
mMt.stopTimer();
当然在JAVA中我们可以向下面这样创建Timer
TemplateMethodTimer mTt =newTemplateMethodTimer(){
publicvoidOnTimer(){
Log.i(TAG,"TestTimer.OnTimer");
}
};
本质上是一样的代码。
方法2:利用类的Observer设计模式,这时Timer类是这样的。
publicclassObserverTimer {
privateTimer mTimer =null;
privateHandler mHandler =null;
privateTimerTask mTask =null;
privateOnTimeListener mListener =null;
privatestaticfinalString TAG =newString("SafetyTimer");
//Observer接口定义
publicinterfaceOnTimeListener{
publicvoidOnTimer();
}
//创建定时器并指定Observer
publicvoidsetListener(OnTimeListener listener){
mListener = listener;
}
//启动定时器
publicvoidstartTimer(intinterval){
mHandler =newHandler(){
publicvoidhandleMessage(Message msg) {
if(mListener !=null){
mListener.OnTimer();
Log.i(TAG,"mListener.OnTimer()");
}
super.handleMessage(msg);
}
};
mTask =newTimerTask(){
publicvoidrun() {
Message message =newMessage();
message.what =0;//anything is ok.
mHandler.sendMessage(message);
}
};
mTimer =newTimer();
mTimer.schedule(mTask,0, interval);
}
//停止Timer动作
//释放获得的资源。
publicvoidstopTimer(){
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 =newObserverTimer();
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的人,就不必再走一次别人已经走过的路而把节约下来的时间用在其他需要挑战的地方。这样做其实没有什么难度,但是实际工作中会这么做的恐怕还真就不多。无论如何请相信:这看似不大的一步,会从根本上改变我们的程序结构的。
我们通过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;
publicclassSafetyTimer {
privateTimer mTimer = null;
privateHandler mHandler = null;
privateTimerTask mTask = null;
privateOnTimeListener mListener = null;
privatelongmInterval = 0;//in milliseconds
privatestaticfinal String TAG =newString("SafetyTimer");
//Observer接口定义
publicinterface OnTimeListener{
publicvoidOnTimer();
}
//创建定时器并指定Observer
publicSafetyTimer(longinterval, OnTimeListener listener){
mInterval = interval;
mListener = listener;
}
//启动定时器
publicvoidstartTimer(){
mHandler =newHandler(){
publicvoidhandleMessage(Message msg) {
if(mListener != null){
mListener.OnTimer();
Log.i(TAG,"mListener.OnTimer()");
}
super.handleMessage(msg);
}
};
mTask =newTimerTask(){
publicvoidrun() {
Message message =newMessage();
message.what = 0;//anything is ok.
mHandler.sendMessage(message);
}
};
mTimer =newTimer();
mTimer.schedule(mTask, 0, mInterval);
}
//停止Timer动作
//释放获得的资源。
publicvoidstopTimer(){
mTimer.cancel();
mTimer.purge();
mTimer = null;
mHandler = null;
mTask = null;
Log.i(TAG,"stopTimer()");
}
//Timer是否处于工作状态。
publicboolean isRunging(){
return(mTimer != null);
}
}
资源链接: