内容简介:Handler 是Android SDK中用来处理异步消息的核心类,子线程可以通过handler来通知主线程进行ui更新。备注:本文源码截图 基于Android sdk 28Handler机制 消息发送主要流程如图
Handler 是Android SDK中用来处理异步消息的核心类,子线程可以通过handler来通知主线程进行ui更新。
备注:本文源码截图 基于Android sdk 28
Handler机制 消息发送主要流程如图
一、创建消息
推荐使用Message.obtain()方法 获取一个新消息,优势在于 Message 内部使用链表维护的一个大小为50的消息池,消息池会回收之前使用过的消息, 提高性能。
/** * Return a new Message instance from the global pool. Allows us to * avoid allocating new objects in many cases. */ public static Message obtain() { synchronized (sPoolSync) { if (sPool != null) { Message m = sPool; sPool = m.next; m.next = null; m.flags = 0; // clear in-use flag sPoolSize--; return m; } } return new Message(); } 复制代码
/** * Recycles a Message that may be in-use. * Used internally by the MessageQueue and Looper when disposing of queued Messages. */ void recycleUnchecked() { // Mark the message as in use while it remains in the recycled object pool. // Clear out all other details. .....//省略初始化相关代码 synchronized (sPoolSync) { if (sPoolSize < MAX_POOL_SIZE) { next = sPool; sPool = this; sPoolSize++; } } } 复制代码
Message使用what属性来区分消息类型, 使用如下另外字段来传递简单数据, 当然也可以使用Bundle来传递任意类型数据
public int what; public int arg1; public int arg2; public Object obj; /** * Sets a Bundle of arbitrary data values. Use arg1 and arg2 members * as a lower cost way to send a few simple integer values, if you can. * @see #getData() * @see #peekData() */ public void setData(Bundle data) { this.data = data; } 复制代码
二、Handler发送消息
使用Handler发送消息有两类方法,使用post系列方法, 或 sendMessage系列方法, 但最终发送消息的逻辑在sendMessageAtTime()方法中。
public final boolean post(Runnable r){ return sendMessageDelayed(getPostMessage(r), 0); } 复制代码
参数uptimeMillis 表示消息 被处理的时间点,是个绝对时间。
public boolean sendMessageAtTime(Message msg, long uptimeMillis) { MessageQueue queue = mQueue; if (queue == null) { RuntimeException e = new RuntimeException( this + " sendMessageAtTime() called with no mQueue"); Log.w("Looper", e.getMessage(), e); return false; } return enqueueMessage(queue, msg, uptimeMillis); } private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) { msg.target = this; if (mAsynchronous) { msg.setAsynchronous(true); } return queue.enqueueMessage(msg, uptimeMillis); } 复制代码
三、待处理消息的消息队列
Handler发送消息后, 将MessageQueue将待处理消息添加到消息队列中。该消息队列使用单向链表来实现,根据消息执行的绝对时间 来对单向链表排序,when值越小,即最先被执行的消息,放在表头。
boolean enqueueMessage(Message msg, long when) { ···· synchronized (this) { msg.when = when; Message p = mMessages; boolean needWake; if (p == null || when == 0 || when < p.when) { // New head, wake up the event queue if blocked. msg.next = p; mMessages = msg; needWake = mBlocked; } else { // Inserted within the middle of the queue. Usually we don't have to wake // up the event queue unless there is a barrier at the head of the queue // and the message is the earliest asynchronous message in the queue. needWake = mBlocked && p.target == null && msg.isAsynchronous(); Message prev; for (;;) { prev = p; p = p.next; if (p == null || when < p.when) { break; } if (needWake && p.isAsynchronous()) { needWake = false; } } msg.next = p; // invariant: p == prev.next prev.next = msg; } // We can assume mPtr != 0 because mQuitting is false. if (needWake) { nativeWake(mPtr); } } return true; } 复制代码
四,Loop循环
应用程序启动后,首先执行 ActivityThread 中的main函数, 开始Looper.loop()循环,
public static void main(String[] args) { ...... Looper.prepareMainLooper(); ...... Looper.loop(); throw new RuntimeException("Main thread loop unexpectedly exited"); } 复制代码
loop()循环 是一个死循环, 不停地从MessageQueue.next()方法 中取出消息处理, MessageQueue.next()是个阻塞的方法, 当没有所有消息都取出后,该方法会阻塞线程。
public static void loop() { final Looper me = myLooper(); final MessageQueue queue = me.mQueue; for (;;) { Message msg = queue.next(); // might block if (msg == null) { // No message indicates that the message queue is quitting. return; } try { msg.target.dispatchMessage(msg); dispatchEnd = needEndTime ? SystemClock.uptimeMillis() : 0; } finally { if (traceTag != 0) { Trace.traceEnd(traceTag); } } msg.recycleUnchecked(); ...... } 复制代码
msg.target 即为发送消息的Handler,最后消息会传到该handler中处理。
/** * Handle system messages here. */ public void dispatchMessage(Message msg) { if (msg.callback != null) { handleCallback(msg); } else { if (mCallback != null) { if (mCallback.handleMessage(msg)) { return; } } handleMessage(msg); } } 复制代码
#####五,ThreadLocal 在子线程中使用创建 Handler时,运行时会有如下错误,原因在于当前线程 没有绑定Looper对象
"No Looper; Looper.prepare() wasn't called on this thread." 复制代码
在主线程启动,在main函数中首先会调用Looper.prepare()方法,创建一个Looper对象,并将该对象与当前线程 通过ThreadLocal 绑定。
private static void prepare(boolean quitAllowed) { if (sThreadLocal.get() != null) { throw new RuntimeException("Only one Looper may be created per thread"); } sThreadLocal.set(new Looper(quitAllowed)); } 复制代码
从Thread源码中,可以看到,每个线程有一个 ThreadLocal.ThreadLocalMap,并且该map由ThreadLocal维护
/* ThreadLocal values pertaining to this thread. This map is maintained * by the ThreadLocal class. */ ThreadLocal.ThreadLocalMap threadLocals = null; 复制代码
ThreadLocal 使用自身为key,向该map中保存数据。
/** * Returns the value in the current thread's copy of this * thread-local variable. If the variable has no value for the * current thread, it is first initialized to the value returned * by an invocation of the {@link #initialValue} method. * * @return the current thread's value of this thread-local */ public T get() { Thread t = Thread.currentThread(); ThreadLocalMap map = getMap(t); if (map != null) { ThreadLocalMap.Entry e = map.getEntry(this); if (e != null) { @SuppressWarnings("unchecked") T result = (T)e.value; return result; } } return setInitialValue(); } /** * Sets the current thread's copy of this thread-local variable * to the specified value. Most subclasses will have no need to * override this method, relying solely on the {@link #initialValue} * method to set the values of thread-locals. * * @param value the value to be stored in the current thread's copy of * this thread-local. */ public void set(T value) { Thread t = Thread.currentThread(); ThreadLocalMap map = getMap(t); if (map != null) map.set(this, value); else createMap(t, value); } 复制代码
Looper中,维护一个static类型的ThreadLocal 变量, 并通过调用prepare() 方法,将looper()对象绑定到当前线程中,
// sThreadLocal.get() will return null unless you've called prepare(). static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>(); 复制代码
完~ (如果错误或不足,望指出, 大家共同进步)
以上所述就是小编给大家介绍的《Handler机制源码分析》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!
猜你喜欢:- Timer机制源码浅析
- View事件机制源码分析
- Checkpoint对齐机制源码分析
- SpringBoot事件监听机制源码分析(上) SpringBoot源码(九)
- vue源码解读-component机制
- React事件机制 - 源码概览(上)
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
鸟哥的Linux私房菜
鸟哥 / 人民邮电出版社 / 2010-6-28 / 88.00元
本书是最具知名度的Linux入门书《鸟哥的Linux私房菜基础学习篇》的最新版,全面而详细地介绍了Linux操作系统。全书分为5个部分:第一部分着重说明Linux的起源及功能,如何规划和安装Linux主机;第二部分介绍Linux的文件系统、文件、目录与磁盘的管理;第三部分介绍文字模式接口 shell和管理系统的好帮手shell脚本,另外还介绍了文字编辑器vi和vim的使用方法;第四部分介绍了对于系......一起来看看 《鸟哥的Linux私房菜》 这本书的介绍吧!