news 2026/6/15 17:55:02

从 C 链表到 Android Looper:MessageQueue 的底层原理一条线讲透

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
从 C 链表到 Android Looper:MessageQueue 的底层原理一条线讲透

前言:为什么要从 C 链表讲起?

很多 Android 开发者都用过Handler / Looper / MessageQueue
但一深入源码就会觉得“抽象、复杂、难以下手”。

其实问题不在 Android,而在于我们没把底层模型串起来

如果你愿意退回一步,用C 语言最基础的数据结构视角去看,就会发现:

Android 的消息机制,本质就是:
链表 + 队列 + 排序 + 阻塞循环。

本文尝试做一件事:
👉从 C 语言的链表出发,一步一步推导到 Android 的 MessageQueue / Looper
把这条逻辑链完整走一遍。

一、指针的本质:一切从“地址”开始

在 C 语言中:

int x = 10; int *p = &x;
  • x是一个值
  • &x是 x 的内存地址
  • p是一个存地址的变量
  • *p表示“通过地址访问那块内存里的值”

指针 = 存地址的变量

这是后面所有数据结构的根基。

这一点非常重要,因为:

  • 链表
  • 队列
  • MessageQueue
  • Looper

全部建立在“地址关系”之上。

二、为什么需要 struct?

单个变量无法表达复杂对象,我们需要把“相关数据”组织在一起:

struct Person { int age; int height; };

struct的本质只是:
👉一块内存的布局说明书

它本身并不负责逻辑。

三、Node:链表的最小原子结构

链表的核心是Node

typedef struct Node { void *data; // 指向真实数据 struct Node *next; // 指向下一个节点 } Node;

这里有两个完全不同层次的指针:

  • data业务数据指针

  • next结构关系指针

一句话总结:

Node = 数据 + 指向下一个 Node 的关系

多个 Node 通过next串起来,就形成了链表:

Node1 -> Node2 -> Node3 -> NULL

四、为什么“只有 Node”是没用的?

此时会遇到一个致命问题:

👉从哪里开始遍历?

链表必须有一个“入口”,也必须有人维护整体状态。

五、Queue:Node 的管理者(系统思维的起点)

于是我们引入“管理结构”:

typedef struct { Node *head; Node *tail; int size; } Queue;

现在结构关系变成:

Queue ├── head ──> Node ──> Node ──> Node ──> NULL ├── tail ────────────────────────────┘ └── size

注意一个非常重要的事实:

Queue 自己不存数据,它只负责“管理 Node 的关系”。

这是从“数据结构”走向“系统设计”的第一步。

六、为什么Queue*不需要二级指针?

初始化 Queue 通常这样写:

Queue q; queue_init(&q);
void queue_init(Queue *q) { q->head = NULL; q->tail = NULL; q->size = 0; }

这里:

  • q本体已经存在(在栈上)

  • 函数只是修改Queue内部字段

  • 并没有修改指针变量本身

所以:
👉一级指针足够

七、什么时候才需要二级指针?

只有一种情况:

当函数需要“创建 / 替换一个指针变量本身”

void create_queue(Queue **pq) { *pq = malloc(sizeof(Queue)); }

调用方式:

Queue *q = NULL; create_queue(&q);

这里的本质是:

  • q是一个Queue*指针变量

  • &q的类型是Queue**

  • Queue**正好能“接住”&q

  • *pq = malloc(...)本质是给q重新赋值

👉二级指针的本质是“类型匹配 + 写回指针变量”

八、从 Queue 到 MessageQueue:关键差异只有一个

普通 Queue 是FIFO

Android 的 MessageQueue 不一样,它是:

按执行时间排序的消息队列

因此 Node 演化为 Message:

typedef struct Message { long when; // 什么时候执行 void (*callback)(void); // 要执行的任务 struct Message *next; } Message;

你会发现:

  • 结构没变

  • 指针没变

  • 只是数据字段更“业务化”

九、MessageQueue 的核心职责

MessageQueue 主要做三件事:

  1. when有序插入 Message

  2. 维护单向链表

  3. 提供next()获取“当前可执行的消息”

它不是简单的队列,而是“时间有序链表”。

十、Looper:系统的“心跳循环”

Looper 的逻辑可以简化成一句话:

for (;;) { Message *msg = queue.next(); dispatch(msg); }

也就是说:

Looper = 无限循环 + 从 MessageQueue 取消息并执行

这就是 Android UI 线程的“发动机”。

十一、为什么 Looper 不会空转卡死?

关键在MessageQueue.next()

  • 如果队列为空

  • 或最近一条消息还没到执行时间

👉线程进入阻塞状态

当:

  • 新消息入队

  • 或时间到达

👉线程被唤醒

因此:

next() ≠ pop()
next() = “能执行才返回,否则阻塞等待”

这是系统层设计的精髓。

十二、完整映射关系一览

C 世界Android 世界
NodeMessage
next 指针Message.next
QueueMessageQueue
for(;;)Looper.loop()
阻塞等待native poll / wake
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/6/14 21:00:06

隧道气象站:守护隧道安全运行的“智慧哨兵”

隧道作为特殊的交通通道,其内部气象环境与外界差异显著,且对行车安全影响极大。隧道气象站作为专门针对隧道环境设计的气象监测系统,能够实时、精准地捕捉隧道内的关键气象参数,为隧道的安全运营提供重要保障。隧道气象站可监测多…

作者头像 李华
网站建设 2026/6/14 18:11:04

线性代数-同济大学第七版 资源下载

线性代数-同济大学第七版 资源下载 【免费下载链接】线性代数-同济大学第七版资源下载 本仓库提供《线性代数-同济大学第七版》的资源文件下载。该资源文件包含了同济大学第七版线性代数教材的完整内容,适用于学习线性代数的学生和教师使用 项目地址: https://git…

作者头像 李华
网站建设 2026/6/15 13:10:24

如何实现300%性能提升?Accelerate分布式推理全攻略

如何实现300%性能提升?Accelerate分布式推理全攻略 【免费下载链接】accelerate 🚀 A simple way to train and use PyTorch models with multi-GPU, TPU, mixed-precision 项目地址: https://gitcode.com/gh_mirrors/ac/accelerate 还在为千亿参…

作者头像 李华
网站建设 2026/6/15 15:11:51

芯片电源完整性效应对信号完整性影响的种类及其分析

“电源感知分析”和“SI/PI联合仿真”正迅速成为行业常用术语,在讨论这些概念时,往往会涉及多种不同的现象,但这些现象有时会被混淆,且常常出现理解偏差。这种混淆的产生是因为电源分配网络(PDN)与信号完整…

作者头像 李华
网站建设 2026/6/15 5:28:55

41、资源管理与应用实用函数解析

资源管理与应用实用函数解析 资源管理器功能 在资源管理中,有一系列实用的函数可用于搜索、存储和枚举资源数据库中的条目。 资源搜索 当使用 XrmQGetSearchList 后接着对具有相同名称和类前缀的资源进行多次探测时,在传递给 XrmQGetSearchList 的名称和类列表中,只…

作者头像 李华
网站建设 2026/6/15 13:44:41

计算机毕设项目之基于Springboot Vue的竞赛管理系统

系统功能介绍(高校竞赛管理系统)一、系统概述本系统基于 Spring Boot Vue Element UI 实现,面向高校的竞赛组织与管理场景,提供从赛事发布、报名、预约、提交、评审、奖项管理到公告与交流的完整闭环管理能力,并区分…

作者头像 李华