Android中使用Timer时需要同时访问TimerTask,Handle等类,手续繁杂而且是真正想做的事淹没在手续化的代码中。本文介绍了的SafetyTimer类隐藏了TimerTask,Handle等类,并通过Observer设计模式为用户提供简单,低耦合的实现方式。
首先看一下SafetyTimer在整个软件中的位置。
有点偏,不过没有关系。
让我们开始。
关于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的时候,就已经是和应用在同一个上下文里了。
看起来挺累的吧,要找到我们真正想做的事还真是不容易。但是又不得不看。有没有办法把这件事弄的漂亮一点呢,有。
方法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()");
- }
- }
这段代码与方法一的不同点在于。
- 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歌词秀(http://craftsman1970.blog.51cto.com/3522772/659482)中用到的SaftyTimer类,就是用方法二实现的,供参考。
我们通过SaftyTimer封装了灰色的Timer,TimerTask,Handler的功能然后通过定义SaftyTimer:OnTimeListener为利用者提供实现所需功能的途径。
下面是时序图
从图中可以很清楚的看到从LayerPlayerService出发的调用中除了生成新对象的2条线以外,只有StartTimer,OnTimer,StopTimer三条线。而SaftyTimer右侧的调用则相对会复杂很多。这就是封装的效果。
以下是源代码,整个工程文件源码下载:http://down.51cto.com/data/249418
本文出自: http://craftsman1970.blog.51cto.com/3522772/659906
- 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);
- }
- }