Android Handler类的源码详解

handler机制的架构设计

Handler机制主要分为两部分:发送消息和处理消息;
发送消息:可以在任意的子线程中进行操作;
处理消息:在主线程中进行操作,主要是通过Looper类轮询MessageQueue队列来处理消息的;

在这里插入图片描述

handler中的发送消息的方法有很多种;但是这些方法经过处理最终会调用到Handler.enqueueMessage();
发送消息:
1.调用sendMessage方法,将消息传递到MessageQueue队列中
2.使用handler.post(new Runnable(){.....})  //作为message.callback的值,传递给MessageQueue队列
处理消息:
在主线程ActivityThread类中,调用Looper.loop()方法,在该方法中轮询消息队列MessageQueue,然后执行这些消息;

Handler类的源码详解

Handler机制在源码层可以分为4层:

Looper机制:sThreadLocal,Looper.loop();
Message:消息的数据结构,消息缓存池;
MessageQueue:enqueueMessage,next,消息等待,同步消息隔离,idleHandler;
Handler:send/post,dispatchMessage消息处理优先级;

1.Looper机制:

sThreadLocal:静态常量,保证一个线程只有一个 Looper;
sMainLooper:静态变量,在 prepareMainLooper 中赋值当前线程 Looper;
mQueue:变量,Looper 构造函数中初始化,因为一个线程只有一个 Looper,所以也同样只有一个 mQueue。

通过以上分析,我们可以总结出一下特性:
Looper、MessageQueue 是线程唯一的;
一个进程只有一个 sMainLooper;
根据 ThreadLocal 的特性,可通过 myLooper 方法获取当前线程的 Looper。

Looper.loop()public static void loop() {
    final Looper me = myLooper();
    final MessageQueue queue = me.mQueue;
    for (;;) { 
        Message msg = queue.next();
        ...
        msg.target.dispatchMessage(msg);
        ...
        msg.recycleUnchecked();
    }
}
Looper.loop() 方法虽然看起来很多,其实他主要就做了三件事:
从消息队列中获取下一个消息;
msg.target 就是 handler,通过 dispatchMessage 方法把消息分发下去,这个方法下面会有说到;
消息回收,放到消息缓存池里。这里需要注意的是 Message 对象并没有释放,会缓存起来。

2.Message数据结构:

public int what, arg1, arg2;
public Object obj;
public Messenger replyTo;
int flags;
long when;      // 消息发送时间
Bundle data;
Handler target;
Runnable callback;

Message next;

private static final Object sPoolSync = new Object();
private static Message sPool;
private static int sPoolSize = 0;

private static final int MAX_POOL_SIZE = 50;

看到 next 变量,我们会想到单链表,其实 Message 就相当于单链表的 node,MessageQueue 就是一个单链表了,会持有表头的引用;
what、arg1、arg2、obj、data 就是我们发送的一些信息;
值得注意的是 target,他是 Handler 类型,就是本消息的 Handler,会在 Handler 发送消息的时候赋值;
后面的四个对象,都是和消息缓存池有关的。

3.MessageQueue消息队列:

主要作为插入队列的方法,有下列几个特性:
把消息加入消息队列,如果当前表头为空,则把消息作为表头引用;如果不为空,则会根据时间的顺序,插入到对应的时间中;
nativeWake 是调用底层在管道中写操作以唤醒,在队列不是阻塞的状态下是不需要唤醒的;
另外注意其中用了 synchronized 关键字,说明消息队列的插入是线性安全的,删除也是线性安全的,之后我们会说到。
安装Docker安装插件,可以按照以下步骤进行操作: 1. 首先,安装Docker。可以按照官方文档提供的步骤进行安装,或者使用适合您操作系统的包管理器进行安装。 2. 安装Docker Compose插件。可以使用以下方法安装: 2.1 下载指定版本的docker-compose文件: curl -L https://github.com/docker/compose/releases/download/1.21.2/docker-compose-`uname -s`-`uname -m` -o /usr/local/bin/docker-compose 2.2 赋予docker-compose文件执行权限: chmod +x /usr/local/bin/docker-compose 2.3 验证安装是否成功: docker-compose --version 3. 在安装插件之前,可以测试端口是否已被占用,以避免编排过程中出错。可以使用以下命令安装netstat并查看端口号是否被占用: yum -y install net-tools netstat -npl | grep 3306 现在,您已经安装Docker安装Docker Compose插件,可以继续进行其他操作,例如上传docker-compose.yml文件到服务器,并在服务器上安装MySQL容器。可以参考Docker的官方文档或其他资源来了解如何使用DockerDocker Compose进行容器的安装和配置。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* [Docker安装docker-compose插件](https://blog.youkuaiyun.com/qq_50661854/article/details/124453329)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] - *3* [Docker安装MySQL docker安装mysql 完整详细教程](https://blog.youkuaiyun.com/qq_40739917/article/details/130891879)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值