每个 Android 开发者必须知道的消息机制问题总结

2016-08-14 13:49:30

  Looper

  作用:

  关联起Thread

  循环取出消息

  1、Looper是否可以直接实例化?

  Looper构造方法是私有的,其中做了两件事

  创建一个MessageQueue

  得到与之对应的Thread

  private Looper(boolean quitAllowed) {

  mQueue = new MessageQueue(quitAllowed);

  mThread = Thread.currentThread();

  }

  2、一个线程能对应多个Lopper?

  不能,一个线程对应一个Looper对象,通过ThreadLocal保证一个线程只有一个Looper与之对应,如果多次调用Looper.prepare();则会抛出运行时异常。

  private static void prepare(boolean quitAllowed) {

  if (sThreadLocal.get() != null) { // 查看是否有looper与当前线程对应

  throw new RuntimeException("Only one Looper may be created per thread");

  }

  sThreadLocal.set(new Looper(quitAllowed));

  }

  3、Looper是无限循环,会阻塞吗?

  是,当开启一个loop后是一个死循环,从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;

  // 略

  for (;;) {

  Message msg = queue.next(); // might block

  if (msg == null) { // 当没有消息的时候,退出

  // No message indicates that the message queue is quitting.

  return;

  }

  // 略

  msg.target.dispatchMessage(msg);

  }

  4、可以再次调用Looper.prepareMainLooper吗?

  不可以,Looper.prepareMainLooper最终也是调用prepare(),同2.

  public static void prepareMainLooper() {

  prepare(false); // 创建一个Looper

  synchronized (Looper.class) {

  if (sMainLooper != null) {

  throw new IllegalStateException("The main Looper has already been prepared.");

  }

  sMainLooper = myLooper();

  }

  }

  5、MainLooper什么时候创建的?

  MainLooper是启动Activity创建ActivityThread(并不是一个Thread)时候创建,所以不能多次创建。

  public static void main(String[] args) {

  // 略

  Process.setArgV0("");

  Looper.prepareMainLooper();

  // 略

  ActivityThread thread = new ActivityThread();

  thread.attach(false);

  // 略

  if (sMainThreadHandler == null) {

  sMainThreadHandler = thread.getHandler();

  }

  // 略

  Looper.loop();

  throw new RuntimeException("Main thread loop unexpectedly exited");

  }

  }

  Handler

  作用:

  发送消息到MessageQueue

  处理消息

  1、Handler如何与Looper、MessageQueue关联起来?

  我们知道一个Looper对应一个Thread,一个Looper包含一个MessageQueue。当我们创建Handler时就会从当前线程中取出与之对应的Looper,让后在从Looper中取出MessageQueue。

  // 1、自动获取

  public Handler(Callback callback, boolean async) {

  // 略

  mLooper = Looper.myLooper(); // 取出当前线程中的Looper

  if (mLooper == null) {

  throw new RuntimeException(

  "Can't create handler inside thread that has not called Looper.prepare()");

  }

  mQueue = mLooper.mQueue; // 取出MessageQueue

  mCallback = callback;

  mAsynchronous = async;

  }

  // 2、传递一个Looper进来

  public Handler(Looper looper, Callback callback, boolean async) {

  mLooper = looper;

  mQueue = looper.mQueue;

  mCallback = callback;

  mAsynchronous = async;

  }

  Message

  单项链表结构。

  作用:

  数据的载体

  1、消息如何复用的?

  从全局消息池(链表结构)中

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

  }

  2、Message为什么能传递?

  Android中想要传递对象要么实现Serializable要么Parcelable,在这里是实现了Parcelable接口。

  public final class Message implements Parcelable {

  // 略

  }

  3、如何与Handler关联?

  我们知道在消息传机制中Handler充当着“快递员”的角色,那么他又是如何与“货物”--Message发生关系呢?实际上Message有一个成员变量target他的类型正是Handler,

  /*package*/ Runnable callback;

  public int arg1;

  public int arg2;

  public Object obj;

  /*package*/ Handler target; // 关键点

  当我们通过Handler去send一个Message时候最终都会为target赋值为this,即当前的Handler。

  private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {

  msg.target = this; // 赋值语句

  if (mAsynchronous) {

  msg.setAsynchronous(true);

  }

  return queue.enqueueMessage(msg, uptimeMillis);

  }

  另为如果是通过Message.Obtain(),获取的复用Message也会为其赋值。

  多说一句,Handler.obtainMessage()调用的就是Message.Obtain()。

  public final Message obtainMessage(){

  return Message.obtain(this);

  }

  总结:

  通过一系列的包涵关系,最终Looper、Handler、Message、MessageQueue即发生关联,从而形成一个闭合,开启消息循环。

  

 

  困惑

  最近一直在看这方面的知识,但是能力有限,还是有不少困惑,如果有错误,或你理解下面的问题请联系我fvaryu@qq.com,愿与君交流学习,谢谢

  1、Message中的sPool,哪里初始化的?为什么Message.obtain()中不会抛异常?

  2、ActivityThread并不是线程,为什么可以创建一个Looper,Main Thread什么时候创建?

  3、为什么序列化了的对象就可以传递?与Binder有关?

  4、MessageQueue对应的是NativeMessageQueue,具体实现需要学习?

  5、Loop.loop(),会退出吗?退出时机是什么?如果会退出,那么主线程同样会退出吗?

为您推荐