开发者社区> 韩曙亮> 正文

【Android 异步操作】手写 Handler ( Message 消息 | ThreadLocal 线程本地变量 | Looper 中的消息队列 MessageQueue )

简介: 【Android 异步操作】手写 Handler ( Message 消息 | ThreadLocal 线程本地变量 | Looper 中的消息队列 MessageQueue )
+关注继续查看

文章目录

一、Message 消息

二、ThreadLocal 线程本地变量

三、Looper 中的消息队列 MessageQueue





一、Message 消息


模仿 Android 中的 Message 基本功能 , 提供 what 与 obj 变量 , 提供一个回收方法 ;


此外 , 还要指明下一个消息 , 以及是哪个 Handler 发送的该消息 ;


package kim.hsl.handler;
public class Message {
    /**
     * 消息识别码
     */
    int what;
    /**
     * 消息对象
     */
    Object obj;
    /**
     * 指向下一个消息
     */
    Message next;
    /**
     * 该 Message 使用哪个 Handler 进行发送的
     */
    Handler target;
    /**
     * 回收方法
     */
    public void recyle(){
        obj = null;
        next = null;
        target = null;
    }
}







二、ThreadLocal 线程本地变量


ThreadLocal 作用是 保存线程私有变量 ;


使用 ThreadLocal 维护一个变量时 , 每个使用该 ThreadLocal 线程本地变量 的线程 , 都会 被分配一个独立的变量副本 ,


每个线程 只 可以 改变本线程内的 变量副本 , 即 ThreadLocal 线程本地变量 ;




1 . ThreadLocal 定义 :


   

/**
     * 一个线程只能有一个 Looper
     * 使用 ThreadLocal 来保存该 Looper
     * 该变量是线程内部存储类 , 只能本线程才可以得到存储的数据 ;
     */
    static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<>();




2 . ThreadLocal 变量获取 : 调用 ThreadLocal 变量的 get() 方法 , 可以获取该 ThreadLocal 线程本地变量 ;


在 ThreadLocalMap map = getMap(t) 中 , 获取的 ThreadLocalMap 与 Java 中的 Map 集合没有任何关联 , 该类就是为了保存 线程本地变量而在 ThreadLocal 中设置的内部类 ; 在该 ThreadLocalMap 内部类中 , 通过 key 键 , 获取对应 value 值 ;


public class ThreadLocal<T> {
    /**
     * 返回 该线程本地变量的 当前线程的变量副本.
     * 如果 该线程中对应的 变量没有值, 应该首先初始化该变量值
     *
     * @return 返回当前线程的线程本地变量值 
     */
    public T get() {
        // 首先通过 Thread 拿到当前的线程 
        Thread t = Thread.currentThread();
        // 通过当前线程 , 获取当前线程的 ThreadLocalMap 
        ThreadLocalMap map = getMap(t);
        if (map != null) {
            // 通过 key 获取指定的 value
            ThreadLocalMap.Entry e = map.getEntry(this);
            if (e != null) {
                @SuppressWarnings("unchecked")
                T result = (T)e.value;
                return result;
            }
        }
        return setInitialValue();
    }
}



3 . ThreadLocal 变量设置 : 调用 ThreadLocal 的 put() 方法 , 可以设置 线程本地变量 ;




4 . Looper 中关于 线程本地变量 的设置 : 在 Looper 中涉及到了 线程本地变量 的设置 ,


Looper 要求每个线程只能保持一个 , 并且各个线程之间的 Looper 相互独立 , 没有任何关联 ;


这就需要 将 Looper 定义成线程本地变量 ;


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






三、Looper 中的消息队列 MessageQueue


在 Looper 中首先要维护一个 ThreadLocal 线程本地变量 , 确保每个线程中都可以获取到一个该变量的独立副本 ;


维护消息队列 : 每个 Looper 中还要维护一个 MessageQueue 消息队列 , 用于存储从 Handler 中发送来的消息 ;


该消息队列 在 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(){
        // 先进行判断 , 如果当前线程已经有了 Looper , 那就抛出异常
        if(sThreadLocal.get() != null){
            throw new RuntimeException("当前线程已存在 Looper");
        }
        // 如果不存在 Looper , 就创建一个 Looper
        sThreadLocal.set(new Looper());
    }
}



版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。

相关文章
ACCESS 触发器delete table事件变量使用及连续删除
    ACCESS的TABLE DELETE 事件触发后,会出现一个[旧]的记录,这条记录非常有用,可以用来作条件判断使用。     如下图的table event事件中,删除一条记录后,可以使用[旧]记录连接执行多个删除相关记录的操作。
593 0
操作系统的线程管理机制以及Thread.Sleep()的作用
说明:本文章内容来自某论坛里的一位大牛的回复。 引题:我们可能经常会用到 Thread.Sleep 函数来使线程挂起一段时间。
738 0
fbh
less 学习-变量
很容易理解: @nice-blue: #5B83AD; @light-blue: @nice-blue + #111; #header { color: @light-blue; } 输出: #header {...
731 0
自定义Application使用示例——几个Activity共同操作某个变量
MainActivity如下: package cn.testapplication; import android.os.Bundle; import android.
681 0
使用OpenApi弹性释放和设置云服务器ECS释放
云服务器ECS的一个重要特性就是按需创建资源。您可以在业务高峰期按需弹性的自定义规则进行资源创建,在完成业务计算的时候释放资源。本篇将提供几个Tips帮助您更加容易和自动化的完成云服务器的释放和弹性设置。
18592 0
SAS学习笔记之《SAS编程与数据挖掘商业案例》(3)变量操作、观测值操作、SAS数据集管理
SAS学习笔记之《SAS编程与数据挖掘商业案例》(3)变量操作、观测值操作、SAS数据集管理 1. SAS变量操作的常用语句 ASSIGNMENT 创建或修改变量 SUM 累加变量或表达式 KEEP 规定在数据集中保留的变量 DROP 规定在数据集中删除的变量 ARRAY 定义一个数组 RENAME
1486 0
环境变量PATH/cp命令/mv命令/文档查看cat/more/less/head/tail
  2.10 环境变量PATH 2.11 cp命令 2.12 mv命令 2.13 文档查看cat/more/less/head/tail     which  rmdir 可以查到命令的路径   例如: ls 命令是定义在/usr/bin/ls 下,可以复制cp  /usr/bin/ls   /tmp/ls2 然后执行/tmp/ls2 可以运行,但是单独执行ls2时不行的,因为没有给ls2定义环境变量。
898 0
+关注
韩曙亮
专注 Android 领域
2605
文章
0
问答
文章排行榜
最热
最新
相关电子书
更多
OceanBase 入门到实战教程
立即下载
阿里云图数据库GDB,加速开启“图智”未来.ppt
立即下载
实时数仓Hologres技术实战一本通2.0版(下)
立即下载