前言:本来打算先写android启动流程分析的,但是在里面看到Looper.loop(),就看了一遍Handler的源码,之前比较晦涩的地方,现在一下就看明白,因此就想记录一下,方便以后查阅。
众所周知,我们在子线程更新UI之前需要切换到主线程(因为View绘制之前会检查线程),常规操作如下
thread {
//切换线程
_handler.obtainMessage().sendToTarget()
}.start()
private val _handler = @SuppressLint("HandlerLeak")
object : Handler() {
override fun handleMessage(msg: Message?) {
super.handleMessage(msg)
}
}
非常规操作:
thread {
Looper.prepare()
//ui operate
Looper.loop()
}.start()
其实道理都是一样的,都是先创建一个Looper对象,然后在Looper对象里面进行操作,所以,今天主要分析要落在Looper.loop()身上了
Handler构造
fun Handler(callback: Callback?, async: Boolean): ??? {
if (FIND_POTENTIAL_LEAKS) {
val klass = javaClass
if ((klass.isAnonymousClass || klass.isMemberClass || klass.isLocalClass) && klass.modifiers and Modifier.STATIC == 0) {
Log.w(TAG, "The following Handler class should be static or leaks might occur: " + klass.canonicalName)
}
}
//这里创建Looper对象
mLooper = Looper.myLooper()
if (mLooper == null) {
throw RuntimeException(
"Can't create handler inside thread that has not called Looper.prepare()")
}
mQueue = mLooper.mQueue
mCallback = callback
mAsynchronous = async
}
Looper.prepare()
private fun prepare(quitAllowed: Boolean) {
if (sThreadLocal.get() != null) {
throw RuntimeException("Only one Looper may be created per thread")
}
sThreadLocal.set(Looper(quitAllowed))
}
loop()主要代码如下
fun loop() {
//me = sThreadLocal.get(),可以看到是从prepare里面去取初始化的Looper
val me = myLooper()
?: throw RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.")
//获取消息队列,所有的msg循环都是在消息队列里面完成的,通过msg.next进行传递
val queue = me!!.mQueue
while (true) {
//取一条消息
val msg = queue.next()
?:
return
val slowDispatchThresholdMs = me!!.mSlowDispatchThresholdMs
//这句代码是不是很熟悉了,我们在新建handler的时候,重写的最多的代码就是这一句了
//target其实就是一个msg内部的Handler
msg.target.dispatchMessage(msg)
msg.recycleUnchecked()
}
}
while里面是个无限循环,主要代码还是在queue.next()这上面
Message next() {
final long ptr = mPtr;
if (ptr == 0) {
return null;
}
int pendingIdleHandlerCount = -1; // -1 only during first iteration
int nextPollTimeoutMillis = 0;
for (;;) {
if (nextPollTimeoutMillis != 0) {
Binder.flushPendingCommands();
}
nativePollOnce(ptr, nextPollTimeoutMillis);
synchronized (this) {
// Try to retrieve the next message. Return if found.
final long now = SystemClock.uptimeMillis();
Message prevMsg = null;
Message msg = mMessages;
if (msg != null && msg.target == null) {
//遍历,查找队列中的下一个异步消息
do {
prevMsg = msg;
msg = msg.next;
} while (msg != null && !msg.isAsynchronous());
}
if (msg != null) {
if (now < msg.when) {
//下一条消息尚未就绪。设置超时以在准备就绪时唤醒。
nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE);
} else {
mBlocked = false;
//这里就是做消息循环的关键代码了
if (prevMsg != null) {
prevMsg.next = msg.next;
} else {
mMessages = msg.next;
}
msg.next = null;
msg.markInUse();
return msg;
}
} else {
// 没有消息的时候就做如下设置
nextPollTimeoutMillis = -1;
}
}
}
至此,源码已经看完了,透过源码能够知道他内部执行是有个无限循环,而dispatchMessage不是根据Message的添加顺序,而是根据他的Message.when来判断是否执行当前的Message,Message设计其实是一个链表的结构,通过next不断的读取,其他应该没有什么难点了。。。
end
网友评论