Android 消息队列
Android 消息队列
PriorityBlockingQueue(阻塞优先级队列)
、Comparable
首先看看要封装的队列需要有什么功能
在实际中,我们执行的任务大概可以分两种,一个是有
明确的执行时间的
,比如,要连续显示10个动画,每个展示5秒这种。一个是没明确的执行时间的
,比如连续上传10张图片,每个上传任务的完成时间是需要等到上传成功回调回来才知道的这种。所以队列第一个功能是每个任务都可以兼容这两种情况,而且当然是一个执行完再执行下一个,排队执行
既然要排队执行,当然会有优先级之分,所以每个任务都能设置优先级,队列可以根据优先级去排队执行任务
1. 定义一个枚举类TaskPriority,定义任务的优先级
// 优先级分为3种,如注释所示,他们的关系:LOW < DEFAULT < HIGH
public enum TaskPriority {LOW, //低DEFAULT,//普通HIGH, //高
}
2. 队列任务执行时间确定和不确定两种情况的实现策略
针对任务执行时间确定的这种情况,比较简单,可以给这个任务设置一个时间 duration,等任务开始执行时,便开始阻塞等待,等到时间到达时,才放开执行下一个任务
针对任务执行时间不确定的情况,我们则需要在任务执行完成的回调里面手动放开,所以这里打算再用一个PriorityBlockingQueue队列,因为它有这样的一个特点:如果队列是空的,调用它的 take()方法时,它就会一直阻塞在那里,当列表不为空时,这个方法就不会阻塞。 所以当任务开始执行时,调用take()方法,等到我们的完成回调来时,再手动给它add一个值,阻塞就放开,再执行下一个任务
3. 确定了任务两种情况的实现策略后,接下来定义一个接口,定义一下每个任务需要做什么事情
public interface ITask extends Comparable<ITask> {// 将该任务插入队列void enqueue();// 执行具体任务的方法void doTask();// 任务执行完成后的回调方法void finishTask();// 设置任务优先级ITask setPriority(TaskPriority mTaskPriority);// 获取任务优先级TaskPriority getPriority();// 当优先级相同 按照插入顺序 先入先出 该方法用来标记插入顺序void setSequence(int mSequence);// 获取入队次序int getSequence();// 每个任务的状态,就是标记完成和未完成boolean getStatus();// 设置每个任务的执行时间,该方法用于任务执行时间确定的情况ITask setDuration(int duration);// 获取每个任务执行的时间int getDuration();// 阻塞任务执行,该方法用于任务执行时间不确定的情况void blockTask() throws Exception;// 解除阻塞任务,该方法用于任务执行时间不确定的情况void unLockBlock();
}
4. 封装一下PriorityBlockingQueue的基本功能
public class BlockTaskQueue {private String TAG = "BlockTaskQueue";private AtomicInteger mAtomicInteger = new AtomicInteger();//阻塞队列private final BlockingQueue<ITask> mTaskQueue = new PriorityBlockingQueue<>();private BlockTaskQueue() {}//单例模式private static class BlockTaskQueueHolder {private final static BlockTaskQueue INSTANCE = new BlockTaskQueue();}public static BlockTaskQueue getInstance() {return BlockTaskQueueHolder.INSTANCE;}/*** 插入时 因为每一个Task都实现了comparable接口 所以队列会按照Task复写的compare()方法定义的优先级次序进行插入* 当优先级相同时,使用AtomicInteger原子类自增 来为每一个task 设置sequence,* sequence的作用是标记两个相同优先级的任务入队的次序*/public <T extends ITask> int add(T task) {if (!mTaskQueue.contains(task)) {task.setSequence(mAtomicInteger.incrementAndGet());mTaskQueue.add(task);Log.d(TAG, "\n add task " + task.toString());}return mTaskQueue.size();}public <T extends ITask> void remove(T task) {if (mTaskQueue.contains(task)) {Log.d(TAG, "\n" + "task has been finished. remove it from task queue");mTaskQueue.remove(task);}if (mTaskQueue.size() == 0) {mAtomicInteger.set(0);}}public ITask poll() {return mTaskQueue.poll();}public ITask take() throws InterruptedException {return mTaskQueue.take();}public void clear() {mTaskQueue.clear();}public int size() {return mTaskQueue.size();}
}
5. 写一个类记录下当前执行的任务信息,方便获取时使用
public class CurrentRunningTask {private static ITask sCurrentShowingTask;public static void setCurrentShowingTask(ITask task) {sCurrentShowingTask = task;}public static void removeCurrentShowingTask() {sCurrentShowingTask = null;}public static ITask getCurrentShowingTask() {return sCurrentShowingTask;}public static boolean getCurrentShowingStatus() {return sCurrentShowingTask != null && sCurrentShowingTask.getStatus();}
}
6. 封装一个基础的任务类
public class BaseTask implements ITask {private final String TAG = getClass().getSimpleName();private TaskPriority mTaskPriority = TaskPriority.DEFAULT; //默认优先级private int mSequence;// 入队次序private Boolean mTaskStatus = false; // 标志任务状态,是否仍在展示protected WeakReference<BlockTaskQueue> taskQueue;//阻塞队列protected int duration = 0; //任务执行时间//此队列用来实现任务时间不确定的队列阻塞功能private PriorityBlockingQueue<Integer> blockQueue;//构造函数public BaseTask() {taskQueue = new WeakReference<>(BlockTaskQueue.getInstance());blockQueue = new PriorityBlockingQueue<>();}//入队实现@Overridepublic void enqueue() {TaskScheduler.getInstance().enqueue(this);}//执行任务方法,此时标记为设为true,并且将当前任务记录下来@Overridepublic void doTask() {mTaskStatus = true;CurrentRunningTask.setCurrentShowingTask(this);}//任务执行完成,改变标记位,将任务在队列中移除,并且把记录清除@Overridepublic void finishTask() {this.mTaskStatus = false;this.taskQueue.get().remove(this);CurrentRunningTask.removeCurrentShowingTask();Log.d(TAG, taskQueue.get().size() + "");}//设置任务优先级实现@Overridepublic ITask setPriority(TaskPriority mTaskPriority) {this.mTaskPriority = mTaskPriority;return this;}//设置任务执行时间public ITask setDuration(int duration) {this.duration = duration;return this;}//获取任务优先级@Overridepublic TaskPriority getPriority() {return mTaskPriority;}//获取任务执行时间@Overridepublic int getDuration() {return duration;}//设置任务次序@Overridepublic void setSequence(int mSequence) {this.mSequence = mSequence;}//获取任务次序@Overridepublic int getSequence() {return mSequence;}// 获取任务状态@Overridepublic boolean getStatus() {return mTaskStatus;}//阻塞任务执行@Overridepublic void blockTask() throws Exception {blockQueue.take(); //如果队列里面没数据,就会一直阻塞}//解除阻塞@Overridepublic void unLockBlock() {blockQueue.add(1); //往里面随便添加一个数据,阻塞就会解除}/*** 排队实现* 优先级的标准如下:* TaskPriority.LOW < TaskPriority.DEFAULT < TaskPriority.HIGH* 当优先级相同 按照插入次序排队*/@Overridepublic int compareTo(ITask another) {final TaskPriority me = this.getPriority();final TaskPriority it = another.getPriority();return me == it ? this.getSequence() - another.getSequence() :it.ordinal() - me.ordinal();}//输出一些信息@Overridepublic String toString() {return "task name : " + getClass().getSimpleName() + " sequence : " + mSequence + " TaskPriority : " + mTaskPriority;}
}
7. TaskScheduler
public class TaskScheduler {private final String TAG = "TaskScheduler";private BlockTaskQueue mTaskQueue = BlockTaskQueue.getInstance();private ShowTaskExecutor mExecutor;private static class ShowDurationHolder {private final static TaskScheduler INSTANCE = new TaskScheduler();}private TaskScheduler() {initExecutor();}private void initExecutor() {mExecutor = new ShowTaskExecutor(mTaskQueue);mExecutor.start();}public static TaskScheduler getInstance() {return ShowDurationHolder.INSTANCE;}public void enqueue(ITask task) {//因为TaskScheduler这里写成单例,如果isRunning改成false的话,不判断一下,就会一直都是falseif (!mExecutor.isRunning()) {mExecutor.startRunning();}//按照优先级插入队列 依次播放mTaskQueue.add(task);}public void resetExecutor() {mExecutor.resetExecutor();}public void clearExecutor() {mExecutor.clearExecutor();}
}
8. 管理任务队列:ShowTaskExecutor
public class ShowTaskExecutor {private final String TAG = "ShowTaskExecutor";private BlockTaskQueue taskQueue;private TaskHandler mTaskHandler;private boolean isRunning = true;private static final int MSG_EVENT_DO = 0;private static final int MSG_EVENT_FINISH = 1;public ShowTaskExecutor(BlockTaskQueue taskQueue) {this.taskQueue = taskQueue;mTaskHandler = new TaskHandler();}//开始遍历任务队列public void start() {AsyncTask.THREAD_POOL_EXECUTOR.execute(new Runnable() {@Overridepublic void run() {try {while (isRunning) { //死循环ITask iTask;iTask = taskQueue.take(); //取任务if (iTask != null) {//执行任务TaskEvent doEvent = new TaskEvent();doEvent.setTask(iTask);doEvent.setEventType(TaskEvent.EventType.DO);mTaskHandler.obtainMessage(MSG_EVENT_DO, doEvent).sendToTarget();//一直阻塞,直到任务执行完if (iTask.getDuration()!=0) {TimeUnit.MILLISECONDS.sleep(iTask.getDuration());}else {iTask.blockTask();}//完成任务TaskEvent finishEvent = new TaskEvent();finishEvent.setTask(iTask);finishEvent.setEventType(TaskEvent.EventType.FINISH);mTaskHandler.obtainMessage(MSG_EVENT_FINISH, finishEvent).sendToTarget();}}} catch (Exception ex) {ex.printStackTrace();}}});}//根据不同的消息回调不同的方法。private static class TaskHandler extends Handler {TaskHandler() {super(Looper.getMainLooper());}@Overridepublic void handleMessage(Message msg) {super.handleMessage(msg);TaskEvent taskEvent = (TaskEvent) msg.obj;if (msg.what == MSG_EVENT_DO && taskEvent.getEventType() == TaskEvent.EventType.DO) {taskEvent.getTask().doTask();}if (msg.what == MSG_EVENT_FINISH && taskEvent.getEventType() == TaskEvent.EventType.FINISH) {taskEvent.getTask().finishTask();}}}public void startRunning() {isRunning = true;}public void pauseRunning() {isRunning = false;}public boolean isRunning() {return isRunning;}public void resetExecutor() {isRunning = true;taskQueue.clear();}public void clearExecutor() {pauseRunning();taskQueue.clear();}
}
9. TaskEvent
public class TaskEvent {private WeakReference<ITask> mTask;int mEventType;public ITask getTask() {return mTask.get();}public void setTask(ITask mTask) {this.mTask = new WeakReference<>(mTask);}public int getEventType() {return mEventType;}public void setEventType(int mEventType) {this.mEventType = mEventType;}public static class EventType {public static final int DO = 0X00;public static final int FINISH = 0X01;}
}
10.使用方法
定义一个Task,继承 BaseTask,并实现对应的方法
public class LogTask extends BaseTask {String name;public LogTask(String name) {this.name = name;}//执行任务方法,在这里实现你的任务具体内容@Overridepublic void doTask() {super.doTask();Log.i("LogTask", "--doTask-" + name);//如果这个Task的执行时间是不确定的,比如上传图片,那么在上传成功后需要手动调用//unLockBlock方法解除阻塞,例如:uploadImage(new UploadListener{public void onSuccess() {unLockBlock();}});}private void uploadImage(UploadListener uploadListener) {try {// long seconds = getDuration();long seconds = (long) (Math.random() * 10000);Log.i("LogTask", "uploadImage milliseconds " + seconds);Thread.sleep(seconds);} catch (Exception e) {e.printStackTrace();}uploadListener.onSuccess();}//任务执行完的回调,在这里你可以做些释放资源或者埋点之类的操作@Overridepublic void finishTask() {super.finishTask();Log.i("LogTask", "--finishTask-" + name);}
}public interface UploadListener {void onSuccess();
}
然后依次入队使用
findViewById(R.id.add).setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {new LogTask("任务2")
// .setDuration(4000) // 设置了时间,代表这个任务时间是确定的,如果不确定,则不用设置.setPriority(TaskPriority.DEFAULT) // 设置优先级,默认是DEFAULT.enqueue(); // 入队new Handler().postDelayed(new Runnable() {@Overridepublic void run() {new LogTask("任务4")
// .setDuration(4000) // 设置了时间,代表这个任务时间是确定的,如果不确定,则不用设置.setPriority(TaskPriority.LOW) // 设置优先级,默认是DEFAULT.enqueue(); // 入队new LogTask("任务1")
// .setDuration(6000) // 设置了时间,代表这个任务时间是确定的,如果不确定,则不用设置.setPriority(TaskPriority.LOW) // 设置优先级,默认是DEFAULT.enqueue(); // 入队new LogTask("任务3")
// .setDuration(2000) // 设置了时间,代表这个任务时间是确定的,如果不确定,则不用设置.setPriority(TaskPriority.HIGH) // 设置优先级,默认是DEFAULT.enqueue(); // 入队}},1000);}});
参考
- 封装一个阻塞队列,轻松实现排队执行任务功能!
- 谈谈LinkedBlockingQueue
- BlockingQueue深入解析-BlockingQueue看这一篇就够了
Android 消息队列相关推荐
- android消息队列模型,Android 消息队列机制
在非UI线程使用Handler进行线程通信时,一般都需要进行3个步骤: 创建Looper Looper.prepar() 创建Handler 启动消息循环Looper.loop() 通过这3步,基本就 ...
- Android进阶知识树——Android消息队列
1.概述 在安卓程序启动时,会默认在主线程中 运行程序,那如果执行一些耗时的操作则UI就会处于阻塞状态,出现界面卡顿的现象,再者用户的多种操作,系统是如何做到一一处理的,系统又是如何管理这些任务的,答 ...
- Android消息队列图片记录
很早之前为了给学生讲明白整个消息队列是怎么个情况,于是大概阅读了一下消息队列的整个工作过程,鉴于网上大部分都是文字说明,没有一个图例,于是做出了下面这张图,权当作以后复习之用,也供大家学习参考,有什么 ...
- android的消息队列机制
android下的线程,Looper线程,MessageQueue,Handler,Message等之间的关系,以及Message的send/post及Message dispatch的过程. Loo ...
- Android Handler消息队列的实现原理
我们在写Android程序的时候,有经常用到Handler来与子线程通信,亦或者是用其来管理程序运行的状态时序.Handler其是由Android提供的一套完善的操作消息队列的API.它既可以运行在主 ...
- 【Android 异步操作】HandlerThread 示例 ( 初始化并执行 | 获取Looper | 获取 Handler | 获取消息队列 | 设置空闲队列 | 代码示例 )
文章目录 一.HandlerThread 初始化 二.HandlerThread 获取Looper 三.HandlerThread 获取消息队列 MessageQueue 四.HandlerThrea ...
- 【Android 异步操作】Handler 机制 ( MessageQueue 消息队列的阻塞机制 | Java 层机制 | native 层阻塞机制 | native 层解除阻塞机制 )
文章目录 一.MessageQueue 的 Java 层机制 二.MessageQueue 的 native 层阻塞机制 三.MessageQueue 的 native 层解除阻塞机制 三.Messa ...
- 【Android 异步操作】Handler 机制 ( Android 提供的 Handler 源码解析 | Handler 构造与消息分发 | MessageQueue 消息队列相关方法 )
文章目录 一.Handler 构造函数 二.Handler 消息分发 三.MessageQueue 消息队列相关函数 一.Handler 构造函数 一般使用 Handler 时 , 调用 Handle ...
- 【Android 异步操作】手写 Handler ( Message 消息 | ThreadLocal 线程本地变量 | Looper 中的消息队列 MessageQueue )
文章目录 一.Message 消息 二.ThreadLocal 线程本地变量 三.Looper 中的消息队列 MessageQueue 一.Message 消息 模仿 Android 中的 Messa ...
最新文章
- linux文件操作函数程序,linux 文件操作函数
- PHP memcache实现消息队列实例
- 培养你的核心竞争能力
- FFmpeg使用基础
- unity中实现简单对象池,附教程原理
- 聊聊微服务架构及分布式事务解决方案
- MySQL 精选 60 道面试题(含答案)
- php 交换函数,php用于反转/交换数组中的键名和对应关联的键值的函数array_flip()...
- P102、面试题14:调整数组顺序使奇数位于偶数前面
- oo第一次博客-三次表达式求导的总结与反思
- Ubuntu之查看依赖软件
- bzoj 2243: [SDOI2011]染色 线段树区间合并+树链剖分
- 计算机科学与技术的研究背景,计算机科学与技术发展背景
- 瑞尔IPO:一桩资本逼宫的上市计划
- 运维自动化工具Cobbler之——安装实践
- java排序算法(一)冒泡排序
- 短期python培训机构
- 行列式的计算方法总结:
- Chrome浏览器调试iOS手机H5页面
- java计算机毕业设计个人阅读习惯个性化推荐系统研究源码+mysql数据库+系统+lw文档+部署