• 一个例子了解 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 等概念,流程如下:

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

  • 相关阅读:
    分布式数据库中间件Mycat百亿级数据存储(转)
    大文本字符串滤重的解决方案(转)
    java处理大文本2G以上
    Mysql binlog详解
    varnish squid nginx比较
    java运行时内存分类
    redis rdb aof比较
    LeetCode 94 ——二叉树的中序遍历
    线性代数之——向量空间
    线性代数之——A 的 LU 分解
  • 原文地址:https://www.cnblogs.com/adamli/p/13408190.html
Copyright © 2020-2023  润新知