Handler机制,是Android系统的消息队列,一样平常用于处理惩罚主线程的页面绘制等消息处理惩罚。
媒介
Handler除了Java层外,另有Native的部门,但我本领有限,只能仿写一个Java层的Handler,而且支持延时消息。项目地点:MiniHandler
注:由于消息机制须要利用一个while死循环来让线程不能结束,以是直接将MiniHandler在Android主线程中利用会卡住主线程,以是须要用一个子线程来运行MiniHandler,一样平常利用HandlerThread,对应到MiniHandler的MiniHandlerThread
简单先容
- 延时消息功能:利用DelayQueue实现,它须要队列中的消息实体实现一个Delayed接口,它继承于Comparable接口,它要求复写一个getDelay()方法,返回延时多长毫秒。以及须要复写compareTo()方法,用于比力2个消息谁先谁后,来决定队列中的消息排序。
类结构先容
- Looper,轮训器,内部包罗一个MessageQueue消息队列,而且利用ThreadLocal将每个线程绑定一个Looper。以是一个线程只有一个Looper,一个Looper也只有一个MessageQueue消息队列
- MessageQueue,消息队列,利用DelayQueue实现队列功能,支持延时消息
- Message,消息实体类,利用享元模式支持消息对象复用
- MiniHandler,消息处理惩罚器以及消息发送器
- MiniHandlerThread,原自Android源码中的HandlerThread,改用MiniHandler实现,就是一个带有Handler事件循环的子线程
原理
- Handler,发送Message消息到MessageQueue,会被Looper轮训器取出
- Looper轮训器中,有一个while循环,不停从MessageQueue消息队列中取出消息举行处理惩罚,如果队列中没有消息,MessageQueue会壅闭当火线程
- Handler处理惩罚完消息,Message消息回收到池中,复用消息能提高服从,以及淘汰对象创建
根本利用
MiniHandler的API和Handler的划一,2者的Java层API只是类名差异。
/** * Toast任务 */public static final int ACTION_TOAST = 1;/** * 延时任务 */public static final int ACTION_DELAY = 2;////事件处理惩罚线程MiniHandlerThread handlerThread = new MiniHandlerThread("handler-thread");handlerThread.start();//创建MiniHandler实例,并绑定到MiniHandlerThreadMiniHandler eventHandler = new MiniHandler(mHandlerThread.getLooper()) { @Override public void handleMessage(Message message) { super.handleMessage(message); long action = message.what; if (action == ACTION_TOAST) { String msg = message.obj.toString(); ToastUtil.toast(getApplicationContext(), msg); } else if (action == ACTION_DELAY) { String delayMsg = message.obj.toString(); ToastUtil.toast(getApplicationContext(), delayMsg); } }};//发消息到立即实行事件线程eventHandler.sendMessage(Message.obtain(ACTION_TOAST, "Toast~"));//大概eventHandler.post(new Runnable() { @Override public void run() { ToastUtil.toast(getApplicationContext(), 延时消息~); }});//发送延时消息到事件线程eventHandler.sendMessageDelayed(Message.obtain(ACTION_DELAY, "延时消息~"), 2000);//大概eventHandler.postDelayed(new Runnable() { @Override public void run() { ToastUtil.toast(getApplicationContext(), 延时消息~); }}, 1000);//退出MiniHnadlerThreadhandlerThread.quitSafely();源码
Message消息实体
消息实体类,利用享元模式支持消息对象复用。为了支持延时消息,消息实体,须要实现一个Delayed接口,它继承于Comparable接口,它要求复写一个getDelay()方法,返回延时多长毫秒。以及须要复写compareTo()方法,用于比力2个消息谁先谁后,来决定队列中的消息排序。
/** * 消息事件实体 */public class Message implements Delayed { /** * 利用中的标记位 */ static final int FLAG_IN_USE = 1; int flags; /** * 为了形成消息链表 */ Message next; /** * 对象锁 */ public static final Object sPoolSync = new Object(); /** * 消息链表的头节点 */ private static Message sPool; /** * 当前链表中数据的个数 */ private static int sPoolSize = 0; /** * 统共可利用的消息链表巨细 */ private static final int MAX_POOL_SIZE = 50; /** * 消息的标识 */ public long what; /** * 消息的附件 */ public Object obj; /** * 消息的处理惩罚器 */ public MiniHandler target; /** * 要实行的任务,可为null */ public Runnable callback; /** * 指定的实行时间,毫秒值 */ public long workTimeMillis; /** * 回收Message */ void recycleUnchecked() { //把标记设置为利用中 flags = FLAG_IN_USE; //清算全部字段 what = 0; obj = null; target = null; callback = null; workTimeMillis = 0; synchronized (sPoolSync) { if (sPoolSize < MAX_POOL_SIZE) { next = sPool; sPool = this; sPoolSize++; } } } /** * 创建一个Message对象 */ public static Message obtain() { synchronized (sPoolSync) { //判定头节点是否null if (sPool != null) { //取出头节点 Message m = sPool; //将头节点的下一个作为最新的头节点 sPool = m.next; //设置须要返回的消息的next为空 m.next = null; //打扫利用中的标记位 m.flags = 0; sPoolSize--; return m; } } //如果消息链表为空 创建新的message return new Message(); } /** * 创建一个Message对象,并绑定处理惩罚它的Handler */ public static Message obtain(MiniHandler handler) { return obtain(handler, 0); } /** * 创建一个Message对象,并绑定处理惩罚它的Handler、消息标识what */ public static Message obtain(MiniHandler handler, long what) { return obtain(handler, what, null); } /** * 创建一个Message对象,绑定消息标识what */ public static Message obtain(long what) { return obtain(what, null); } /** * 创建一个Message对象,绑定消息标识what、消息附件obj */ public static Message obtain(long what, Object obj) { return obtain(null, what, obj); } /** * 创建一个Message对象,并绑定处理惩罚它的Handler、消息标识what、消息附件obj */ public static Message obtain(MiniHandler handler, long what, Object obj) { Message message = obtain(); message.target = handler; message.what = what; message.obj = obj; return message; } @Override public long getDelay(TimeUnit unit) { return unit.convert(workTimeMillis - System.currentTimeMillis(), TimeUnit.MILLISECONDS); } @Override public int compareTo(Delayed o) { return (int) (this.getDelay(TimeUnit.MILLISECONDS) - o.getDelay(TimeUnit.MILLISECONDS)); }}MessageQueue消息队列
消息队列,利用DelayQueue实现队列功能,支持延时消息
public class MessageQueue { /** * 是否退出 */ volatile boolean isQuit; /** * 消息队列 */ private final BlockingQueue<Message> mMessageQueue = new DelayQueue<>(); /** * 消息入队 */ public boolean enqueueMessage(Message message, long uptimeMillis) { try { message.workTimeMillis = uptimeMillis; mMessageQueue.put(message); return true; } catch (InterruptedException e) { e.printStackTrace(); } return false; } /** * 拿出一条消息 */ public Message next() { try { //如果队列中没有消息,就会壅闭在这里 return mMessageQueue.take(); } catch (InterruptedException e) { e.printStackTrace(); } return null; } /** * 移除队列中指定Handler的未实行的回调和消息 */ public final void removeCallbacksAndMessages(MiniHandler handler) { if (handler == null) { return; } List<Message> targetMessages = new ArrayList<>(); for (Message message : mMessageQueue) { if (message.target == handler) { targetMessages.add(message); } } mMessageQueue.removeAll(targetMessages); } public void quit() { mMessageQueue.clear(); isQuit = true; }}Looper轮训器
轮训器,内部包罗一个MessageQueue消息队列,而且利用ThreadLocal将每个线程绑定一个Looper。以是一个线程只有一个Looper,一个Looper也只有一个MessageQueue消息队列
public class Looper { private static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<>(); /** * 消息队列 */ final MessageQueue mMessageQueue; private Looper() { //一个线程,只有一个Looper,一个Looper也只有一个消息队列 mMessageQueue = new MessageQueue(); } /** * 把当火线程和Looper举行绑定 */ public static void prepare() { Looper looper = sThreadLocal.get(); if (looper != null) { throw new RuntimeException("一个线程只能绑定一个Looper,请确保prepare方法在一个线程中只调用一次"); } sThreadLocal.set(new Looper()); } /** * 获取当火线程的Looper */ public static Looper myLooper() { return sThreadLocal.get(); } /** * 开始循环从队列中取出消息 */ public static void loop() { //获取当火线程的轮询器 Looper looper = myLooper(); MessageQueue queue = looper.mMessageQueue; while (!queue.isQuit) { Message message = queue.next(); try { message.target.dispatchMessage(message); } finally { //回收Message对象 message.recycleUnchecked(); } } } /** * 安全退出,会等全部事件都实行完,再关闭 */ public void quitSafely() { mMessageQueue.quit(); }}MiniHandler消息处理惩罚器
消息处理惩罚器以及消息发送器
public class MiniHandler { /** * 消息队列 */ private final MessageQueue mMessageQueue; /** * 事件回调,可以选择构造时传入一个Callback,就可以不须要复写handleMessage()方法举行处理惩罚 */ private MiniHandler.Callback mCallback; public MiniHandler() { this(Looper.myLooper()); } public MiniHandler(Callback callback) { Looper looper = Looper.myLooper(); //Looper没有绑定 if (looper == null) { throw new RuntimeException( "Can't create handler inside thread " + Thread.currentThread() + " that has not called Looper.prepare()"); } mMessageQueue = looper.mMessageQueue; mCallback = callback; } public MiniHandler(Looper looper) { //Looper没有绑定 if (looper == null) { throw new RuntimeException( "Can't create handler inside thread " + Thread.currentThread() + " that has not called Looper.prepare()"); } mMessageQueue = looper.mMessageQueue; } public interface Callback { /** * @param msg A {@link android.os.Message Message} object * @return True if no further handling is desired */ boolean handleMessage(Message msg); } /** * 移除队列中指定Handler的未实行的回调和消息 */ public final void removeCallbacksAndMessages() { mMessageQueue.removeCallbacksAndMessages(this); } /** * 发送消息到消息队列中 */ public boolean sendMessage(Message message) { return sendMessageDelayed(message, 0); } /** * 在主线程实行一个Runnable */ public final boolean post(Runnable task) { return sendMessageDelayed(getPostMessage(task), 0); } /** * 延伸一段时间后,在主线程实行一个Runnable * * @param delayMillis 延时时间,毫秒值 */ public final boolean postDelayed(Runnable task, long delayMillis) { return sendMessageDelayed(getPostMessage(task), delayMillis); } /** * 获取一个带Runnable任务的Message */ private static Message getPostMessage(Runnable task) { Message m = Message.obtain(); m.callback = task; return m; } /** * 发送延时消息 * * @param message 消息 * @param delayMillis 延时时间 */ public final boolean sendMessageDelayed(Message message, long delayMillis) { if (delayMillis < 0) { delayMillis = 0; } return sendMessageAtTime(message, System.currentTimeMillis() + delayMillis); } public boolean sendMessageAtTime(Message message, long uptimeMillis) { MessageQueue queue = this.mMessageQueue; if (queue == null) { RuntimeException e = new RuntimeException( this + " sendMessageAtTime() called with no mQueue"); Log.w("Looper", e.getMessage(), e); return false; } return enqueueMessage(queue, message, uptimeMillis); } private boolean enqueueMessage(MessageQueue queue, Message message, long uptimeMillis) { message.target = this; return queue.enqueueMessage(message, uptimeMillis); } /** * 分发消息给Handler举行处理惩罚 */ void dispatchMessage(Message message) { //如果是post()或postDelayed()发出的任务,则实行这个任务 if (message.callback != null) { handleCallback(message); } else { //如果在Handler构造时传入了Callback,则回调这个Callback if (mCallback != null) { if (mCallback.handleMessage(message)) { return; } } //都没有,则调用handleMessage(),Handler的子类可以复写该方法举行事件处理惩罚 handleMessage(message); } } /** * 实行Message绑定的任务 */ private static void handleCallback(Message message) { message.callback.run(); } /** * 子类重写该方法举行处理惩罚消息 */ public void handleMessage(Message message) { }}MiniHandlerThread
原自Android源码中的HandlerThread,改用MiniHandler实现,就是一个带有Handler事件循环的子线程
/** * A {@link Thread} that has a {@link Looper}. * The {@link Looper} can then be used to create {@link MiniHandler}s. * <p> * Note that just like with a regular {@link Thread}, {@link #start()} must still be called. */public class MiniHandlerThread extends Thread { int mPriority; int mTid = -1; Looper mLooper; private MiniHandler mHandler; public MiniHandlerThread(String name) { super(name); mPriority = Process.THREAD_PRIORITY_DEFAULT; } /** * Constructs a HandlerThread. * * @param name * @param priority The priority to run the thread at. The value supplied must be from * {@link android.os.Process} and not from java.lang.Thread. */ public MiniHandlerThread(String name, int priority) { super(name); mPriority = priority; } /** * Call back method that can be explicitly overridden if needed to execute some * setup before Looper loops. */ protected void onLooperPrepared() { } @Override public void run() { mTid = Process.myTid(); Looper.prepare(); synchronized (this) { mLooper = Looper.myLooper(); notifyAll(); } Process.setThreadPriority(mPriority); onLooperPrepared(); Looper.loop(); mTid = -1; } /** * This method returns the Looper associated with this thread. If this thread not been started * or for any reason isAlive() returns false, this method will return null. If this thread * has been started, this method will block until the looper has been initialized. * * @return The looper. */ public Looper getLooper() { if (!isAlive()) { return null; } // If the thread has been started, wait until the looper has been created. synchronized (this) { while (isAlive() && mLooper == null) { try { wait(); } catch (InterruptedException e) { } } } return mLooper; } /** * @return a shared {@link MiniHandler} associated with this thread * @hide */ public MiniHandler getThreadHandler() { if (mHandler == null) { mHandler = new MiniHandler(getLooper()); } return mHandler; } /** * Quits the handler thread's looper safely. * <p> * Causes the handler thread's looper to terminate as soon as all remaining messages * in the message queue that are already due to be delivered have been handled. * Pending delayed messages with due times in the future will not be delivered. * </p><p> * Any attempt to post messages to the queue after the looper is asked to quit will fail. * For example, the {@link MiniHandler#sendMessage(Message)} method will return false. * </p><p> * If the thread has not been started or has finished (that is if * {@link #getLooper} returns null), then false is returned. * Otherwise the looper is asked to quit and true is returned. * </p> * * @return True if the looper looper has been asked to quit or false if the * thread had not yet started running. */ public boolean quitSafely() { Looper looper = getLooper(); if (looper != null) { looper.quitSafely(); return true; } return false; } /** * Returns the identifier of this thread. See Process.myTid(). */ public int getThreadId() { return mTid; }} |