【Android】App通信基础架构相关类源码解析
应用通信基础架构相关类源码解析
这里主要对Android App开发时,常用到的一些通信基础类进行一下源码的简单分析,包括:
- Handler:处理器,与某个Looper(一个线程对应一个Looper)进行关联。用于接收消息,并在关联的Looper,处理消息。
- Looper:驱动器,驱动基于事件的消息系统(通信架构的核心)其实现在Native层,基于epoll机制(感兴趣的可自行了解)。
- Runnable: 表示“可执行的代码”,本质是Interface,规定了Run这个接口。
- MessageQueue: 消息队列,提供了入队、出队等操作。一个线程,只能有一个MessageQueue。
- Thread: 线程类,封装了线程相关操作。
基于Android12代码。
类图:
Handler
常见用法
private Handler mHandler = new Handler(Looper.getMainLooper()) {@Overridepublic void handleMessage(Message msg) {// 处理消息}
};private void sendMessage() {// 发送消息Message msg = mHandler.obtainMessage();// 填充msgmHandler.sendMessage(msg);
}private void postRunnable() {// 告知Handler一段可执行的代码(Runnable)mHandler.post(new Runnable() {@Overridepublic void run() {// do something}});
}
通过上述代码中,可以看出。创建Handler时需要绑定Looper,也就是绑定到运行的线程上。如过不指定looper,使用创建handler时所在线程的Looper。
源码定义在 frameworks/base/core/java/android/os/Handler.java
public Handler() {this(null, false);
}public Handler(@NonNull Looper looper) {this(looper, null, false);
}public Handler(@Nullable Callback callback, boolean async) {if (FIND_POTENTIAL_LEAKS) {final Class<? extends Handler> klass = getClass();if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) &&(klass.getModifiers() & Modifier.STATIC) == 0) {Log.w(TAG, "The following Handler class should be static or leaks might occur: " +klass.getCanonicalName());}}// 获取当前线程对应的LoopermLooper = Looper.myLooper();if (mLooper == null) {throw new RuntimeException("Can't create handler inside thread " + Thread.currentThread()+ " that has not called Looper.prepare()");}// 使用Looper中的MessageQueuemQueue = mLooper.mQueue;mCallback = callback;mAsynchronous = async;
}@UnsupportedAppUsage
public Handler(@NonNull Looper looper, @Nullable Callback callback, boolean async) {mLooper = looper;mQueue = looper.mQueue;mCallback = callback;mAsynchronous = async;
}
调用Handler的sendMessage,到Handler处理(handleMessage)这个Message。Handler会将这个Message,入队到绑定的Looper的MessageQueue(消息队列中)。
public final boolean sendMessage(@NonNull Message msg) {// 没有延时 return sendMessageDelayed(msg, 0);
}public final boolean sendMessageDelayed(@NonNull Message msg, long delayMillis) {if (delayMillis < 0) {delayMillis = 0;}return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
}public boolean sendMessageAtTime(@NonNull 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);
}private boolean enqueueMessage(@NonNull MessageQueue queue, @NonNull Message msg,long uptimeMillis) {msg.target = this;// 记录一下UIDmsg.workSourceUid = ThreadLocalWorkSource.getUid();if (mAsynchronous) {msg.setAsynchronous(true);}// 消息入队MessageQueuereturn queue.enqueueMessage(msg, uptimeMillis);
}
Looper从MessageQueue中依次取出Message,并告知Handler的handleMessage处理消息(想要看懂looper,涉及到其Native实现,这里不分析,可自行了解)
Looper
Looper类基于epoll机制,提供了一套事件驱动机制。Java层的实现在frameworks/base/core/java/android/os/Looper.java,该类中的sMainLooper变量存储了 主线程(或者叫UI线程)对应的Looper,可以通过getMainLooper取得。
public final class Looper {private static final String TAG = "Looper";// sThreadLocal.get() will return null unless you've called prepare().@UnsupportedAppUsagestatic final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();@UnsupportedAppUsageprivate static Looper sMainLooper; // guarded by Looper.class// 省略public static Looper getMainLooper() {synchronized (Looper.class) {return sMainLooper;}}
}
常见的用法,比如在自定义的线程中。
public class MyThread extends Thread { private Handler mHandler; @Override public void run() { Looper.prepare(); // 准备Looper mHandler = new Handler() { @Override public void handleMessage(Message msg) { // 处理消息 } } }; Looper.loop(); // 开始循环,等待消息 }
}
Looper的实现这里就不分析了,路径在**/frameworks/base/core/java/android/os/Looper.java**,可自行了解(建议先掌握epoll)
Thread
Android Thread类提供线程功能,其定义在 libcore/ojluni/src/main/java/java/lang/Thread.java
public
class Thread implements Runnable {public Thread() {init(null, null, "Thread-" + nextThreadNum(), 0);}
}
调用start方法,可以启动线程,比如上面定义的MyThread类。
MyThread thr = new MyThread();
thr.start();
其提供了一些方法,用于控制线程,比如
- sleep: 让线程等待一段时间
- jion:等待线程退出(或者叫执行完成)
- interrupt:打断线程。
注意:Thread和Looper是两个事情,其关系是一对一。 Thread就是常规意义上的线程,程序代码最小的运行单位(先不考虑协程),Looper是一套基于消息(事件)的驱动机制。
Runnable是一个接口类,规定了Run这个方法。MessageQueue是一个消息队列。这个类功能比较单一。其源码路径如下,感兴趣的可自行了解。
- /frameworks/base/core/java/android/os/MessageQueue.java
- /libcore/ojluni/src/main/java/java/lang/Runnable.java
再贴一遍类图,加深理解。
相关文章:

【Android】App通信基础架构相关类源码解析
应用通信基础架构相关类源码解析 这里主要对Android App开发时,常用到的一些通信基础类进行一下源码的简单分析,包括: Handler:处理器,与某个Looper(一个线程对应一个Looper)进行关联。用于接…...

06-kafka配置
生产者配置 NAMEDESCRIPTIONTYPEDEFAULTVALID VALUESIMPORTANCEbootstrap.servershost/port列表,用于初始化建立和Kafka集群的连接。列表格式为host1:port1,host2:port2,…,无需添加所有的集群地址,kafka会根据提供的地址发现其他的地址&…...

Git、TortoiseGit、SVN、TortoiseSVN 的关系和区别
Git、TortoiseGit、SVN、TortoiseSVN 的关系和区别 (一)Git(分布式版本控制系统):(二)SVN(集中式版本控制系统)(三)TortoiseGit一、下载安装 git二、安装过程…...

4月5日排序算法总结(1)
冒泡排序 利用每趟都确定出一个最大值或者最小值 如果需要排一个从小到大的数组,那么我们每一趟都要确定一个最大值放在最后,一共有n个数,我们最多需要排列n-1趟就可以了,我们可以改进自己的代码,利用一个flag标记&a…...

Pandas追加写入文件的时候写入到了第一行
# 原代码 def find_money(file_path, account, b_account, money, type_word, time):file pd.read_excel(file_path)with open(money.csv, a, newline, encodingutf-8) as f:for i in file.index:省略中间的代码if 省略中间的代码:file.loc[[i]].to_csv(f,indexFalse)find_sam…...

04---webpack编写可维护的构建配置
01 构建配置抽离成npm包; 意义:通用性: 业务开发者无需关注构建配置 统一团队构建脚本可维护性:构建配置合理的拆分 质量:冒烟测试 单元测试 持续集成构建配置管理的可选方案:1 通过多个配置文件管理不同…...

【云计算】云数据中心网络(一):VPC
云数据中心网络(一):VPC 1.什么是 VPC2.VPC 的组成2.1 虚拟交换机2.2 虚拟路由器 3.VPC 网络规划3.1 VPC 数量规划3.2 交换机数量规划3.3 地址空间规划3.4 不同规模企业地址空间规划实践 4.VPC 网络高可靠设计4.1 单地域单可用区部署4.2 单地…...

自动驾驶中的多目标跟踪_第一篇
自动驾驶中的多目标跟踪:第一篇 多目标跟踪(multi-object/multi-target tracking)的任务包括估计场景中目标的数目、位置(状态)或其他属性,最关键的是需要在一段时间内持续地进行估计。 附赠自动驾驶学习资料和量产经验:链接 应…...

AI爆款文案 巧用AI大模型让文案变现插上翅膀
💂 个人网站:【 摸鱼游戏】【神级代码资源网站】【工具大全】🤟 一站式轻松构建小程序、Web网站、移动应用:👉注册地址🤟 基于Web端打造的:👉轻量化工具创作平台💅 想寻找共同学习交…...

Python入门的60个基础练习(一)
01-Hello World python的语法逻辑完全靠缩进,建议缩进4个空格。如果是顶级代码,那么必须顶格书写,哪怕只有一个空格也会有语法错误。下面示例中,满足if条件要输出两行内容,这两行内容必须都缩进,而且具有相…...

微软云学习环境
微软公有云 - Microsoft Azure 本文介绍通过微软学习中心Microsoft Learn来免费试用Azure上的服务,也不需要绑定信用卡。不过每天只有几个小时的时间。 官网 https://docs.microsoft.com/zh-cn/learn/ 实践 比如创建虚拟机,看到自己的账号下多了Learn的…...

大厂面试:找出数组中第k大的数的最佳算法
一.前置条件 假如数组为a,大小为n,要找到数组a中第k大的数。 二.解决方案 1.使用任意一种排序算法(例如快速排序)将数组a进行从大到小的排序,则第n-k个数即为答案。 2.构造一个长度为k的数组,将前k个数复制过来并降序…...

爬取高校专业信息的Python爬虫简介与实践
1. 介绍 在当前高校专业信息繁多的情况下,选择适合自己的专业成为了许多学生面临的挑战。为了帮助学生更好地了解各高校专业情况,我们开发了一个Python爬虫程序,用于爬取高校专业信息并保存到Excel文件中。本文将详细介绍该爬虫的实现过程以…...

redis 集群模式(redis cluster)介绍
目录 一 redis cluster 相关定义 1, redis cluster 是什么 2,redis 集群的组成 3,集群的作用 4,集群架构图 二 Redis集群的数据分片 1,哈希槽是什么 2,哈希槽如何排布 3,Redis集…...

python实现网络爬虫
网络爬虫是一个自动从互联网上抓取数据的程序。Python有很多库可以帮助我们实现网络爬虫,其中最常用的是requests(用于发送HTTP请求)和BeautifulSoup(用于解析HTML或XML文档)。 以下是一个简单的Python网络爬虫示例&a…...

LeetCode 836. 矩形重叠
解题思路 相关代码 class Solution {public boolean isRectangleOverlap(int[] rec1, int[] rec2) {int x1 rec1[0];int y1 rec1[1];int x2 rec1[2];int y2 rec1[3];int a1 rec2[0];int b1 rec2[1];int a2 rec2[2];int b2 rec2[3];return Math.min(y2,b2)>Math.max…...

为说阿拉伯语的国家进行游戏本地化
阿拉伯语是由超过4亿人使用的语言,并且是二十多个国家的官方语言。进入这些国家的市场并非易事——虽然他们共享一种通用语言,但每个国家都有自己独特的文化,有自己的禁忌和对审查的处理方式。这就是为什么视频游戏公司长期以来都远离阿拉伯语…...

【Python系列】读取 Excel 第一列数据并赋值到指定列
💝💝💝欢迎来到我的博客,很高兴能够在这里和您见面!希望您在这里可以感受到一份轻松愉快的氛围,不仅可以获得有趣的内容和知识,也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学…...

二叉树——存储结构
二叉树的存储结构 二叉树一般可以使用两种结构存储,一种是顺序结构,另一种是链式结构。 一、顺序存储 二叉树的顺序存储是指用一组连续的存储单元依次自上而下、自左至右存储完全二叉树上的结点元素,即将完全二叉树上编号为i的结点元素存储…...

LangChain - OpenGPTs
文章目录 MessageGraph 消息图认知架构AssistantsRAGChatBot 持久化配置新模型新工具astream_events总结 关键链接: OpenGPT GitHub 存储库YouTube 上的 OpenGPT 演练LangGraph:Python、JS 两个多月前,在 OpenAI 开发日之后,我们…...

pe格式从入门到图形化显示(四)-节表
文章目录 前言一、什么是Windows PE格式节表?二、解析节表并显示1.节表数据结构以及字段描述2.节表的属性3.解析4.显示 前言 通过分析和解析Windows PE格式,并使用qt进行图形化显示 一、什么是Windows PE格式节表? PE格式的节表(…...

路由策略与路由控制之双点双向重发布(OSPF-ISIS)实验
双点双向重发布在路由协议中,特别是在OSPF(开放式最短路径优先)与IS-IS(中间系统到中间系统)等协议之间,指的是在两个协议间或者两个进程间进行路由信息共享的机制。这种机制涉及到在两个不同的协议区域使用…...

9proxy—数据采集工具全面测评
9Proxy数据采集工具Unlock the web with 9Proxy, the top residential proxy provider. Get unlimited bandwidth, affordable prices, and secure HTTPS and Socks5 configurations.https://9proxy.com/?utm_sourceblog&utm_mediumcsdn&utm_campaignyan 前言 在当今数…...

上海晶珩树莓派工业智能机械臂,亮相2024年embedded world博览会!
上海晶珩树莓派工业智能机械臂,亮相2024年embedded world博览会! 工业智能机械臂是上海晶珩(EDATEC)团队基于树莓派工业相机ED-AIC2000和树莓派工业触摸屏ED-HMI2320开发的创新应用案例。 工业智能机械臂具备卓越的定位能力&…...

蓝桥杯——求和
题目 给定 n 个整数 a1, a2,…,an,求它们两两相乘再相加的和即: Sa1a2a1a3a1ana2a3 a(n-2)*an...a(n-1)*an 输入格式 输入的第一行包含一个整数 n。 第二行包含 几 个整数 a1,a2,,an。 输出格式 输出一个整数 S,表示所…...

设计模式:责任链模式示例
责任链模式可以应用于多种场景,下面是几个不同场景的例子,每个例子都包括完整的代码。 示例1:日志处理系统 在日志处理系统中,日志消息可以根据其严重性(错误、警告、信息)被不同级别的日志处理器处理。 …...

SpringBoot快速入门笔记(4)
文章目录 一、Vue框架1、前端环境准备2、简介3、快速开始4、事件绑定 二、Vue组件化开发1、NPM2、Vue Cli3、组件化开发4、SayHello自定义组件5、Movie自定义组件 一、Vue框架 1、前端环境准备 编码工具:VSCode 依赖管理:NPM 项目构建:VueCl…...

GoPro相机使用的文件格式和频率
打开GoPro相机(以11为例),里面是一个DCIM文件夹。 DCIM是digital camera in memory 的简写,即存照片的文件夹,常见于数码相机、手机存储卡中的文件夹名字。 正常手机拍照和视频都是保存在此文件夹的。正常建议不用删,因为只要拍照…...

Redis Stack 安装部署
参考:Run Redis Stack on Docker | Redis Redis-stack 初体验_redis stack-CSDN博客 【docker】运行redis_docker run redis-stack-server requirepass-CSDN博客 Redis Stack 是一组软件套件,它主要由三部分组成。 一个是 Redis Stack Server&#x…...

【经典算法】LeetCode 5: 最长回文子串(Java/C/Python3实现含注释说明,Medium)
目录 题目描述思路及实现方式一:动态规划法思路代码实现Java版本C语言版本Python3版本 复杂度分析 方式二:中心扩展法思路代码实现Java版本C语言版本Python3版本 复杂度分析 总结相似题目 标签(题目类型):回文串、动态规划 题目描述 给定一…...