• Looper分析


    Looper分析

    Handler 机制中,Looper 的作用是提供了一个消息循环 ( message loop ) 的机制,用于处理和分发消息。

    Looper 是一个线程局部的对象,每个线程只能有一个 Looper 对象。它通过一个无限循环来不断地从消息队列中取出消息,并将消息分发给对应的 Handler 进行处理。

    在使用 Handler 机制时,我们可以通过调用 Looper.prepare() 方法来创建一个Looper对象,并通过 Looper.loop() 方法来启动消息循环。在消息循环开始后,Looper会不断地从消息队列中取出消息,然后将消息分发给对应的 Handler 进行处理。

    Handler 可以通过调用 post()sendMessage() 等方法将消息发送到消息队列中,然后由 Looper 负责将这些消息取出并分发给对应的 Handler 进行处理。这样就实现了线程间的消息传递和处理。

    Looper还可以通过调用 quit() 方法来终止消息循环,停止消息的处理。

    下来以主线程内的 Looper 分析下。

    Looper 创建/运行

    App 运行,进程创建后主线程开始运行的入口在 ActivityThreadmain(String[] args) 方法。

    // ActivityThread.java  sdk30
    
    public static void main(String[] args) {
    	// ...... 一系列的初始化操作。
        // 创建主线程的 Looper 并设置到 ThreadLocal,同时创建了绑定的 MessageQueue。
        Looper.prepareMainLooper(); 
    
        // ......
        
        ActivityThread thread = new ActivityThread(); // 主线程对象创建
        thread.attach(false, startSeq);
    
        if (sMainThreadHandler == null) { // 主线程处理各事件的 Handler
            sMainThreadHandler = thread.getHandler();
        }
    
        // ......
        
        Looper.loop();  // Looper 开始无限循环,从 MessageQueue 中取消息,也同时保证了主线程的存活。
    
        throw new RuntimeException("Main thread loop unexpectedly exited");
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    上面代码中 Looper 的创建与运行就两行。

    1. Looper.prepareMainLooper(); 方法的调用,创建了 **主线程 ** 的 Looper 对象,并将它设置到了 sThreadLocal 中。

      // Looper.java sdk30
      
      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));
      }
      
      @Deprecated
      public static void prepareMainLooper() {
          prepare(false);
          synchronized (Looper.class) {
              if (sMainLooper != null) {
                  throw new IllegalStateException("The main Looper has already been prepared.");
              }
              sMainLooper = myLooper();
          }
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19

      上面代码保证了一个线程只能有一个 Looper 对象:

      • if (sThreadLocal.get() != null) 判断表明 sThreadLocal 内对应于主线程的 Looper 对象只能存在一个。若主线程运行起来时发现已经有存在的 Looper 对象,将抛出异常,也就表明 app 进程直接crash。
      • prepareMainLooper() 被标注了 @DeprecatedLooperpublic 类,在 app 程序中是可以调用 Looper.prepareMainLooper() 方法的。换言之,在 sThreadLocal 中已经存在 Looper 对象的情况下,,可以再次调用方法 Looper.prepareMainLooper(),因此在 prepare(boolean quitAllowed) 一开始就先判断是否存在了 Looper 对象。进一步表明,一个线程中只能有一个 Looper
      • 赋值 sMainLooper

      这样主线程的 Looper 就创建完成了。

    2. Looper.loop(); 开启了 Looper 的无限循环,从 MessageQueue 中取消息,附带同时保证了主线程的存活。还负责将 msg 分发给对应的 Handler 执行。

    在这里插入图片描述

    Looper 运行图

    looper循环图

  • 相关阅读:
    采用php vue2 开发的一套医院安全(不良)事件管理系统源码(可自动生成鱼骨图)
    FreeRTOS学习第9篇--队列介绍
    【Java Web】HTML 标签 总结
    华为机试真题 Python 实现【过滤组合字符串】【2022.11 Q4新题】
    Linux基础命令
    手写签名功能(vue3)
    Flex布局详解
    java计算机毕业设计ssm+vue杂货网络销售及配送系统
    10个自动EDA库功能介绍:几行代码进行的数据分析靠不靠谱
    人工智能 | ShowMeAI资讯日报 #2022.06.24
  • 原文地址:https://blog.csdn.net/snowgeneral/article/details/133931278