Android 消息队列
生活随笔
收集整理的這篇文章主要介紹了
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);}});參考
總結
以上是生活随笔為你收集整理的Android 消息队列的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 如何做好rebuttal
- 下一篇: Oracle Demo库默认用户/密码为