在Android的线程通信机制模型可以套用工厂的生产线模型;
Handler:工人
Looper:机床
Message: 产品
MessageQueue: 传送带
模型图:
模型图中我们可以看见,Handler把一个一个的Message不断的post到MessageQueue中,通过Looper把Message不断的循环读取,然后再通过dispatchMessage分发至Handler的handlerMessage的回调方法中,通过这种机制,Android系统就可以源源不断的处理各种消息。
概念清楚之后从上而下分析原理就清楚得多了。
Handler
我们使用Handler一般是
Handler mHandler = new Handler(Looper.getMainLooper());
private void handlerTest(){
new Thread(new Runnable() {
@Override
public void run() {
//耗时操作
mHandler.post(new Runnable() {
@Override
public void run() {
//UI线程 更新UI
}
});
}
}).start();
}
或者这样:
Handler mHandler1 = new Handler(){
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case 1:
String s = msg.obj.toString();
//UI线程
break;
}
super.handleMessage(msg);
}
};
private void handlerTest1(){
new Thread(new Runnable() {
@Override
public void run() {
Message m = Message.obtain();
m.what = 1;
m.obj = "test";
mHandler1.sendMessage(m);
}
}).start();
}
其实无论是post还是通过sendMessage最终都会调用至
sendMessageAtTime 而post是对sendMessage的一次封装,为了便捷我们使用。
来看 mHandler.post
public final boolean post(Runnable r){
return sendMessageDelayed(getPostMessage(r), 0);
}
这里只是进行了一次包装来看看getPostMessage()
private static Message getPostMessage(Runnable r, Object token) {
Message m = Message.obtain();
m.obj = token;
m.callback = r;
return m;
}
其实到这一步大家就和很清楚,我们自己sendMessage其实也就是这些玩意,下面我放完代码片段。
public final boolean sendMessageDelayed(Message msg, long delayMillis)
{
if (delayMillis < 0) {
delayMillis = 0;
}
return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
}
mHandler1.sendMessage
public final boolean sendMessage(Message msg){
return sendMessageDelayed(msg, 0);
}
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;
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);
}
最终是调用enqueueMessage把消息添加到MessageQueue里(后面会解释是如何添加的);
那么Handler是如何接收消息的呢?
Handler mHandler1 = new Handler(){
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case 1:
String s = msg.obj.toString();
//UI线程
break;
}
super.handleMessage(msg);
}
};
在我们使用的时候是通过handleMessage方法回调获取到发送出去的信息;在Handler有个dispatchMessage方法,字面意思已经很清楚了,这是通过分发的来获取回调的。
/**
* Subclasses must implement this to receive messages.
*/
public void handleMessage(Message msg) {
}
/**
* 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);
}
}
Handler的职责其实很像一个工人,拿着未加工的产品通过机床加工后又在机床取出来,
Looper
在分析Looper之前,先来解释一个概念,
我们都知道,在工作线程中不能更新UI,这个仿佛是一个定律,其实并不是不能在工作线程更新UI,而是UI不能在不是创建它的线程更新,而UI基本上都是在UI线程创建的,
所以才会有:在工作线程中不能更新UI。
而说到Looper必须来看看Android的入口AndroidThread类中的main方法
public static void main(String[] args) {
SamplingProfilerIntegration.start();
// CloseGuard defaults to true and can be quite spammy. We
// disable it here, but selectively enable it later (via
// StrictMode) on debug builds, but using DropBox, not logs.
CloseGuard.setEnabled(false);
Environment.initForCurrentUser();
// Set the reporter for event logging in libcore
EventLogger.setReporter(new EventLoggingReporter());
Process.setArgV0("<pre-initialized>");
//1.初始化Looper
Looper.prepareMainLooper();
//2. 创建ActivityThread实例
ActivityThread thread = new ActivityThread();
thread.attach(false);
if (sMainThreadHandler == null) {
sMainThreadHandler = thread.getHandler();
}
AsyncTask.init();
if (false) {
Looper.myLooper().setMessageLogging(new
LogPrinter(Log.DEBUG, "ActivityThread"));
}
//3.启动Loop
Looper.loop();
throw new RuntimeException("Main thread loop unexpectedly exited");
}
这里可以看见注释1、2、3分别初始化了UI线程,Looper,并且启动了Looper
Looper.prepareMainLooper
private static Looper sMainLooper; // guarded by Looper.class
public static void prepareMainLooper() {
prepare(false);
synchronized (Looper.class) {
if (sMainLooper != null) {
throw new IllegalStateException("The main Looper has already been prepared.");
}
sMainLooper = myLooper();
}
}
可以看见这里首先调用了prepare方法
Looper.prepare
static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
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对象把自己装进了ThreadLocal里;
这里大致提一下ThreadLocal,它是用于处理多线程并发操作的对象,每一个线程都会有一个ThreadLocal对象,它们只能再本线程访问。
在prepare之后可以看见一个变量
sMainLooper = myLooper();
字面意思已经很清楚了,Ui线程的Looper
Looper.myLooper
public static @Nullable Looper myLooper() {
return sThreadLocal.get();
}
这里把存在ThreadLocal中的Looper又取了出来,所以Looper其实是和线程关联的,每一个线程对应了一个Looper。
Looper.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;
// 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();
//1.循环
for (;;) {
//2.获取下一条消息
Message msg = queue.next(); // might block
if (msg == null) {
// No message indicates that the message queue is quitting.
return;
}
// This must be in a local variable, in case a UI event sets the logger
final Printer logging = me.mLogging;
if (logging != null) {
logging.println(">>>>> Dispatching to " + msg.target + " " +
msg.callback + ": " + msg.what);
}
final long traceTag = me.mTraceTag;
if (traceTag != 0 && Trace.isTagEnabled(traceTag)) {
Trace.traceBegin(traceTag, msg.target.getTraceName(msg));
}
try {
//3.这里其实是就是回调handler的dispatchMessage
msg.target.dispatchMessage(msg);
} finally {
if (traceTag != 0) {
Trace.traceEnd(traceTag);
}
}
if (logging != null) {
logging.println("<<<<< Finished to " + msg.target + " " + msg.callback);
}
// Make sure that during the course of dispatching the
// identity of the thread wasn't corrupted.
final long newIdent = Binder.clearCallingIdentity();
if (ident != newIdent) {
Log.wtf(TAG, "Thread identity changed from 0x"
+ Long.toHexString(ident) + " to 0x"
+ Long.toHexString(newIdent) + " while dispatching to "
+ msg.target.getClass().getName() + " "
+ msg.callback + " what=" + msg.what);
}
msg.recycleUnchecked();
}
}
从这个方法看,loop其实是一个死循环,在注释2处不断的在MessageQueue.next中获取下一个需要处理的消息,在注释3出不断分发给Handler(取出产品),Looper.loop()方法就是机开关的打开的方法(Looper提供了打开方法,并没有提供关闭方法,Looper的关闭,个人觉得与线程的生命周期有关)。
所以,如果不调用Looper.loop() 那么无论handler如何post,send消息都不会有handleMessage的回调。
那么问题来了,Looper又是如何与Handler关联起来的呢?
来看看Handler的初始化函数:
public Handler(Callback callback, boolean async) {
if (FIND_POTENTIAL_LEAKS) {
final Class<? extends Handler> klass = getClass();
if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) &&
(klass.getModifiers() & Modifier.STATIC) == 0) {
Log.w(TAG, "The following Handler class should be static or leaks might occur: " +
klass.getCanonicalName());
}
}
//1.这个Looper是在初始化Handler的线程的Looper
mLooper = Looper.myLooper();
if (mLooper == null) {
throw new RuntimeException(
"Can't create handler inside thread that has not called Looper.prepare()");
}
mQueue = mLooper.mQueue;
mCallback = callback;
mAsynchronous = async;
}
注释1处就是Handler关联Looper的关键了。
现在来理一理 Handler、Looper、Thread的关系,以UI线程为例:
Looper初始化时被放进Thread的局部变量ThreadLocal,取出时也通过局部变量ThreadLocal,所以Looper被关联至UI Thread,而Handler在构造函数中直接通过Looper.myLooper();取出Looper,所以取到的是UI线程的Looper,而UI线程的Looper在AndroidThread 也就是程序入口初始化。
示意图
至此Handler、Looper、Thread关系已经很清晰了。
MessageQueue
MessageQueue我们很自然的想到他会是一个map之类的集合用来保存Message,可是看见它的初始化函数的时候
private static final String TAG = "MessageQueue";
private static final boolean DEBUG = false;
// True if the message queue can be quit.
private final boolean mQuitAllowed;
@SuppressWarnings("unused")
private long mPtr; // used by native code
Message mMessages;
private final ArrayList<IdleHandler> mIdleHandlers = new ArrayList<IdleHandler>();
private SparseArray<FileDescriptorRecord> mFileDescriptorRecords;
private IdleHandler[] mPendingIdleHandlers;
private boolean mQuitting;
// Indicates whether next() is blocked waiting in pollOnce() with a non-zero timeout.
private boolean mBlocked;
// The next barrier token.
// Barriers are indicated by messages with a null target whose arg1 field carries the token.
private int mNextBarrierToken;
private native static long nativeInit();
private native static void nativeDestroy(long ptr);
private native void nativePollOnce(long ptr, int timeoutMillis); /*non-static for callbacks*/
private native static void nativeWake(long ptr);
private native static boolean nativeIsPolling(long ptr);
private native static void nativeSetFileDescriptorEvents(long ptr, int fd, int events);
初始化参数并没有集合相关的参数,在这个类里面找到了一个Message的引用与一个返回Message 的next方法,在看完Message的类时候发现Message其实自身维护了一个链表(剧透···)。
Message mMessages;
Message next() {
// Return here if the message loop has already quit and been disposed.
// This can happen if the application tries to restart a looper after quit
// which is not supported.
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) {
// Stalled by a barrier. Find the next asynchronous message in the queue.
do {
prevMsg = msg;
msg = msg.next;
} while (msg != null && !msg.isAsynchronous());
}
if (msg != null) {
if (now < msg.when) {
// Next message is not ready. Set a timeout to wake up when it is ready.
nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE);
} else {
// Got a message.
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 {
// No more messages.
nextPollTimeoutMillis = -1;
}
// Process the quit message now that all pending messages have been handled.
if (mQuitting) {
dispose();
return null;
}
// If first time idle, then get the number of idlers to run.
// Idle handles only run if the queue is empty or if the first message
// in the queue (possibly a barrier) is due to be handled in the future.
if (pendingIdleHandlerCount < 0
&& (mMessages == null || now < mMessages.when)) {
pendingIdleHandlerCount = mIdleHandlers.size();
}
if (pendingIdleHandlerCount <= 0) {
// No idle handlers to run. Loop and wait some more.
mBlocked = true;
continue;
}
if (mPendingIdleHandlers == null) {
mPendingIdleHandlers = new IdleHandler[Math.max(pendingIdleHandlerCount, 4)];
}
mPendingIdleHandlers = mIdleHandlers.toArray(mPendingIdleHandlers);
}
// Run the idle handlers.
// We only ever reach this code block during the first iteration.
for (int i = 0; i < pendingIdleHandlerCount; i++) {
final IdleHandler idler = mPendingIdleHandlers[i];
mPendingIdleHandlers[i] = null; // release the reference to the handler
boolean keep = false;
try {
keep = idler.queueIdle();
} catch (Throwable t) {
Log.wtf(TAG, "IdleHandler threw exception", t);
}
if (!keep) {
synchronized (this) {
mIdleHandlers.remove(idler);
}
}
}
// Reset the idle handler count to 0 so we do not run them again.
pendingIdleHandlerCount = 0;
// While calling an idle handler, a new message could have been delivered
// so go back and look again for a pending message without waiting.
nextPollTimeoutMillis = 0;
}
}
所以MessageQueue的职责不是对Message进行存储,而是对外提供Message这个链表的操作。
那么MessageQueue又是如何与Looper关联起来的呢?
来看看Looper的构造函数
final MessageQueue mQueue;
private Looper(boolean quitAllowed) {
mQueue = new MessageQueue(quitAllowed);
mThread = Thread.currentThread();
}
MessageQueue在Looper的构造函数里面进行了初始化,结合Handler、Looper、Thread关系图,其实直接就与Looper绑定了;
在Looper初始化,在Handler取出
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、Looper、Thread、MessageQueue的关系图是这样的:
Message
在分析Message之前,我们先来思考一下,在生产线上,每个产品至少有编号、产品的具体信息,如:
一块硬盘,我想检查一下第10块硬盘的质量是否合格?
所以这2个信息是必不可少的;还记得Handler的使用代码么?
Handler mHandler1 = new Handler(){
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case 1:
String s = msg.obj.toString();
//UI线程
break;
}
super.handleMessage(msg);
}
};
private void handlerTest1(){
new Thread(new Runnable() {
@Override
public void run() {
Message m = Message.obtain();
m.what = 1;
m.obj = "test";
mHandler1.sendMessage(m);
}
}).start();
}
这里的what对应的是产品编号,obj对应的是产品信息,那么Message为什么需要使用Message.obtain()来创建呢?
其实这个obtain是对Handler使用优化的一个重要方法,在Java读写文件的时候我们都会使用缓存来提高效率,而Handler作为一个线程间通信的重要方式,使用时非常频繁的,如果频繁的创建和销毁Message,导致GC不断触发是一件很耗费cpu的事情。
而Message使用链表来做了一个大小为50的池来缓存。
Message next;
private static final Object sPoolSync = new Object();
private static Message sPool;
private static int sPoolSize = 0;
private static final int MAX_POOL_SIZE = 50;
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方法先判断sPool也就是池中是否有对象存在,存在则把这个Message对象拿出来,并且把标识flags改成正在使用(注意,这里在池中获取对象,可以参考链表delete的操作,这里是把delete对象付给了新对象)
而sPool则在recycle方法中维护
public void recycle() {
if (isInUse()) {
if (gCheckRecycle) {
throw new IllegalStateException("This message cannot be recycled because it "
+ "is still in use.");
}
return;
}
recycleUnchecked();
}
void recycleUnchecked() {
// Mark the message as in use while it remains in the recycled object pool.
// Clear out all other details.
flags = FLAG_IN_USE;
what = 0;
arg1 = 0;
arg2 = 0;
obj = null;
replyTo = null;
sendingUid = -1;
when = 0;
target = null;
callback = null;
data = null;
synchronized (sPoolSync) {
if (sPoolSize < MAX_POOL_SIZE) {
next = sPool;
sPool = this;
sPoolSize++;
}
}
}
这一段代码大致意思就是当"回收"(这个回收是指手动调用这个方法,而不是GC回收)的时候,判断池大小是否小于50,如果小于则把该对象加入链表的表头。
搞清楚Message之后那么它与MessageQueue又是如何关联起来的呢?
public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
//1.这个mQueue就是与Handler关联的mQueue
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);
}
在sendMessage()的方法最终都会调用到queue.enqueueMessage(msg, uptimeMillis),第一个参数就是Message,第二个参数是延时,这里我们不管;
而这个queue其实就是Handler绑定的MessageQueue,而enqueueMessage从字面意思就插入队列
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;
/*1.我们知道Message是使用链表来维护的,
*当mMessages为空的时候表示链表没有数据
*/
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;
//2.把新的Message插入链表直到没有新的Message,
//break
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;
}
通过这个方法MessageQueue也就关联上了Message;
如果不深究到native层其实这一段代码还是很好理解的(native各种c,头都大了),插入到链表之前做了各种检查,直到确定合法,才把Message添加至链表;
Message和MessageQueue的关系和生产线的模型还是有偏差的,MessageQueue并不是Message的容器,真正的容器其实是Message自身的链表。
再来看看最开始的模型图
现在看来,是不是一目了然了呢。
总结:Hander、Looper、Message、MessageQueue的关系用代码来描述就是
Handler:负责发送信息,与回调获取信息。
Looper:消息泵,不断的读取消息集合中的的信息分发给Handler
Message:消息包装类,包装了需要发送的信息以及发送标识,同时自身是一个链表。
MessageQueue:对Message链表进行维护以及使用,对外提供Message操作的方法。