Android 源码分析-消息队列和 Looper

1. Android 源码分析-消息队列和 Looper
概念

  1. 什么是消息队列
    消息队列在 android 中对应 MessageQueue 这个类,顾名思义,消息队列中存放了大量的消息(Message)
  2. 什么是消息
    消息(Message)代表一个行为(what)或者一串动作(Runnable),有两处会用到 Message:
    Handler 和 Messenger
  3. 什么是 Handler 和 Messenger
    Handler 大家都知道,主要用来在线程中发消息通知 ui 线程更新 ui。Messenger 可以翻译为信使,可以实现进程间通信(IPC),Messenger 采用一个单线程来处理所有的消息,而且进程间的通信都是通过发消息来完成的,感觉不能像 AIDL 那样直接调用对方的接口方法(具体有待考证),这是其和 AIDL 的主要区别,也就是说 Messenger 无法处理多线程,所有的调 用 都 是 在 一 个 线 程 中 串 行 执 行 的 。 Messenger 的 典 型 代 码 是 这 样 的 : new
    Messenger(service).send(msg),它的本质还是调用了 Handler 的 sendMessage 方法
  4. 什么是 Looper
    Looper 是循环的意思,它负责从消息队列中循环的取出消息然后把消息交给目标处理
  5. 线程有没有 Looper 有什么区别?
    线程如果没有 Looper,就没有消息队列,就无法处理消息,线程内部就无法使用 Handler。这就是为什么在子线程内部创建 Handler 会报错:"Can't create handler inside thread that has not called Looper.prepare()",具体原因下面再分析。
  6. 如何让线程有 Looper 从而正常使用 Handler? 在线程的 run 方法中加入如下两句:
  Looper.prepare();
  Looper.loop();

这一切不用我们来做,有现成的,HandlerThread 就是带有 Looper 的线程。
想 用 线 程 的 Looper 来 创 建 Handler , 很 简 单 , Handler handler = new
Handler(thread.getLooper()),有了上面这几步,你就可以在子线程中创建 Handler 了,好吧, 其实 android 早就为我们想到这一点了,也不用自己写,IntentService 把我们该做的都做了, 我们只要用就好了,具体怎么用后面再说。
消息队列和 Looper 的工作机制
一个 Handler 会有一个 Looper,一个 Looper 会有一个消息队列,Looper 的作用就是循环的遍历消息队列,如果有新消息,就把新消息交给它的目标处理。每当我们用 Handler 来发送消息,消息就会被放入消息队列中,然后 Looper 就会取出消息发送给它的目标 target。一般情况,一个消息的 target 是发送这个消息的 Handler,这么一来,Looper 就会把消息交给
Handler 处理,这个时候 Handler 的 dispatchMessage 方法就会被调用,一般情况最终会调用
Handler 的 handleMessage 来处理消息,用 handleMessage 来处理消息是我们常用的方式。源码分析

  1. Handler 发送消息的过程
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);
        }
        //这里 msg 被加入消息队列 queue
      return queue.enqueueMessage(msg, uptimeMillis);
}
  1. Looper 的工作过程
    public static void loop() {
        final Looper me = myLooper(); if (me == null) {
          throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
    }
    //从 Looper 中取出消息队列
    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 Printer logging = me.mLogging;
    if (logging != null) {
          logging.println(">>>>> Dispatching to " + msg.target + " " + msg.callback + ": " + msg.what);
    }
    //将消息交给 target 处理,这个 target 就是 Handler 类型
    msg.target.dispatchMessage(msg);
    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.recycle();
    }
}
  1. Handler 如何处理消息
    /**
      * 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) {
            //这个方法很简单,直接调用 msg.callback.run(); 
            handleCallback(msg);
        } else {
            //如果我们设置了 callback 会由 callback 来处理消息
            if (mCallback != null) {
            if (mCallback.handleMessage(msg)) {
                return;
          }
      }

  //否则消息就由这里来处理,这是我们最常用的处理方式
    handleMessage(msg);
  }
}

我们再看看 msg.callback 和 mCallback 是啥东西
/package/ Runnable callback;
现在已经很明确了, msg.callback 是个 Runnable , 什么时候会设置这个 callback :
handler.post(runnable),相信大家都常用这个方法吧

/**
* Callback interface you can use when instantiating a Handler to  avoid
* having to implement your own subclass of  Handler.
*
* @param msg A {@link android.os.Message Message} object
* @return True if no further handling is  desired
*/
public interface Callback {
 public boolean handleMessage(Message msg);
}

final Callback mCallback;
而 mCallback 是个接口, 可以这样来设置 Handler handler = new Handler(callback), 这个
callback 的意义是什么呢,代码里面的注释已经说了,可以让你不用创建 Handler 的子类但是还能照样处理消息, 恐怕大家常用的方式都是新 new 一个 Handler 然后 override 其
handleMessage 方法来处理消息吧,从现在开始,我们知道,不创建 Handler 的子类也可以处理消息。多说一句,为什么创建 Handler 的子类不好?这是因为,类也是占空间的,一个应用 class 太多,其占用空间会变大,也就是应用会更耗内存。
HandlerThread 简介

@Override
public void run() {
    mTid = Process.myTid(); 
    Looper.prepare(); 
    synchronized (this) {
          mLooper = Looper.myLooper(); notifyAll();
    }
    Process.setThreadPriority(mPriority); 
    onLooperPrepared();
    Looper.loop();
    mTid = -1;
}

HandlerThread 继承自 Thread , 其在 run 方法内部为自己创建了一个 Looper , 使用上
HandlerThread 和普通的 Thread 不一样,无法执行常见的后台操作,只能用来处理新消息, 这是因为 Looper.loop()是死循环,你的 code 根本执行不了,不过貌似你可以把你的 code 放在 super.run()之前执行,但是这好像不是主流玩法,所以不建议这么做。
IntentService 简介

public void onCreate() {
// TODO: It would be nice to have an option to hold a partial wakelock
// during processing, and to have a static startService(Context, Intent)
// method that would launch the service & hand off a wakelock.
super.onCreate();
HandlerThread thread = new HandlerThread("IntentService[" + mName + "]"); thread.start();
mServiceLooper = thread.getLooper();
mServiceHandler = new ServiceHandler(mServiceLooper);
}

IntentService 继承自 Service,它是一个抽象类,其被创建的时候就 new 了一个 HandlerThread和 ServiceHandler,有了它,就可以利用 IntentService 做一些优先级较高的 task,IntentService 不会被系统轻易杀掉。使用 IntentService 也是很简单, 首先 startService(intent), 然后
IntentService 会把你的 intent 封装成 Message 然后通过 ServiceHandler 进行发送, 接着
ServiceHandler 会 调 用 onHandleIntent(Intent intent) 来 处 理 这 个 Message , onHandleIntent(Intent intent)中的 intent 就是你 startService(intent)中的 intent,ok,现在你需要做的是从 IntentService 派生一个子类并重写 onHandleIntent 方法,然后你只要针对不同的
intent 做不同的事情即可,事情完成后 IntentService 会自动停止。所以,IntentService 是除了 Thread 和 AsyncTask 外又一执行耗时操作的方式,而且其不容易被系统干掉,建议关键操作采用 IntentService。
在子线程创建 Handler 为什么会报错?

public Handler(Callback callback, boolean async) {
       if (FIND_POTENTIAL_LEAKS) {
          final Class 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());
        }
}
    //获取当前线程的 
Looper 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; mCallback = callback; mAsynchronous = async;
}

如何避免这种错误:在 ui 线程使用 Handler 或者给子线程加上 Looper。

你可能感兴趣的:(Android 源码分析-消息队列和 Looper)