之前写过一篇关于Android组件化的文章,《Android组件化框架设计与实践》,之前没看过的小伙伴可以先点击阅读。那篇文章是从实战中进行总结得来,是公司的一个真实项目进行组件化架构改造,粒度会分的更粗些,是对整体架构实践进行相应的总结,里面说了要打造一个组件化框架的话,需要从以下7个方面入手:
代码解耦。如何将一个庞大的工程分成有机的整体?
组件单独运行。因为每个组件都是高度内聚的,是一个完整的整体,如何让其单独运行和调试?
组件间通信。由于每个组件具体实现细节都互相不了解,但每个组件都需要给其他调用方提供服务,那么主项目与组件、组件与组件之间如何通信就变成关键?
UI 跳转。UI 跳转指的是特殊的数据传递,跟组件间通信区别有什么不同?
组件生命周期。这里的生命周期指的是组件在应用中存在的时间,组件是否可以做到按需、动态使用、因此就会涉及到组件加载、卸载等管理问题。
集成调试。在开发阶段如何做到按需编译组件?一次调试中可能有一两个组件参与集成,这样编译时间就会大大降低,提高开发效率。
代码隔离。组件之间的交互如果还是直接引用的话,那么组件之间根本没有做到解耦,如何从根本上避免组件之间的直接引用,也就是如何从根本上杜绝耦合的产生?
今天则会从更小细粒度入手,主要讲讲在组件化架构下组件与组件之间通信机制是如何、包括所谓的UI跳转,其实也是组件化通信,只不过它稍微特殊点,单独抽取出来而已。学习知识的过程很常见的一个思路就是从整体概况入手,首先对整体有个粗略的印象,然后再深入细节,抽丝剥茧般去挖掘其中的内在原理,一个点一个不断去突破,这样就能建立起自己整个知识树,所以今天我们就从通信机制这个点入手,看看其中内在玄机有哪些。
思维导图同样,在每写一篇文章之前,放个思维导图,这样做的好处对于想写的内容有很好的梳理,逻辑和结构上显得清晰点。
主流方式总所周知,Android提供了很多不同的信息的传递方式,比如在四大组件中本地广播、进程间的AIDL、匿名间的内存共享、Intent Bundle传递等等,那么在这么多传递方式,哪种类型是比较适合组件与组件直接的传递呢。
本地广播,也就是LoacalBroadcastRecevier。更多是用在同一个应用内的不同系统规定的组件进行通信,好处在于:发送的广播只会在自己的APP内传播,不会泄漏给其他的APP,其他APP无法向自己的APP发送广播,不用被其他APP干扰。本地广播好比对讲通信,成本低,效率高,但有个缺点就是两者通信机制全部委托与系统负责,我们无法干预传输途中的任何步骤,不可控制,一般在组件化通信过程中采用比例不高。
进程间的AIDL。这个粒度在于进程,而我们组件化通信过程往往是在线程中,况且AIDL通信也是属于系统级通信,底层以Binder机制,虽说Android提供模板供我们实现,但往往使用者不好理解,交互比较复杂,往往也不适用应用于组件化通信过程中。
匿名的内存共享。比如用Sharedpreferences,在处于多线程场景下,往往会线程不安全,这种更多是存储一一些变化很少的信息,比如说组件里的配置信息等等。
Intent Bundle传递。包括显性和隐性传递,显性传递需要明确包名路径,组件与组件往往是需要互相依赖,这背离组件化中SOP(关注点分离原则),如果走隐性的话,不仅包名路径不能重复,需要定义一套规则,只有一个包名路径出错,排查起来也稍显麻烦,这个方式往往在组件间内部传递会比较合适,组件外与其他组件打交道则使用场景不多。
说了这么多,那组件化通信什么机制比较适合呢?既然组件层中的模块是相互独立的,它们之间并不存在任何依赖。没有依赖就无法产生关系,没有关系,就无法传递消息,那要如何才能完成这种交流?
目前主流做法之一就是引入第三者,比如图中的Base Module。
组件层的模块都依赖于基础层,从而产生第三者联系,这种第三者联系最终会编译在APP Module中,那时将不会有这种隔阂,那么其中的Base Module就是跨越组件化层级的关键,也是模块间信息交流的基础。比较有代表性的组件化开源框架有得到DDComponentForAndroid、阿里Arouter、聚美Router 等等。
除了这种以通过引入第三者方式,还有一种解决方式是以事件总线方式,但这种方式目前开源的框架中使用比例不高,如图: