惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

V
Vulnerabilities – Threatpost
V
V2EX
GbyAI
GbyAI
Recent Announcements
Recent Announcements
Microsoft Security Blog
Microsoft Security Blog
阮一峰的网络日志
阮一峰的网络日志
Hugging Face - Blog
Hugging Face - Blog
T
Tailwind CSS Blog
Y
Y Combinator Blog
C
Check Point Blog
爱范儿
爱范儿
CTFtime.org: upcoming CTF events
CTFtime.org: upcoming CTF events
美团技术团队
雷峰网
雷峰网
IT之家
IT之家
WordPress大学
WordPress大学
V
Visual Studio Blog
Microsoft Azure Blog
Microsoft Azure Blog
MyScale Blog
MyScale Blog
N
News and Events Feed by Topic
罗磊的独立博客
S
SegmentFault 最新的问题
S
Security Affairs
aimingoo的专栏
aimingoo的专栏
F
Fortinet All Blogs
K
KPMG report finds enterprise disconnect between AI and its ROI | CIO
Exploit-DB.com RSS Feed
Exploit-DB.com RSS Feed
H
Hacker News: Front Page
Google DeepMind News
Google DeepMind News
B
Blog
O
OpenAI News
C
Cisco Blogs
Simon Willison's Weblog
Simon Willison's Weblog
The Last Watchdog
The Last Watchdog
Hacker News: Ask HN
Hacker News: Ask HN
博客园_首页
人人都是产品经理
人人都是产品经理
C
Cybersecurity and Infrastructure Security Agency CISA
Recent Commits to openclaw:main
Recent Commits to openclaw:main
Help Net Security
Help Net Security
月光博客
月光博客
J
Java Code Geeks
L
LangChain Blog
博客园 - 司徒正美
Stack Overflow Blog
Stack Overflow Blog
Security Archives - TechRepublic
Security Archives - TechRepublic
Apple Machine Learning Research
Apple Machine Learning Research
T
The Exploit Database - CXSecurity.com
N
News and Events Feed by Topic
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More

美团技术团队

美团 · 技术团队 美团 · 技术团队 美团 · 技术团队 美团 · 技术团队 美团 · 技术团队 美团 · 技术团队 美团发布基于 N-gram 全新模型:嵌入扩展新范式,实现轻量化 MoE 高效进化 2025美团技术年货,「马」上到来 多维创新打造强泛化智能体模型,LongCat-Flash-Thinking-2601技术报告发布 美团 EvoCUA 刷新开源 SOTA,会用电脑还会持续进化的智能体! 美团 LongCat-Flash-Thinking-2601 发布,工具调用能力登顶开源 SOTA! KuiTest:基于大模型通识的 UI 交互遍历测试 AAAI 2026 | 美团技术团队学术论文精选 2025 | 美团技术团队热门技术文章汇总 美团 LongCat-Video-Avatar 正式发布,实现开源 SOTA 级拟真表现 大模型剪枝新范式:先浓缩,再剪枝——DenoiseRotator技术解读 LongCat 上线 AI 生图!精准高效,AI 创作不设限 美团发布 LongCat-Image 图像生成模型,编辑能力登顶开源 SOTA AI Coding与单元测试的协同进化:从验证到驱动 R-HORIZON:探索长程推理边界,复旦NLP&美团LongCat联合提出LRMs能力评测新框架 美团 LongCat 发布 AMO-Bench:突破 AIME 评测饱和困境,重新定义 LLM 数学上限 美团 LongCat Interaction 团队发布大模型交互系统技术报告 WOWService 美团 LongCat 团队发布全模态一站式评测基准 UNO-Bench 美团开源LongCat-Audio-Codec,高效语音编解码器助力实时交互落地 NeurIPS 2025 | 美团技术团队论文精选 LongCat-Flash-Omni正式发布并开源:开启全模态实时交互时代 美团 LongCat 团队发布 VitaBench:基于复杂生活场景的交互式 Agent 评测基准 LongCat-Video 视频生成模型正式发布,探索世界模型的第一步 ICCV 2025 | 美团论文精选及多模态推理竞赛冠军方法分享 从0到1建设美团数据库容量评估系统 可验证过程奖励在提升大模型推理效率中的探索与实践 LongCat-Flash-Thinking 正式发布,更强、更专业,保持极速! 开源 | InfiniteTalk:无限长虚拟人视频生成的新范式 美团正式发布并开源 LongCat-Flash-Chat,动态计算开启高效 AI 时代 美团 M17 团队开源 Meeseeks 评测集:揭秘大模型的“听话”能力 可信实验白皮书系列08:开放式分析引擎 | 附PDF合集 美团智能头盔研发实践系列02:软件功能篇 美团智能头盔研发实践系列01:硬件设计篇 ACL 2025 | 美团技术团队论文精选 美团开源OIBench与CoreCodeBench:揭示大模型编程能力的真实水平 可信实验白皮书系列07:高阶实验工具 开源 | MeiGen-MultiTalk:基于单张照片实现多人互动演绎 可信实验白皮书系列06:观察性研究 JDK高版本特性总结与ZGC实践 可信实验白皮书系列05:准实验 可信实验白皮书系列04:随机轮转实验 可信实验白皮书系列03:随机对照实验 可信实验白皮书系列02:AB实验基础 可信实验白皮书系列01:从0到1的方法论与实践指南 MTGR:美团外卖生成式推荐Scaling Law落地实践 OR算法+ML模型混合推理框架架构演进 ICLR&CVPR 2025美团技术团队论文精选 行为正则化与顺序策略优化结合的离线多智能体学习算法 预测技术在美团弹性伸缩场景的探索与应用 美团技术年货 | 600+页电子书,算法、工程、测试、数据、安全系列大合集 鸿蒙应用签名实操及机制探究 2024 | 美团技术团队热门技术文章汇总 AutoConsis:UI内容一致性智能检测 CIKM 2024 | 美团技术团队精选论文解读 大前端:如何突破动态化容器的天花板? KDD 2024 OAG-Challenge Cup赛道三项冠军技术方案解读 新一代实验分析引擎:驱动履约平台的数据决策 大众点评技术部包揽KDD 2024 OAG-Challenge Cup赛道全部3项冠军 ACL 2024 | 美团技术团队精选论文解读 KDD 2024 | 美团技术团队精选论文解读 基本功 | 一文讲清多线程和多线程同步 小程序可测性能力建设与实践 SIGIR 2024 | 美团技术团队精选论文解读 Spark向量化计算在美团生产环境的实践 CVPR 2024 | 美团技术团队精选论文解读 基于多模态信息抽取的菜品知识图谱构建 DDD在大众点评交易系统演进中的应用 美团外卖基于GPU的向量检索系统实践 美团大规模KV存储挑战与架构实践 基于接口数据变异的App健壮性测试实践 美团技术年货 | 600+页电子书,前端、后端、算法、测试、运维系列大合集 美团RASP大规模研发部署实践总结 2023 | 美团技术团队热门技术文章汇总 美团到店终端从标准化到数字化的演进之路 AIOps在美团的探索与实践——事件管理篇 美团技术博客十周年,感谢一路相伴 基于UI交互意图理解的异常检测方法 如何利用「深度上下文兴趣网络」提升点击率? 基于模式挖掘的可靠性治理探索 代码变更风险可视化系统建设与实践 美团多场景建模的探索与实践 MJDK 如何实现压缩速率的 5 倍提升? 如何提供一个可信的AB测试解决方案 KDD 2023 | 美团技术团队精选论文解读 美团前端研发框架Rome实践和演进趋势 斩获CVPR 2023竞赛2项冠军|美团街景理解中视觉分割技术的探索与应用 MySQL自治平台建设的内核原理及实践(下) CVPR 2023 | 美团技术团队精选论文解读 超大规模数据库集群保稳系列之三:美团数据库容灾体系建设实践 超大规模数据库集群保稳系列之二:数据库攻防演练建设实践 Robust 2.0:支持Android R8的升级版热修复框架 超大规模数据库集群保稳系列之一:高可用系统 一次「找回」TraceId的问题分析与过程思考 基于AI+数据驱动的慢查询索引推荐 SOTA!目标检测开源框架YOLOv6 3.0版本来啦
Android组件化方案及组件消息总线modular-event实战
海亮 · 2018-12-20 · via 美团技术团队

背景

组件化作为Android客户端技术的一个重要分支,近年来一直是业界积极探索和实践的方向。美团内部各个Android开发团队也在尝试和实践不同的组件化方案,并且在组件化通信框架上也有很多高质量的产出。最近,我们团队对美团零售收银和美团轻收银两款Android App进行了组件化改造。本文主要介绍我们的组件化方案,希望对从事Android组件化开发的同学能有所启发。

为什么要组件化

近年来,为什么这么多团队要进行组件化实践呢?组件化究竟能给我们的工程、代码带来什么好处?我们认为组件化能够带来两个最大的好处。

提高组件复用性

可能有些人会觉得,提高复用性很简单,直接把需要复用的代码做成Android Module,打包AAR并上传代码仓库,那么这部分功能就能被方便地引入和使用。但是我们觉得仅仅这样是不够的,上传仓库的AAR库是否方便被复用,需要组件化的规则来约束,这样才能提高复用的便捷性。

降低组件间的耦合

我们需要通过组件化的规则把代码拆分成不同的模块,模块要做到高内聚、低耦合。模块间也不能直接调用,这需要组件化通信框架的支持。降低了组件间的耦合性可以带来两点直接的好处:第一,代码更便于维护;第二,降低了模块的Bug率。

组件化之前的状态

我们的目标是要对团队的两款App(美团零售收银、美团轻收银)进行组件化重构,那么这里先简单地介绍一下这两款应用的架构。

总的来说,这两款应用的构架比较相似,主工程Module依赖Business Module,Business Module是各种业务功能的集合,Business Module依赖Service Module,Service Module依赖Platform Module,Service Module和Platform Module都对上层提供服务。

有所不同的是Platform Module提供的服务更为基础,主要包括一些工具Utils和界面Widget,而Service Module提供各种功能服务,如KNB、位置服务、网络接口调用等。这样的话,Business Module就变得非常臃肿和繁杂,各种业务模块相互调用,耦合性很强,改业务代码时容易“牵一发而动全身”,即使改一小块业务代码,可能要连带修改很多相关的地方,不仅在代码层面不利于进行维护,而且对一个业务的修改很容易造成其他业务产生Bug。

组件化之前的状态

组件化方案调研

为了得到最适合我们业态和构架的组件化方案,我们调研了业界开源的一些组件化方案和公司内部其他团队的组件化方案,在此做个总结。

开源组件化方案调研

我们调研了业界一些主流的开源组件化方案。

号称业界首个支持渐进式组件化改造的Android组件化开源框架。无论页面跳转还是组件间调用,都采用CC统一的组件调用方式完成。

得到的方案采用路由 + 接口下沉的方式,所有接口下沉到base中,组件中实现接口并在IApplicationLike中添加代码注册到Router中。

组件间调用需指定同步实现还是异步实现,调用组件时统一拿到RouterResponse作为返回值,同步调用的时候用RouterResponse.getData()来获取结果,异步调用获取时需要自己维护线程。

阿里推出的路由引擎,是一个路由框架,并不是完整的组件化方案,可作为组件化架构的通信引擎。

聚美的路由引擎,在此基础上也有聚美的组件化实践方案,基本思想是采用路由 + 接口下沉的方式实现组件化。

美团其他团队组件化方案调研

美团收银ComponentCenter

美团收银的组件化方案支持接口调用和消息总线两种方式,接口调用的方式需要构建CCPData,然后调用ComponentCenter.call,最后在统一的Callback中进行处理。消息总线方式也需要构建CCPData,最后调用ComponentCenter.sendEvent发送。美团收银的业务组件都打包成AAR上传至仓库,组件间存在相互依赖,这样导致mainapp引用这些组件时需要小心地exclude一些重复依赖。在我们的组件化方案中,我们采用了一种巧妙的方法来解决这个问题。

美团App ServiceLoader

美团App的组件化方案采用ServiceLoader的形式,这是一种典型的接口调用组件通信方式。用注解定义服务,获取服务时取得一个接口的List,判断这个List是否为空,如果不为空,则获取其中一个接口调用。

WMRouter

美团外卖团队开发的一款Android路由框架,基于组件化的设计思路。主要提供路由、ServiceLoader两大功能。之前美团技术博客也发表过一篇WMRouter的介绍:《WMRouter:美团外卖Android开源路由框架》。WMRouter提供了实现组件化的两大基础设施框架:路由和组件间接口调用。支持和文档也很充分,可以考虑作为我们团队实现组件化的基础设施。

组件化方案

组件化基础框架

在前期的调研工作中,我们发现外卖团队的WMRouter是一个不错的选择。首先,WMRouter提供了路由+ServiceLoader两大组件间通信功能,其次,WMRouter架构清晰,扩展性比较好,并且文档和支持也比较完备。所以我们决定了使用WMRouter作为组件化基础设施框架之一。然而,直接使用WMRouter有两个问题:

  1. 我们的项目已经在使用一个路由框架,如果使用WMRouter,需要把之前使用的路由框架改成WMRouter路由框架。
  2. WMRouter没有消息总线框架,我们调研的其他项目也没有适合我们项目的消息总线框架,因此我们需要开发一个能够满足我们需求的消息总线框架,这部分会在后面详细描述。

组件化分层结构

在参考了不同的组件化方案之后,我们采用了如下分层结构:

  1. App壳工程:负责管理各个业务组件和打包APK,没有具体的业务功能。
  2. 业务组件层:根据不同的业务构成独立的业务组件,其中每个业务组件包含一个Export Module和Implement Module。
  3. 功能组件层:对上层提供基础功能服务,如登录服务、打印服务、日志服务等。
  4. 组件基础设施:包括WMRouter,提供页面路由服务和ServiceLoader接口调用服务,以及后面会介绍的组件消息总线框架:modular-event。

整体架构如下图所示:

分层结构

业务组件拆分

我们调研其他组件化方案的时候,发现很多组件方案都是把一个业务模块拆分成一个独立的业务组件,也就是拆分成一个独立的Module。而在我们的方案中,每个业务组件都拆分成了一个Export Module和Implement Module,为什么要这样做呢?

1. 避免循环依赖

如果采用一个业务组件一个Module的方式,如果Module A需要调用Module B提供的接口,那么Module A就需要依赖Module。同时,如果Module B需要调用Module A的接口,那么Module B就需要依赖Module A。此时就会形成一个循环依赖,这是不允许的。

循环依赖

也许有些读者会说,这个好解决:可以把Module A和Module B要依赖的接口放到另一个Module中去,然后让Module A和Module B都去依赖这个Module就可以了。这确实是一个解决办法,并且有些项目组在使用这种把接口下沉的方法。

但是我们希望一个组件的接口,是由这个组件自己提供,而不是放在一个更加下沉的接口里面,所以我们采用了把每个业务组件都拆分成了一个Export Module和Implement Module。这样的话,如果Module A需要调用Module B提供的接口,同时Module B需要调用Module A的接口,只需要Module A依赖Module B Export,Module B依赖Module A Export就可以了。

组件结构

2. 业务组件完全平等

在使用单Module方案的组件化方案中,这些业务组件其实不是完全平等,有些被依赖的组件在层级上要更下沉一些。但是采用Export Module+Implement Module的方案,所有业务组件在层级上完全平等。

3. 功能划分更加清晰

每个业务组件都划分成了Export Module+Implement Module的模式,这个时候每个Module的功能划分也更加清晰。Export Module主要定义组件需要对外暴露的部分,主要包含:

  • 对外暴露的接口,这些接口用WMRouter的ServiceLoader进行调用。
  • 对外暴露的事件,这些事件利用消息总线框架modular-event进行订阅和分发。
  • 组件的Router Path,组件化之前的工程虽然也使用了Router框架,但是所有Router Path都是定义在了一个下沉Module的公有Class中。这样导致的问题是,无论哪个模块添加/删除页面,或是修改路由,都需要去修改这个公有的Class。设想如果组件化拆分之后,某个组件新增了页面,还要去一个外部的Java文件中新增路由,这显然难以接受,也不符合组件化内聚的目标。因此,我们把每个组件的Router Path放在组件的Export Module中,既可以暴露给其他组件,也可以做到每个组件管理自己的Router Path,不会出现所有组件去修改一个Java文件的窘境。

Implement Module是组件实现的部分,主要包含:

  • 页面相关的Activity、Fragment,并且用WMRouter的注解定义路由。
  • Export Module中对外暴露的接口的实现。
  • 其他的业务逻辑。

组件功能划分

组件化消息总线框架modular-event

前文提到的实现组件化基础设施框架中,我们用外卖团队的WMRouter实现页面路由和组件间接口调用,但是却没有消息总线的基础框架,因此,我们自己开发了一个组件化消息总线框架modular-event。

为什么需要消息总线框架

之前,我们开发过一个基于LiveData的消息总线框架:LiveDataBus,也在美团技术博客上发表过一篇文章来介绍这个框架:《Android消息总线的演进之路:用LiveDataBus替代RxBus、EventBus》。关于消息总线的使用,总是伴随着很多争论。有些人觉得消息总线很好用,有些人觉得消息总线容易被滥用。

既然已经有了ServiceLoader这种组件间接口调用的框架,为什么还需要消息总线这种方式呢?主要有两个理由。

1. 更进一步的解耦

基于接口调用的ServiceLoader框架的确实现了解耦,但是消息总线能够实现更彻底的解耦。接口调用的方式调用方需要依赖这个接口并且知道哪个组件实现了这个接口。消息总线方式发送者只需要发送一个消息,根本不用关心是否有人订阅这个消息,这样发送者根本不需要了解其他组件的情况,和其他组件的耦合也就越少。

2. 多对多的通信

基于接口的方式只能进行一对一的调用,基于消息总线的方式能够提供多对多的通信。

消息总线的优点和缺点

总的来说,消息总线最大的优点就是解耦,因此很适合组件化这种需要对组件间进行彻底解耦的场景。然而,消息总线被很多人诟病的重要原因,也确实是因为消息总线容易被滥用。消息总线容易被滥用一般体现在几个场景:

1. 消息难以溯源

有时候我们在阅读代码的过程中,找到一个订阅消息的地方,想要看看是谁发送了这个消息,这个时候往往只能通过查找消息的方式去“溯源”。导致我们在阅读代码,梳理逻辑的过程不太连贯,有种被割裂的感觉。

2. 消息发送比较随意,没有强制的约束

消息总线在发送消息的时候一般没有强制的约束。无论是EventBus、RxBus或是LiveDataBus,在发送消息的时候既没有对消息进行检查,也没有对发送调用进行约束。这种不规范性在特定的时刻,甚至会带来灾难性的后果。比如订阅方订阅了一个名为login_success的消息,编写发送消息的是一个比较随意的程序员,没有把这个消息定义成全局变量,而是定义了一个临时变量String发送这个消息。不幸的是,他把消息名称login_success拼写成了login_seccess。这样的话,订阅方永远接收不到登录成功的消息,而且这个错误也很难被发现。

组件化消息总线的设计目标

1. 消息由组件自己定义

以前我们在使用消息总线时,喜欢把所有的消息都定义到一个公共的Java文件里面。但是组件化如果也采用这种方案的话,一旦某个组件的消息发生变动,都会去修改这个Java文件。所以我们希望由组件自己来定义和维护消息定义文件。

2. 区分不同组件定义的同名消息

如果消息由组件定义和维护,那么有可能不同组件定义了重名的消息,消息总线框架需要能够区分这种消息。

3. 解决前文提到的消息总线的缺点

解决消息总线消息难以溯源和消息发送没有约束的问题。

基于LiveData的消息总线

之前的博文《Android消息总线的演进之路:用LiveDataBus替代RxBus、EventBus》详细阐述了如何基于LiveData构建消息总线。组件化消息总线框架modular-event同样会基于LiveData构建。使用LiveData构建消息总线有很多优点:

  1. 使用LiveData构建消息总线具有生命周期感知能力,使用者不需要调用反注册,相比EventBus和RxBus使用更为方便,并且没有内存泄漏风险。
  2. 使用普通消息总线,如果回调的时候Activity处于Stop状态,这个时候进行弹Dialog一类的操作就会引起崩溃。使用LiveData构建消息总线完全没有这个风险。

组件消息总线modular-event的实现

解决不同组件定义了重名消息的问题

其实这个问题还是比较好解决的,实现的方式就是采用两级HashMap的方式解决。第一级HashMap的构建以ModuleName作为Key,第二级HashMap作为Value;第二级HashMap以消息名称EventName作为Key,LiveData作为Value。查找的时候先用组件名称ModuleName在第一级HashMap中查找,如果找到则用消息名EventName在第二级HashName中查找。整个结构如下图所示:

消息总线结构

对消息总线的约束

我们希望消息总线框架有以下约束:

  1. 只能订阅和发送在组件中预定义的消息。换句话说,使用者不能发送和订阅临时消息。
  2. 消息的类型需要在定义的时候指定。
  3. 定义消息的时候需要指定属于哪个组件。

如何实现这些约束

  1. 在消息定义文件上使用注解,定义消息的类型和消息所属Module。
  2. 定义注解处理器,在编译期间收集消息的相关信息。
  3. 在编译器根据消息的信息生成调用时需要的interface,用接口约束消息发送和订阅。
  4. 运行时构建基于两级HashMap的LiveData存储结构。
  5. 运行时采用interface+动态代理的方式实现真正的消息订阅和发送。

整个流程如下图所示:

实现流程

消息总线modular-event的结构

  • modular-event-base:定义Anotation及其他基本类型
  • modular-event-core:modular-event核心实现
  • modular-event-compiler:注解处理器
  • modular-event-plugin:Gradle Plugin

Anotation

  • @ModuleEvents:消息定义
@Retention(RetentionPolicy.SOURCE)
@Target(ElementType.TYPE)
public @interface ModuleEvents {
    String module() default "";
}
  • @EventType:消息类型
@Retention(RetentionPolicy.SOURCE)
@Target(ElementType.FIELD)
public @interface EventType {
    Class value();
}

消息定义

通过@ModuleEvents注解一个定义消息的Java类,如果@ModuleEvents指定了属性module,那么这个module的值就是这个消息所属的Module,如果没有指定属性module,则会把定义消息的Java类所在的包的包名作为消息所属的Module。

在这个消息定义java类中定义的消息都是public static final String类型。可以通过@EventType指定消息的类型,@EventType支持java原生类型或自定义类型,如果没有用@EventType指定消息类型,那么消息的类型默认为Object,下面是一个消息定义的示例:

//可以指定module,若不指定,则使用包名作为module名
@ModuleEvents()
public class DemoEvents {

    //不指定消息类型,那么消息的类型默认为Object
    public static final String EVENT1 = "event1";

    //指定消息类型为自定义Bean
    @EventType(TestEventBean.class)
    public static final String EVENT2 = "event2";

    //指定消息类型为java原生类型
    @EventType(String.class)
    public static final String EVENT3 = "event3";
}

interface自动生成

我们会在modular-event-compiler中处理这些注解,一个定义消息的Java类会生成一个接口,这个接口的命名是EventsDefineOf+消息定义类名,例如消息定义类的类名为DemoEvents,自动生成的接口就是EventsDefineOfDemoEvents。消息定义类中定义的每一个消息,都会转化成接口中的一个方法。使用者只能通过这些自动生成的接口使用消息总线。我们用这种巧妙的方式实现了对消息总线的约束。前文提到的那个消息定义示例DemoEvents.java会生成一个如下的接口类:

package com.sankuai.erp.modularevent.generated.com.meituan.jeremy.module_b_export;

public interface EventsDefineOfDemoEvents extends com.sankuai.erp.modularevent.base.IEventsDefine {
  com.sankuai.erp.modularevent.Observable<java.lang.Object> EVENT1();

  com.sankuai.erp.modularevent.Observable<com.meituan.jeremy.module_b_export.TestEventBean> EVENT2(
      );

  com.sankuai.erp.modularevent.Observable<java.lang.String> EVENT3();
}

关于接口类的自动生成,我们采用了square/javapoet来实现,网上介绍JavaPoet的文章很多,这里就不再累述。

使用动态代理实现运行时调用

有了自动生成的接口,就相当于有了一个壳,然而壳下面的所有逻辑,我们通过动态代理来实现,简单介绍一下代理模式和动态代理:

  • 代理模式: 给某个对象提供一个代理对象,并由代理对象控制对于原对象的访问,即客户不直接操控原对象,而是通过代理对象间接地操控原对象。
  • 动态代理: 代理类是在运行时生成的。也就是说Java编译完之后并没有实际的class文件,而是在运行时动态生成的类字节码,并加载到JVM中。

在动态代理的InvocationHandler中实现查找逻辑:

  1. 根据interface的typename得到ModuleName。
  2. 调用的方法的methodname即为消息名。
  3. 根据ModuleName和消息名找到相应的LiveData。
  4. 完成后续订阅消息或者发送消息的流程。

消息的订阅和发送可以用链式调用的方式编码:

  • 订阅消息
ModularEventBus
        .get()
        .of(EventsDefineOfModuleBEvents.class)
        .EVENT1()
        .observe(this, new Observer<TestEventBean>() {
            @Override
            public void onChanged(@Nullable TestEventBean testEventBean) {
                Toast.makeText(MainActivity.this, "MainActivity收到自定义消息: " + testEventBean.getMsg(),
                        Toast.LENGTH_SHORT).show();
            }
        });
  • 发送消息
ModularEventBus
        .get()
        .of(EventsDefineOfModuleBEvents.class)
        .EVENT1()
        .setValue(new TestEventBean("aa"));

订阅和发送的模式

  • 订阅消息的模式

    1. observe:生命周期感知,onDestroy的时候自动取消订阅。
    2. observeSticky:生命周期感知,onDestroy的时候自动取消订阅,Sticky模式。
    3. observeForever:需要手动取消订阅。
    4. observeStickyForever:需要手动取消订阅,Sticky模式。
  • 发送消息的模式

    1. setValue:主线程调用。
    2. postValue:后台线程调用。

总结

本文介绍了美团行业收银研发组Android团队的组件化实践,以及强约束组件消息总线modular-event的原理和使用。我们团队很早之前就在探索组件化改造,前期有些方案在落地的时候遇到很多困难。我们也研究了很多开源的组件化方案,以及公司内部其他团队(美团App、美团外卖、美团收银等)的组件化方案,学习和借鉴了很多优秀的设计思想,当然也踩过不少的坑。我们逐渐意识到:任何一种组件化方案都有其适用场景,我们的组件化架构选择,应该更加面向业务,而不仅仅是面向技术本身。

后期工作展望

我们的组件化改造工作远远没有结束,未来可能会在以下几个方向继续进行深入的研究:

  1. 组件管理:组件化改造之后,每个组件是个独立的工程,组件也会迭代开发,如何对这些组件进行版本化管理。
  2. 组件重用:现在看起来对这些组件的重用是很方便的,只需要引入组件的库即可,但是如果一个新的项目到来,需求有些变化,我们应该怎样最大限度的重用这些组件。
  3. CI集成:如何更好的与CI集成。
  4. 集成到脚手架:集成到脚手架,让新的项目从一开始就以组件化的模式进行开发。

参考资料

  1. Android消息总线的演进之路:用LiveDataBus替代RxBus、EventBus
  2. WMRouter:美团外卖Android开源路由框架
  3. 美团外卖Android平台化架构演进实践

作者简介

  • 海亮,美团高级工程师,2017年加入美团,目前主要负责美团轻收银、美团收银零售版等App的相关业务及模块开发工作。

招聘

美团餐饮生态诚招Android高级/资深工程师和技术专家,Base北京、成都,欢迎有兴趣的同学投递简历到chenyuxiang@meituan.com。