关于Android的异步操作,我在文章《Android开发实践:线程与异步任务》中介绍了两种方法,一种是采用线程,另一种是采用AsyncTask,今天再深入探讨下另一种模型:命令式的异步任务管理。


一般而言,单一的异步操作,比如从指定的网址下载一个图片采用线程或者AsyncTask是很方便的;如果异步任务是需要循环处理,比如定时更新某个UI控件,那么,可以通过定时器或者线程+Sleep循环来实现。那么,还有这么一种需求,需要你通过命令来与你的异步线程进行交互,比如你要远程操作一台设备,可以执行:打开、获取参数、设置参数、发送命令、关闭等等,这样的需求下,你的确可以通过对每一个命令开启一个线程的方式来实现,然而还有更好地方法么?


针对这种需求,我们来一起设计了一个基于命令模式的异步任务线程,在该线程启动后,在你没有发送命令的情况下,休眠等待;你可以连续向该线程发送一系列的命令,该线程会唤醒,并依次执行你所发送的命令,并在需要的情况下回调通知命令的发生者。


1. 命令模式


根据需求,我们可以知道,这样的设计采用命令模式最好不过了,所谓命令模式,就是将一个请求或者操作封装到一个对象中,命令的管理者不需要知道每个命令的具体参数和执行方法,只需要通过队列将命令对象缓冲起来,并在需要的时候依次调用命令对象的执行接口即可。


在这里,我们的任务就可以抽象为命令模式中的“命令”,首先设计任务的接口:


public interface Tasker {                                                                                                                                                                                                                                                                                                                       public void execute();}


2. 任务的定义


根据命令模式的定义,每个任务都可以设计为一个类,实现该Tasker的接口,作为示例,我实现了Tasker接口的对象的两个简单的任务类:


(1)“空任务”类,啥都不做


public class EmptyTasker implements Tasker {    @Override    public void execute() {                                                                                                                                                                                                                                                                                    }}


(2)“延时任务”类,负责在指定的延时之后执行任务


public class DelayTasker implements Tasker {                                                                                                                                                                                                                                                                            private final long mDelayTime;    private final TimeArrivedListener mListener;                                                                                                                                                                                                                                                                             //回调函数,通知外界延时时间到    public interface TimeArrivedListener {        public void onDelayTimeArrived();    }                                                                                                                                                                                                                                                                             //通过构造函数传递所需的参数    public DelayTasker( long delayTime, TimeArrivedListener listener){                                                                                                                                                                                                                                                                                     mDelayTime = delayTime;        mListener  = listener;    }                                                                                                                                                                                                                                                                             @Override    public void execute() {                                                                                                                                                                                                                                                                                     try {                     Thread.sleep(mDelayTime);            mListener.onDelayTimeArrived();               }        catch (InterruptedException e) {                      e.printStackTrace();                  }    }}

3. 任务管理者


任务管理者负责管理任务队列,实现任务的执行,同时向使用者提供可访问的接口,主要包括如下实现:


(1) 任务执行线程

负责从任务队列取任务对象,并且调用任务的执行函数执行任务代码。


(2) 任务队列

以先进先出的形式管理任务队列,并且要注意多线程的读写安全。


(3) 调用接口

一般包括:初始化(开启任务线程)、逆初始化(关闭任务线程)、添加命令


我设计的任务管理者代码如下,你可以根据自己的需求添加/修改/删除接口或者实现细节。


public class TaskExecutor {                                                                                                                                                     //控制线程执行/退出的标志变量    private volatile boolean mIsRunning = true;                                                                                                                                                        //锁和条件变量    private Lock mLock = new ReentrantLock();    private Condition mCondition = mLock.newCondition();                                                                                                                                                        //任务列表    private Queue<Tasker> mTaskerQueue = new LinkedList<Tasker>();                                                                                                                                                        //初始化函数,开启任务等待线程    public void initilize() {        new Thread(new WorkRunnable()).start();    }                                                                                                                                                        //销毁函数,关闭任务等待线程    public void destroy() {                                                                                                                                                                //线程退出命令        mIsRunning = false;                                                                                                                                                                //添加一个任务,唤醒mCondition.await        addTasker(new EmptyTasker());         }                                                                                                                                                        //添加一个新任务    public void addTasker( Tasker tasker ) {                                                                                                                                                                mLock.lock();        mTaskerQueue.add(tasker);        mCondition.signal();        mLock.unlock();    }                                                                                                                                                        //获取下一个任务,如果任务列表为空,则阻塞    private Tasker getNextTasker() {                                                                                                                                                                mLock.lock();        try {                                                                                                                                                                        //如果任务队列为空,则阻塞等待            while( mTaskerQueue.isEmpty() ) {                             mCondition.await();            }                                                                                                                                                                        //返回队列首任务,并从队列删除掉            return mTaskerQueue.poll();               }        catch (InterruptedException e) {            e.printStackTrace();                  }        finally {            mLock.unlock();        }                                                                                                                                                                     return null;    }                                                                                                                                                        //任务等待/执行线程    private class WorkRunnable implements Runnable {                                                                                                                                                       @Override        public void run() {                                                                                                                                                                        while(mIsRunning) {                           Tasker tasker = getNextTasker();                tasker.execute();                                                             }                                                                                                                                                                        Log.d("TaskExecutor", "WorkRunnable run exit ! ");        }                                                                                                                                                            }}


4. 使用案例


这里,我简单地应用上述异步任务线程完成了一个app示例,该app只有一个Button,每点击一次就延时1s弹出一个Toast消息,当你连续点击Button的时候,就会从1往后不断加1,连续的显示。


该app的MainActivity代码如下:


public class MainActivity extends Activity implements TimeArrivedListener {                                                                                 private TaskExecutor mTaskExecutor;    private int mClickTimes = 0;                                                             @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);                                                                 mTaskExecutor = new TaskExecutor();        mTaskExecutor.initilize();    }                                                             @Override    protected void onDestroy() {        mTaskExecutor.destroy();        super.onDestroy();    }                                                             public void onClickDelay(View v) {                                                                     //每点击一次按钮,则延时1s,弹出消息提示        mTaskExecutor.addTasker(new DelayTasker(1000, this));         }                                                          @Override    public void onDelayTimeArrived() {                                                               mClickTimes++;                                                                     this.runOnUiThread(new Runnable() {                   @Override            public void run() {                Toast.makeText(MainActivity.this,"This is the " + mClickTimes + " times click" , Toast.LENGTH_SHORT).show();                          }        });       }}


基于命令模式的异步任务线程就探讨到这里了,在你的Android工程中可以很容易地移植TaskExecutor类,本工程的项目代码见博文后面的附件,有任何疑问欢迎留言或者来信[email protected]交流,一起探讨和完善这种异步任务线程。


更多相关文章

  1. 学习Android线程模型解析(包括UI的更新)
  2. Android Studio——为什么说android UI操作不是线程安全的
  3. Android中Handler的使用方法——在子线程中更新界面
  4. android 使用asynctask结合fragment更新UI(另附线程池管理示例)
  5. Android常用命令集锦
  6. Android中Handler的线程间通讯原理
  7. android UI 单线程模型
  8. Android官方的文档中提到了模拟器中设置代理服务器的方法,即在命

随机推荐

  1. android 开发中判断网络是否连接的代码
  2. 很好的资源学习入口_android
  3. android系统学习笔记二
  4. xml-----属性收集
  5. Android-TCPDump for Android(抓TCP数据包
  6. Android(安卓)Android.mk 文件一点感悟
  7. Android中AIDL详解
  8. Android的布局管理器与java中的实现方式
  9. Android(安卓)OpenCV 人脸识别 Opencv3.1
  10. android的文件读写