一个例子了解 HandlerThread,Looper,ThreadLocal,Handler,MessageQueue,Message的关系

我们经常会用到 HandlerThread 在线程中执行Runnable方法,调用代码如下,

private HandlerThread mHandlerThread = new HandlerThread("MainActivity");
mHandlerThread.start();
mWorkHandler = new Handler(mHandlerThread.getLooper());
mWorkHandler.post(new Runnable() {
  @Override
  public void run() {

  }
});
相关机制是怎么触发的呢?
这里面涉及到HandlerThread,Looper,ThreadLocal,Handler,MessageQueue,Message 等概念,

Looper类,是用来封装消息循环和消息队列的。

流程如下:

1.mHandlerThread.start();
本身继承Thread,该方法启动线程,
HandlerThread run方法
HandlerThread.run相关代码如下:
public void run() {
  mTid = Process.myTid();
  Looper.prepare();
  synchronized (this) {
  mLooper = Looper.myLooper();
  notifyAll();
}
Process.setThreadPriority(mPriority);
onLooperPrepared();
Looper.loop();
mTid = -1;
}

1.1 执行 Looper.prepare()
  Looper.prepare() 创建Looper实例放在 sThreadLocal 对象里面, 调用如下:
  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));
  }
1.2 Looper.myLooper()方法从 sThreadLocal 中获取Looper实例(这个实例是线程独立的,即获取的是对应线程创建的Looper实例)
  给 HandlerThread 的全局变量 mLooper

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

1.3 执行Looper.loop()创建消息循环,
  核心逻辑是从 当前线程的Looper中取出 MessageQueue,循环遍历 MessageQueue 中的消息
  Looper.loop()代码
  public static void loop() {
    final Looper me = myLooper();
    final MessageQueue queue = me.mQueue;
    ...
  }

2.new Handler(mHandlerThread.getLooper())
  2.1 mHandlerThread.getLooper() 获取HandlerThread 中创建的 Looper对象
  2.2 把获取的Looper初始化到Hander中
3. mWorkHandler.post(new Runnable()..)
  3.1通过 getPostMessage 方法将Runnable封装到 Message 对象中
  3.2 最终会调用sendMessageAtTime方法
  该方法中MessageQueue对象 mQueue 就是从2.1 Hander中Lopper中获取的,而且这个MessageQueue 在1.3 消息循环中不停的被遍历,
  你只要向 MessageQueue 中添加Runnable封装 Message,就会在指定的时间执行 Runnable方法。
 

Handler.java 相关调用代码如下:
  public final boolean post(Runnable r)
  {
    return sendMessageDelayed(getPostMessage(r), 0);
  }

  private static Message getPostMessage(Runnable r) {
    Message m = Message.obtain();
    m.callback = r;
   return m;
 }

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

----------------------

所以如下事例中在直接创建的线程中,不能直接 使用 Handler否则会抛出异常。
而HandlerThread 可以直接使用,因为HandlerThread 初始化时候内部已经调用过Looper.prepare()
new Thread(() -> {
Log.i(TAG, "testLooper()");
//Looper.prepare();
//在线程中使用Handler 会抛出如下异常,需要在使用Handler前,调用 Looper.prepare();
//java.lang.RuntimeException: Can't create handler inside thread Thread[Thread-3,5,main] that has not called Looper.prepare()
Handler handler = new Handler();
}).start();

posted @ 2020-07-31 10:20  adam.li  阅读(197)  评论(0编辑  收藏  举报