包括以下内容:
- Handler:发送及处理消息
- Looper:分发消息
- MessageQueue :存储消息
- Message:消息实体 戳这里看详情
扩展应用: - HandlerThread: 封装好消息机制的线程 戳这里看详情
- IntentService:开启子线程处理事务的service
- ThreadLocal:线程本地变量的管理类
- LocalBroadcastReceiver:内部用handler来管理 戳这里看详情
一. 背景
1.1 使用场景
跨线程发送消息,一般是子线程向主线程发送消息
1.2 为什么要使用
安卓的线程机制:只有主线程才可以更改ui
二.关系图
uml
三. 流程解析
用一个简单的使用handler发送消息的流程来解析下:
我们使用handler其实主要分三步:
- 新建一个handler
- 发送消息
- 处理消息
下面从这三部分来解析
1.初始化 handler
// 构造函数入参: handler需要同一个looper绑定,默认为当前线程所在looper
callback: 回调,处理消息时会用到
private Handler mhandler = new Handler(looper,callback){
@Override
public void handleMessage(Message msg) {
}
};
在这里,需要关心的是参数 Looper; 用户可指定一个looper,或者不填;
不填的情况下是怎么处理的呢:
- 获取Looper
在Handler源码中,当构造函数中未指定looper对象时,会调用:
mLooper = Looper.myLooper();
继续查看Looper:
/**
* Return the Looper object associated with the current thread. Returns
* null if the calling thread is not associated with a Looper.
*/
public static @Nullable Looper myLooper() {
return sThreadLocal.get();
}
意思是: 会返回当前线程一一绑定的looper,如果未曾绑定过则返回null;
那么 怎么绑定呢,在什么时机去绑定呢?
这得分2种情况:主线程的looper和子线程的looper
- 主线程的looper
这个无需我们过多考虑(想想,我们要在主线程新建一个对应的handler,都是使用无参的构造函数对吧),其实这是因为应用启动时系统帮我们做好了:
public static void main(String[] args) {
Looper.prepareMainLooper();
.....
ActivityThread thread = new ActivityThread();
.....
Looper.loop();
}
/**
* Initialize the current thread as a looper, marking it as an
* application's main looper. The main looper for your application
* is created by the Android environment, so you should never need
* to call this function yourself. See also: {@link #prepare()}
*/
public static void prepareMainLooper() {
prepare(false);
synchronized (Looper.class) {
if (sMainLooper != null) {
throw new IllegalStateException("The main Looper has already been prepared.");
}
sMainLooper = myLooper();
}
}
4.子线程的looper
子线程的需要我们来 自己绑定,答案就在Looper的类解释文案上:
* <p>This is a typical example of the implementation of a Looper thread,
* using the separation of {@link #prepare} and {@link #loop} to create an
* initial Handler to communicate with the Looper.
*
* <pre>
* class LooperThread extends Thread {
* public Handler mHandler;
*
* public void run() {
* Looper.prepare();
*
* mHandler = new Handler() {
* public void handleMessage(Message msg) {
* // process incoming messages here
* }
* };
*
* Looper.loop();
* }
* }
可见关键在于 Looper.prepare()
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));
}
继续查看Looper的构造函数
private Looper(boolean quitAllowed) {
mQueue = new MessageQueue(quitAllowed);
mThread = Thread.currentThread();
}
可见,在Looper.prepare()里做了两件事:
给当前线程新建并绑定了一个looper
生成一个消息队列
那么looper.loop()做了什么呢?
/**
* Run the message queue in this thread. Be sure to call
* {@link #quit()} to end the loop.
*/
public static void loop() {
//这里告诉我们获取某个线程的looper接口: myLooper(); 这个很有用
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;
// Make sure the identity of this thread is that of the local process,
// and keep track of what that identity token actually is.
Binder.clearCallingIdentity();
final long ident = Binder.clearCallingIdentity();
//从消息队列中取消息,会堵塞
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);
} finally {
}
............
}
}
初始化的流程暂告一段落,现在我们明白了 初始化handler时需要同一个looper绑定,并开启looper的循环;
- handler 发送一个消息
可以通过sendMessage() 或者post()来发送消息,这二者其实都最后调用了:
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);
}
继续看enqueueMessage()
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
//设置消息的处理对象,后续分发时有用
msg.target = this;
if (mAsynchronous) {
msg.setAsynchronous(true);
}
// 加入消息队列中
return queue.enqueueMessage(msg, uptimeMillis);
}
然后再看看 消息队列是怎么入列一个消息的:
boolean enqueueMessage(Message msg, long when) {
if (msg.target == null) {
throw new IllegalArgumentException("Message must have a target.");
}
if (msg.isInUse()) {
throw new IllegalStateException(msg + " This message is already in use.");
}
synchronized (this) {
if (mQuitting) {
IllegalStateException e = new IllegalStateException(
msg.target + " sending message to a Handler on a dead thread");
Log.w(TAG, e.getMessage(), e);
msg.recycle();
return false;
}
msg.markInUse();
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;
}
有点长,大概可以概括为: 以单链表的形式插入消息;
那么接下来系统做什么了呢?消息去哪了? 别急,想想之前的Looper.loop()
我们把消息扔到某个消息队列,而消息队列是looper里创建的,一一对应,而handler又是和某个looper绑定的,这里的关键就是~~~Looper
想想Looper.looper()里的for循环吧:
//从消息队列中取消息,会堵塞
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);
} finally {
}
}
这里会取消息队列里的消息并分发
其中: msg.target 就是消息的处理器,即某个handler,那么分发就得看
public void dispatchMessage(Message msg) {
if (msg.callback != null) {
handleCallback(msg);
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
}
}
细节就不说了,终于看到熟悉的handleMessage了,也就是说,我们发送的消息终于绕了一圈,又回到了我们的handleMessage了;
好,收工!(如果感觉很多细节都很模糊,都没涉及到,这是正常滴,因为我都没讲~~~; )
下面补充下总的流程图:
流程图.png
补充下 looper 和 handler,MessageQueue的对应图:
一个线程只可有一个looper,一个looper可同时绑定多个handler,但一个handler只可绑定一个looper;
一个looper里初始化一个消息队列,每个消息队列有多个消息,每个消息根据targer可找到对应的handler。
对应图
网友评论