【Android 异步操作】手写 Handler ( 循环者 Looper | Looper 初始化 | Looper 遍历消息队列 MessageQueue )

简介: 【Android 异步操作】手写 Handler ( 循环者 Looper | Looper 初始化 | Looper 遍历消息队列 MessageQueue )

文章目录

一、Looper 初始化

二、Looper 遍历消息队列 MessageQueue

三、完整 Looper 代码





一、Looper 初始化


Looper 是 线程本地变量 , 在每个线程中 , 可以通过线程调用 ThreadLocal 变量的 get 方法获取该线程对应的对象副本 , 调用 ThreadLocal 变量的 set 方法 , 设置该线程对应类型的对象副本 ;



Looper 调用 prepare 方法进行初始化 , 在该方法中处理 线程本地变量的先关初始化与设置 ,


如果之前已经初始化过 , 本次调用 prepare 方法是第二次调用 , 则会 抛出异常 ,


如果之前没有初始化过 , 那么创建一个 Looper , 然后调用线程本地变量 ThreadLocal 的 set 方法 , 将该 Looper 对象设置成线程本地变量 ;


 

/**
     * 一个线程只能有一个 Looper
     * 使用 ThreadLocal 来保存该 Looper
     * 是线程内部存储类 , 只能本线程才可以得到存储的数据 ;
     */
    static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<>();
    /**
     * 准备 Looper 方法
     */
    public static void prepare(){
        System.out.println("prepare 创建 Looper ");
        // 先进行判断 , 如果当前线程已经有了 Looper , 那就抛出异常
        if(sThreadLocal.get() != null){
            throw new RuntimeException("当前线程已存在 Looper");
        }
        // 如果不存在 Looper , 就创建一个 Looper
        sThreadLocal.set(new Looper());
    }






二、Looper 遍历消息队列 MessageQueue


在 Looper 线程中 , 最后一句代码肯定是 Looper.loop() , 执行该方法后 , 就开启了一个无限循环 ,


不断从 消息队列 MessageQueue 中获取消息 , 然后发送给该 消息 Message 对应的 Handler ,


哪个 Handler 发送的消息 , 就将消息在送回给哪个 Handler ;



消息同步 : 当 消息队列 MessageQueue 为空时 , 无法从消息队列中获取数据 , 此时线程会 阻塞 , 直到有新的消息到来后 , 解除阻塞 ;



Looper 循环遍历消息队列部分代码 :


 

/**
     * 不断从 消息队列 MessageQueue 中取出 Message 消息执行
     */
    public static void loop(){
        System.out.println("开始无限循环获取 Message");
        // 获取当前线程的 Looper
        Looper looper = Looper.looper();
        // 从当前线程的 Looper 获取 消息队列 MessageQueue
        MessageQueue messageQueue = looper.mQueue;
        // 不断从 消息队列中获取 消息 , 分发到发送消息的 Handler 中执行
        for(;;){
            // 获取消息队列中的第一个消息
            Message next = messageQueue.next();
            // 分发到发送该消息的 Handler 中执行
            next.target.handleMessage(next);
        }
    }






三、完整 Looper 代码


package kim.hsl.handler;
public class Looper {
    /**
     * 一个线程只能有一个 Looper
     * 使用 ThreadLocal 来保存该 Looper
     * 是线程内部存储类 , 只能本线程才可以得到存储的数据 ;
     */
    static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<>();
    /**
     * 消息队列
     */
    public MessageQueue mQueue;
    /**
     * Looper 构造函数
     */
    private Looper(){
        mQueue = new MessageQueue();
    }
    /**
     * 获取当前线程对应的 Looper
     * @return
     */
    public static Looper looper(){
        return sThreadLocal.get();
    }
    /**
     * 准备 Looper 方法
     */
    public static void prepare(){
        System.out.println("prepare 创建 Looper ");
        // 先进行判断 , 如果当前线程已经有了 Looper , 那就抛出异常
        if(sThreadLocal.get() != null){
            throw new RuntimeException("当前线程已存在 Looper");
        }
        // 如果不存在 Looper , 就创建一个 Looper
        sThreadLocal.set(new Looper());
    }
    /**
     * 不断从 消息队列 MessageQueue 中取出 Message 消息执行
     */
    public static void loop(){
        System.out.println("开始无限循环获取 Message");
        // 获取当前线程的 Looper
        Looper looper = Looper.looper();
        // 从当前线程的 Looper 获取 消息队列 MessageQueue
        MessageQueue messageQueue = looper.mQueue;
        // 不断从 消息队列中获取 消息 , 分发到发送消息的 Handler 中执行
        for(;;){
            // 获取消息队列中的第一个消息
            Message next = messageQueue.next();
            // 分发到发送该消息的 Handler 中执行
            next.target.handleMessage(next);
        }
    }
}



目录
相关文章
|
5月前
|
消息中间件 测试技术 RocketMQ
消息队列 MQ产品使用合集之在异步发送消息函数sendMessage()中出现了错误,错误代码为-3,该如何解决
消息队列(MQ)是一种用于异步通信和解耦的应用程序间消息传递的服务,广泛应用于分布式系统中。针对不同的MQ产品,如阿里云的RocketMQ、RabbitMQ等,它们在实现上述场景时可能会有不同的特性和优势,比如RocketMQ强调高吞吐量、低延迟和高可用性,适合大规模分布式系统;而RabbitMQ则以其灵活的路由规则和丰富的协议支持受到青睐。下面是一些常见的消息队列MQ产品的使用场景合集,这些场景涵盖了多种行业和业务需求。
|
4月前
|
安全 Android开发 Kotlin
Android经典面试题之Kotlin延迟初始化的by lazy和lateinit有什么区别?
**Kotlin中的`by lazy`和`lateinit`都是延迟初始化技术。`by lazy`用于只读属性,线程安全,首次访问时初始化;`lateinit`用于可变属性,需手动初始化,非线程安全。`by lazy`支持线程安全模式选择,而`lateinit`适用于构造函数后初始化。选择依赖于属性特性和使用场景。**
141 5
Android经典面试题之Kotlin延迟初始化的by lazy和lateinit有什么区别?
|
4月前
|
消息中间件 存储 中间件
云原生异步问题之消息队列中的异步如何解决
云原生异步问题之消息队列中的异步如何解决
|
5月前
|
存储 Java 数据库连接
Android Java开发异步
【6月更文挑战第15天】
|
5月前
|
JSON Java API
【Android】使用 Retrofit2 发送异步网络请求的简单案例
**摘要:** Retrofit是Android和Java的HTTP客户端库,简化了RESTful API交互。它通过Java接口定义HTTP请求,并提供注解管理参数、HTTP方法等。要使用Retrofit,首先在AndroidManifest.xml中添加`INTERNET`权限,然后在`build.gradle`中引入Retrofit和Gson依赖。创建服务器响应数据类和描述接口的接口,如`Result`和`Api`。通过Retrofit.Builder配置基础URL并构建实例,之后调用接口方法创建Call对象并发送异步请求。
193 1
|
5月前
|
消息中间件 存储 中间件
中间件消息队列协议异步通信
【6月更文挑战第5天】
44 2
|
5月前
|
Android开发
40. 【Android教程】AsyncTask:异步任务
40. 【Android教程】AsyncTask:异步任务
125 2
|
5月前
|
Java Android开发
程序与技术分享:Android使用Dagger注入的方式初始化对象的简单使用
程序与技术分享:Android使用Dagger注入的方式初始化对象的简单使用
140 0
|
6月前
|
消息中间件 存储 物联网
AMQP(Advanced Message Queuing Protocol)是一种标准化的消息队列协议,用于异步通信和消息传递
AMQP是开放标准的消息队列协议,确保异步通信中的消息路由、可靠性和灵活性。它支持持久化、确认机制,防止消息丢失,允许灵活路由与定制,适用于多领域,如企业应用、云计算和物联网。
137 0
|
6月前
|
Shell Android开发
Android USB系统初始化init.usb.rc
Android USB系统初始化init.usb.rc
265 0