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;
-
-
- 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;
- mHandler.sendMessage(message);
- }
- };
- mTimer = new Timer();
- mTimer.schedule(mTask, 0, interval);
- }
-
-
-
- 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");
-
-
- public interface OnTimeListener{
- public void OnTimer();
- }
-
-
- 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;
- mHandler.sendMessage(message);
- }
- };
- mTimer = new Timer();
- mTimer.schedule(mTask, 0, interval);
- }
-
-
-
- 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歌词秀(http://craftsman1970.blog.51cto.com/3522772/659482)
中用到的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;
- private static final String TAG = new String("SafetyTimer");
-
-
- public interface OnTimeListener{
- public void OnTimer();
- }
-
-
- 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;
- mHandler.sendMessage(message);
- }
- };
- mTimer = new Timer();
- mTimer.schedule(mTask, 0, mInterval);
- }
-
-
-
- public void stopTimer(){
- mTimer.cancel();
- mTimer.purge();
- mTimer = null;
- mHandler = null;
- mTask = null;
- Log.i(TAG, "stopTimer()");
- }
-
-
- public boolean isRunging(){
- return (mTimer != null);
- }
- }
|