《Android开发艺术探索》笔记(八)——Android的消息机制

《Android开发艺术探索》笔记(八)——Android的消息机制

作者:cmad 时间:2016-05-19 分类:Android 评论:0条 浏览:708



  Android的消息机制主要是指Handler的运行机制,Handler的运行需要底层的MessageQueue和Looper的支撑。MessageQueue是消息队列,Looper是用来循环处理从消息队列取出来的消息体(Message),扮演着消息循环的角色。

  介绍Android的消息机制之前我们先来看以一个类:ThreadLocal。

ThreadLocal

  ThreadLocal是一个线程内部的数据存储类,通过它可以在指定的线程中存储数据,数据存储以后只有在指定线程中可以获取到存储的数据,对于其他线程来说则无法获取到数据。来看个例子:

final ThreadLocal<Boolean> mBooleanThreadLocal = new ThreadLocal<>();

mBooleanThreadLocal.set(true);
Log.d("ThreadLocal","[Thread#main]mBooleanThreadLocal="+mBooleanThreadLocal.get());

new Thread("Thread#1"){
@Override
public void run() {
mBooleanThreadLocal.set(false);
Log.d("ThreadLocal","[Thread#1]mBooleanThreadLocal="+mBooleanThreadLocal.get());
}
}.start();


new Thread("Thread#2"){
@Override
public void run() {
Log.d("ThreadLocal","[Thread#2]mBooleanThreadLocal="+mBooleanThreadLocal.get());
}
}.start();

输出结果:

D/ThreadLocal: [Thread#main]mBooleanThreadLocal=true
D/ThreadLocal: [Thread#1]mBooleanThreadLocal=false
D/ThreadLocal: [Thread#2]mBooleanThreadLocal=null

  从日志可以看出,在主线程里设置了mBooleanThreadLocal为ture所以输出为false,在线程1里设置为false所以输出为false,在线程2中没有设置所以输出为null。虽然在不同线程中访问的是同一个ThreadLocal对象,但是它们通过ThreadLocal获取到的值却是不一样的,这就是ThreadLocal的奇妙之处。

  为什么要介绍ThreadLocal呢?因为Looper内部保存每个线程的Looper对象用的就是ThreadLocal,Looper在当前线程取出的Looper对象就是当前线程保存的Looper,详细看后面Looper的介绍。

MessageQueue

  MessageQueue主要包含两个操作:插入和读取。读取操作本身会伴随着删除操作,插入和读取对应的方法为enqueueMessage和next,其中enqueueMessage的作用是往消息队列中插入一条消息,而next的作用是从消息队列中取出一条消息并将这条消息从消息队列中删除。尽管MessageQueue被叫做消息队列,但是它内部实现并不是用的队列,实际上它是通过一个单链表的数据结构来维护消息列表,单链表在插入和删除上比较有优势。具体的实现可以查看MessageQueue的源码。

Looper

  Looper在Android的消息机制中扮演着消息循环的角色。具体来说就是它会不停的从MessageQueue中查看是否有新消息,如果有新消息就会立刻处理,否则就一直阻塞在那里。

  看一下Looper的构造方法,在构造方法中会创建一个MessageQueue即消息队列,然后将当前现场的对象保存起来。

private Looper(boolean quitAllowed) {
mQueue = new MessageQueue(quitAllowed);
mThread = Thread.currentThread();
}

  我们发现构造方法是一个private私有方法,Looper提供了prepare方法来创建Looper对象,还提供了prepareMainLooper方法来创建主线程的Looper。通过Looper的loop方法来开启消息循环,在loop里有个死循环去重MessageQueue中获取消息Message,然后执行消息。看下prepare方法:

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));
}

  prepare方法里创建了Looper对象,并保存到了sThreadLocal里面,看下sThreadLocal:

static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();

  sThreadLocal是一个ThreadLocal,获取当前线程的Looper对象调用Looper的myLooper方法:

public static @Nullable Looper myLooper() {
return sThreadLocal.get();
}

  myLooper是从sThreadLocal中去获取Looper,也就是获取当前线程的保存的Looper,所以通过myLooper获取的是当前线程创建的Looper对象。

Handler

  Handler的工作主要包括消息的发送和接收过程,消息的发送可以通过post和send的一系列方法来实现,查看源码发现post的一系列方法最终通过send的一系列方法来实现。

public final boolean sendMessage(Message msg){
return sendMessageDelayed(msg, 0);
}

public final boolean sendEmptyMessage(int what){
return sendEmptyMessageDelayed(what, 0);
}

public final boolean sendEmptyMessageDelayed(int what, long delayMillis) {
Message msg = Message.obtain();
msg.what = what;
return sendMessageDelayed(msg, delayMillis);
}

public final boolean sendEmptyMessageAtTime(int what, long uptimeMillis) {
Message msg = Message.obtain();
msg.what = what;
return sendMessageAtTime(msg, uptimeMillis);
}


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);
}

public final boolean sendMessageAtFrontOfQueue(Message msg) {
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, 0);
}

private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
msg.target = this;
if (mAsynchronous) {
msg.setAsynchronous(true);
}
return queue.enqueueMessage(msg, uptimeMillis);
}

  可以发现,send的一系列方法最后调用了enqueueMessage方法,而enqueueMessage方法设置了msg的target为当前Handler,然后调用了MessageQueue的enqueueMessage方法,前面我们讲过,MessageQueue的enqueueMessage方法作用就是将消息插入到消息队列,所以send方法实质就是将消息插入到消息队列。

  上面我们看到send最后调用的是MessageQueue的enqueueMessage方法,那MessageQueue对象是哪来的呢?看一下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());
}
}

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;
}

public Handler(Looper looper, Callback callback, boolean async) {
mLooper = looper;
mQueue = looper.mQueue;
mCallback = callback;
mAsynchronous = async;
}

  Handler的构造方法有很多,但是最终都是调用的上面两个中的一个。可以看到MessageQueue是从Looper中获取的,前面我们也知道在创建Looper对象的时候会创建一个MessageQueue的对象。从上面两个构造函数可以得知,当我们创建Handler没有传入Looper对象的时候是调用Looper.myLooper()方法获取的,即获取当前线程的Looper对象。

  子线程默认是没有Looper对象的,所以我们在子线程创建Handler如果不创建Looper或者传入已有的Looper则会报错,因为Looper为空。在子线程中创建Handler我们可以先调用Looper.prepare()方法来创建Looper对象然后在创建Handler,这样Handler里就能获取Looper对象。或者在创建的时候传入Looper对象,比如通过Looper.getMainLooper()方法获取主线程的Looper传入。


  介绍了MessageQueue、Looper、Handler,我们来看一下消息机制的整个流程,Handler通过send将消息插入到MessageQueue消息队列,Looper通过循环从MessageQueue中获取消息,然后调用消息的target的dispatchMessage方法来处理消息msg.target.dispatchMessage(msg)。Message的target是一个Handler对象,也就是我们send消息的Handler,在Handler的enqueueMessage方法中我们看到了Message的target设置的Handler本身this,所以处理消息的过程又切换到了创建Handler的线程中去执行了。

  再来看看Handler的dispatchMessage方法:

public void dispatchMessage(Message msg) {
if (msg.callback != null) {
handleCallback(msg);
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
}
}

  逻辑很简单,首先检查Message的callback是否为null,不为null就通过handleCallback来处理消息。Message的callback就是一个Runnable对象,实际就是Handler的post方法传入的Runnable参数。handleCallback的逻辑也很简单,就是调用了handleCallback的run方法。

private static void handleCallback(Message message) {
message.callback.run();
}

  其次,检查mCallback是否为null,不为null就调用mCallback的handleMessage方法处理消息。Callback是一个接口,是通过构造函数设置的。

public interface Callback {
public boolean handleMessage(Message msg);
}

  最后调用Handler的handleMessage方法来处理消息,也就是我们常用的创建Handler实现的handleMessage方法。


至此,Android的消息机制就分析完了。


相关推荐
更多

发表评论

电子邮件地址不会被公开。 必填项已用*标注

您可以使用这些HTML标签和属性: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>