内容简介: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事件机制 - 源码概览(上)
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。