核心类方法浅析
Handler:
sendMessage/post:将消息发送到消息队列中
dispatchMessage:将消息分发给对应Handler
handleMessage:依据消息进行相关处理/操作
MessageQueue:
enqueueMessage:将消息依据时间放入消息队列(入队)
next:从消息队列取出消息(出队)
Looper:
prepare:创建一个循环器+消息队列实例
loop:消息循环(即从消息队列取出消息并发给Handler)
源码分析
依旧采用由使用步骤深入分析
Handler.sendMessage()
①创建Handler对象:
实际调用:
public Handler() {
this(null, false);
}
public Handler(Callback callback, boolean async) {
mLooper = Looper.myLooper();
if (mLooper == null) {
throw new RuntimeException(
"Can't create handler inside thread that has not called Looper.prepare()");
}
mQueue = mLooper.mQueue;
}
创建Handler对象的过程也就是将Handler绑定至循环器+消息队列的过程:通过myLooper获取当前线程的循环器对象并赋值绑定、由循环器获得消息队列进行赋值绑定。
此处发现用来绑定的循环器和消息队列并没有在构造方法中创建,那么这两个实例是何时生成的?
注:①之前的隐式操作:循环器+消息队列实例生成、消息循环开始
上述描述中循环器通过Looper.prepare进行生成,而该方法在安卓应用启动时即被调用生成:
publicstatic void main(String[] args) {
...
Looper.prepareMainLooper();
ActivityThread thread = new ActivityThread();
// 创建主线程
Looper.loop();
// 自动开启 消息循环
}
通过主线程调用prepareMainLooper创建应用的主线程循环器
public static final void prepare() {
if (sThreadLocal.get() != null) {
throw new RuntimeException("Only one Looper may be created per thread");
}
sThreadLocal.set(new Looper(true));
}
prepare方法首先进行是否重复调用判断(ThreadLocal是否已存在)
然后再生成该线程的循环器并设置进去
private Looper(boolean quitAllowed) {
mQueue = new MessageQueue(quitAllowed);
mRun = true;
mThread = Thread.currentThread();
}
循环器构造方法中会生成对应的消息队列,并将当前线程与其绑定起来
上述分析了主线程循环器的创建+子线程由手动创建循环器发生的一系列操作
在循环器+消息队列创建成功后,消息的循环loop()随即开始:
public static void loop() {
...
final Looper me = myLooper();
if (me == null) {
throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
}
final MessageQueue queue = me.mQueue;
for (;;) {
Message msg = queue.next();
if (msg == null) {
return;
}
msg.target.dispatchMessage(msg);
msg.recycle();
}
}
消息循环开启:首先通过相关循环器获取消息队列,遍历消息将每个消息发送至其对应Handler,发送完成后回收资源
消息遍历过程next():
Message next() {
...
// 该参数用于确定消息队列中是否还有消息
// 从而决定消息队列应处于出队消息状态 or 等待状态
int nextPollTimeoutMillis = 0;
for (;;) {
if (nextPollTimeoutMillis != 0) {
Binder.flushPendingCommands();
}
// nativePollOnce方法在native层,若是nextPollTimeoutMillis为-1,此时消息队列处于等待状态
nativePollOnce(ptr, nextPollTimeoutMillis);
synchronized (this) {
final long now = SystemClock.uptimeMillis();
Message prevMsg = null;
Message msg = mMessages;
// 出队消息,即 从消息队列中取出消息:按创建Message对象的时间顺序
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;
if (DEBUG) Log.v(TAG, "Returning message: " + msg);
msg.markInUse();
return msg;
}
} else {
// 若 消息队列中已无消息,则将nextPollTimeoutMillis参数设为-1
// 下次循环时,消息队列则处于等待状态
nextPollTimeoutMillis = -1;
}
......
}
.....
}
}
loop会进行消息循环取出操作(无限for循环),包含:①通过nextPollTimeoutMillis控制下一个消息出队时间及循环等待状态 ②有消息时进行消息出队相关操作
消息分发过程dispatchMessage(msg):
public void dispatchMessage(Message msg) {
if (msg.callback != null) {
handleCallback(msg);
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
}
}
通过msg内容是否包含callBack判断执行哪种通信方式(sendMessage/post):sendMessage:调用handleMessage;post:调用handleCallBack(即调用传入的run())
所以第一步整体执行的操作:
隐式:①主线程自动生成循环器+消息队列(子线程手动生成)
②开启消息循环(loop()),循环将消息出队并分发给对应Handler
显示:创建Handler实例(与对应循环器+消息队列绑定)
②创建消息对象
Message msg = Message.obtain(); // 实例化消息对象
msg.what = 1; // 消息标识
msg.obj = "AA"; // 消息内容存放
源码分析:
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();
}
obtain实际是从消息池中取出可用消息对象进行复用(若池子用完则创建新实例使用)
③发送信息sendMessage
public final boolean sendMessage(Message msg)
{
return sendMessageDelayed(msg, 0);
}
发送信息实际调用sendMessageDelayed,逐层向下分析
public final boolean sendMessageDelayed(Message msg, long delayMillis)
{
if (delayMillis < 0) {
delayMillis = 0;
}
return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
}
public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
MessageQueue queue = mQueue;
return enqueueMessage(queue, msg, uptimeMillis);
}
上述获取消息队列,用于准备将消息放入队列
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
msg.target = this;
return queue.enqueueMessage(msg, uptimeMillis);
}
该步将对应Handler记录到msg中,以便分发时调用,然后再消息入队
boolean enqueueMessage(Message msg, long when) {
...
synchronized (this) {
msg.markInUse();
msg.when = when;
Message p = mMessages;
boolean needWake;
// 判断消息队列里有无消息
// a. 若无,则将当前插入的消息 作为队头 & 若此时消息队列处于等待状态,则唤醒
if (p == null || when == 0 || when < p.when) {
msg.next = p;
mMessages = msg;
needWake = mBlocked;
} else {
needWake = mBlocked && p.target == null && msg.isAsynchronous();
Message prev;
// b. 判断消息队列里有消息,则根据 消息(Message)创建的时间 插入到队列中
for (;;) {
prev = p;
p = p.next;
if (p == null || when < p.when) {
break;
}
if (needWake && p.isAsynchronous()) {
needWake = false;
}
}
msg.next = p;
prev.next = msg;
}
if (needWake) {
nativeWake(mPtr);
}
}
return true;
}
放入队列操作:判断当前队列是否有消息(相当于判断循环状态)①有消息:依据时间节点插入合适位置 ②没有消息:当前消息作为头部放入,并判断是否需要唤醒
上述一系列信息发送操作实质:
将消息与其目标Handler绑定起来,再依据消息时间放入消息队列等待循环出队
至此,sendMessage流程即分析完毕,上述黑体字就是整个流程的关键操作
Handler.post()
①主线程创建handler实例
此步骤同上述sendMessage方法,进行隐式处理、绑定等动作
②工作线程发送信息
mHandler.post(new Runnable() {
@Override
public void run() {
... // 需执行的UI操作
}
});
post方法的处理,逐层深入:
public final boolean post(Runnable r)
{
return sendMessageDelayed(getPostMessage(r), 0);
}
private static Message getPostMessage(Runnable r) {
Message m = Message.obtain();
m.callback = r;
return m;
}
public final boolean sendMessageDelayed(Message msg, long delayMillis)
{
if (delayMillis < 0) {
delayMillis = 0;
}
return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
}
从sendMessageDelayed开始就与sendMessage()相同了
上述操作就是将post传入的runnable实例封装成一个message,再进行消息发送等任务,剩余就和发送消息处理完全相同。
循环中消息处理:
public static void loop() {
...
final Looper me = myLooper();
if (me == null) {
throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
}
final MessageQueue queue = me.mQueue;
for (;;) {
Message msg = queue.next();
if (msg == null) {
return;
}
msg.target.dispatchMessage(msg);
msg.recycle();
}
}
public void dispatchMessage(Message msg) {
if (msg.callback != null) {
handleCallback(msg);
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
}
}
在dispatchMessage中,因为之前封装消息时,将run赋值给了callBack,所以此处处理情况与sendMessage不同,触发handleCallback
private static void handleCallback(Message message) {
message.callback.run();
}
该方法就直接调用先前runnable实例中实现的run方法
至此post实现过程分析完毕,与sendMessage实际只多了封装消息步骤与run方法调用