最近决定把之前学习过的东西整理1遍,然后把写得1些代码review1遍,今天来学习1下消息机制,之前学过,没太弄清楚,有很多都忘记得差不多了,终究到底还是自己用得太少了,要多实践多实践。
1、首先上图(图片来源于他人的博客,盗图1枚)
从这张图我们可以看到触及到消息机制的1些类,比如Looper、Message、MessageQueue、Handler等,和里面的成员变量和方法。下面我们来学习1下这几个类。
Message:
what : what this message is about.用户自定义的消息码,以便接受者可以辨认。每一个Handler 对消息码有自己的命名空间,所以不用担心和其他的handler冲突。在消息处理中,我们可以根据这个字段的不同的值进行不同的处理。
arg1和arg2 :这两个参数是为了减小开消的替换物,就是你要是使用setData()寄存少数几个整型数值的话。
obj : 发送给接收者的任意对象。当我们使用Messenger跨进程发送消息的时候,如果是Parcelable框架类的话必须是非空的。对1般的数据1般使用setData()传递。
target : 处理消息的handler。
when :消息甚么时候入队列,甚么时候提交,甚么时候回收这样的标志吧。
callback : handler发送消息的时候可以post1个runnable对象,会触发回调。
next:下1个消息,看代码我们知道消息是以链表1样的情势存储的,而消息对列是以对列的方式处理消息,先进入的消息先处理。
obtain() : 推荐使用这样的方式取得消息对象,效力会更高。
recycle() : 当消息处理完后,回收消息对象。
MessageQueue
MessageQueue类提供1个消息队列,和插入、删除和提取消息的函数接口。
mPtr : 通过这个变量保存1个Native层的NativeMessageQueue对象
mMessages : 保存接收到的Message消息。
mQuitAllowed: 是不是允许终止,如果允许的话该值为true。
void quit(boolean safe) {
if (!mQuitAllowed) {
throw new IllegalStateException("Main thread not allowed to quit.");
}
synchronized (this) {
if (mQuitting) {
return;
}
mQuitting = true;
if (safe) {
removeAllFutureMessagesLocked();
} else {
removeAllMessagesLocked();
}
// We can assume mPtr != 0 because mQuitting was previously false.
nativeWake(mPtr);
}
}
mQuitting : 是不是终止了。
private boolean isPollingLocked() {
// If the loop is quitting then it must not be idling.
// We can assume mPtr != 0 when mQuitting is false.
return !mQuitting && nativeIsPolling(mPtr);
}
mBlocked:是不是正在等待被激活以获得消息。
1个线程最多只可以具有1个MessageQueue,安卓中通过ThreadLocal来保证1个线程中最多有1个Looper
Looper
Threads by default do not have a message loop associated with them.线程默许情况下是没有消息循环的。实现Thread的消息循环和消息派发,缺省情况下Thread是没有这个消息循环的既没有Looper;
需要主动去创建,然后启动Looper的消息循环loop;与外部的交互通过Handler进行;Looper 的构造函数很简单,创建MessageQueue,保存当前线程到 mThread 中。但它是私有的,只能通过两个静态函数 prepare()/prepareMainLooper() 来调用。
mQueue : 消息对列
prepare() : 初始化当前线程作为Looper。在调用loop()之前1定要先履行这个方法。知道调用了quite这个方法。
This gives you a chance to create handlers that then reference
* this looper, before actually starting the loop. Be sure to call
* {@link #loop()} after calling this method, and end it by calling
* {@link #quit()}.
public static void prepare() {
prepare(true);
}
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));
}
void prepareMainLooper()
初始化当前线程为looper,并且使其作为程序的主looper。通常是由程序根据环境创建的,所以开发者不建议使用这个方法。
public static void prepareMainLooper() {
prepare(false);
synchronized (Looper.class) {
if (sMainLooper != null) {
throw new IllegalStateException("The main Looper has already been prepared.");
}
sMainLooper = myLooper();
}
}
myLooper()
取得当前线程的looper,sThreadLocal是 ThreadLocal sThreadLocal 。ThreadLocal保证了1个线程里面只有1个Looper对象。关于ThreadLocal的原理大家可以到网上找点资料看1下,有点类似根据id寻觅值。
public static @Nullable Looper myLooper() {
return sThreadLocal.get();
}
loop()
这个类中最重要的1个方法。让Looper开始工作,从消息队列里取消息,处理消息。 Looper对象通过MessageQueue来寄存消息和事件。1个线程只能有1个Looper,对应1个MessageQueue。
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();
for (;;) {
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.traceBegin(traceTag, msg.target.getTraceName(msg));
}
try {
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();
}
}
void quit()
Quits the looper
public void quit() {
mQueue.quit(false);
}
Handler
mLooper : 线程的消息处理循环,其实不是每个线程都有消息处理循环。1般开发中用得比较多的是1个有Looper的Thread实现,HandlerThread。
mQueue : 消息对列对象,是成员对象mLooper的成员变量。
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;
mCallback 提供了另外一种使用Handler 的简便途径:只需实现回调接口 Callback,而无需子类化Handler。mAsynchronous 是标识是不是异步处理消息。
obtainMessage()
从消息池返回1个新的消息对象。实际上就是调用Message.obtain();
public final Message obtainMessage()
{
return Message.obtain(this);
}
boolean sendMessage(Message msg)
将消息push到消息对列里面所有等待消息的最后面,在规定的时间内,线程里面的handler会遭到这个消息。
public final boolean sendMessage(Message msg)
{
return sendMessageDelayed(msg, 0);
}
boolean post(Runnable r)
将Runnable对象添加到消息对列里面,这个Runnable对象将被该线程的handler处理。如果成功添加到消息对列里面的话返回true。失败返回false,失败通常是looper处理的这个消息正在对列中退出。
public final boolean post(Runnable r)
{
return sendMessageDelayed(getPostMessage(r), 0);
}
void dispatchMessage(Message msg)
顾名思义这个方法是处理消息的。会根据不同的条件调用不同的函数。在传入的这个Message对象履行Message.obtain()的时候会对msg.callback进行赋值。
public void dispatchMessage(Message msg) {
if (msg.callback != null) {
handleCallback(msg);
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
}
}
所以在查看消息处理对应的函数时,要看消息是不是是通过obtain()取得的,如果是那末消息处理就会交由传递参数中callback.run()来处理。而mCallback 则是在实例化Handler的时候初始化赋值的。如果msg.callback == null,且 mCallback == null,则由Handler本身的handleMessage()来处理。
**在判断调用哪一个消息处理函数时,1定要先看是不是在调用obtain构造消息的时候是否是传递了msg或Runable参数,如果没有,则判断在构造Handler时是不是将
Callback 函数当作参数传递了进来,最后再看自己的Handler是不是重写了handleMessage函数。**
void handleMessage(Message msg)
子类必须实现这个方法,去接收消息,然后再进行1些处理。
public void handleMessage(Message msg) {
}
**> MessageQueue作为1个容器,保存了所有待履行的消息。
MessageQueue中的Message包括3种类型:普通的同步消息,Sync barrier(target = null),异步消息(isAsynchronous() = true)。 MessageQueue的核心函数为enqueueMessage和next,前者用于向容器内添加Message,而Looper通过后者从MessageQueue中获得消息,并实现无消息情况下的等待。 MessageQueue把Android消息机制的Java实现和C++实现联系起来。 每一个线程最多可以有1个Looper。 每一个Looper有且唯一1个MessageQueue 每一个Handler关联1个MessageQueue,由该MessageQueue关联的Looper履行(调用Hanlder.dispatchMessage) 每一个MessageQueue可以关联任意多个Handler Looper API的调用顺序:Looper.prepare >> Looper.loop >> Looper.quit Looper的核心函数是Looper.loop,1般loop不会返回,直到线程退出,所以需要线程完成某个work时,请发送消息给Message(或说Handler)**