type
status
date
slug
summary
tags
category
icon
password

1 模块化&组件化

有利于业务模块分离,高内聚,低耦合,代码边界清晰。有利于团队合作多线开发,加快编译速度,提高开发效率,管理更加方便,利于维护和迭代。
宿主 App 中只有一个 Application,整个业务被拆分为各个 mod 模块和 lib 组件库。对一些功能组件进行封装抽取为 lib,给上层提供依赖。mod 模块之间没有任务依赖关系,通过 Arouter 进行通信。
notion image

(1) 模块化

项目中通过以业务为维度把 App 拆分成主页模块,登录模块,搜索模块,用户模块,视频模块等,相互间不可以访问不可以作为依赖,与此同时他们共同依赖于基础库,网络请求库,公共资源库,图片加载库等。如果还需要使用到启动器组件、Banner组件、数据库Room组件等则单独按需添加。
APP 壳工程负责打包环境,签名,混淆规则,业务模块集成,APP 主题等配置等工作,一般不包含任何业务。

(2) 组件化

模块化和组件化最明显的区别就是模块相对组件来说粒度更大。一个模块中可能包含多个组件。在划分的时候,模块化是业务导向,组件化是功能导向。组件化是建立在模块化思想上的一次演进。
项目中以功能维度拆分了启动器组件、Banner组件、数据库Room组件等组件。模块化&组件化拆分后工程图:
notion image

(3) 组件间通信

组件化之后就无法直接访问其他模块的类和方法,这是个比较突出的问题,就像原来可以直接使用 LogintManager 来拉起登录,判断是否已登录,但是这个类已经被拆分到了 mod_login 模块下,而业务模块之间是不能互相作为依赖的,所以无法在其他模块直接使用 LogintManager
主要借助阿里的路由框架 ARouter 实现组件间通信,把对外提供的能力,以接口的形式暴露出去。
比如在公共资源库中的 service 包下创建 ILoginService,提供对外暴露登录的能力,在 mod_login 模块中提供 LoginServiceImpl 实现类,任意模块就可以通过 LoginServiceProvider 使用 iLoginService 对外提供暴露的能力。
  1. 公共资源库lib_common中创建 ILoginService,提供对外暴露登录的能力。
2. mod_login 模块中 LoginService 提供 ILoginService 的具体实现。
3. 公共资源库中lib_common创建 LoginServiceProvider,获取 LoginService,提供使用方法。
那么其他模块就可以通过 LoginServiceProvider 使用 iLoginService 对外提供暴露的能力。虽然看起来这么做会显得更复杂,单一工程可能更加适合我们,每个类都能直接访问,每个方法都能直接调用,但是我们不能局限于单人开发的环境,在实际场景上多人协作是常态,模块化开发是主流

2 ARouter基本使用

我们所使用的原生路由方案一般是通过显式intent和隐式intent两种方式实现的(这里主要是指跳转Activity or Fragment)。在显式intent的情况下,因为会存在直接的类依赖的问题,导致耦合非常严重;而在隐式intent情况下,则会出现规则集中式管理,导致协作变得非常困难。一般而言配置规则都是在Manifest中的,这就导致了扩展性较差。除此之外,使用原生的路由方案会出现跳转过程无法控制的问题,因为一旦使用了StartActivity()就无法插手其中任何环节了,只能交给系统管理,这就导致了在跳转失败的情况下无法降级,而是会直接抛出运营级的异常。这时候如果考虑使用自定义的路由组件就可以解决以上问题,比如通过URL索引就可以解决类依赖的问题;通过分布式管理页面配置可以解决隐式intent中集中式管理Path的问题;自己实现整个路由过程也可以拥有良好的扩展性,还可以通过AOP的方式解决跳转过程无法控制的问题,与此同时也能够提供非常灵活的降级方式。

2.1 添加依赖

在需要集成的module中添加依赖和配置

2.2 初始化

在Application里初始化ARouter

2.3 注入

Arouter 注入,可以封装在BaseActivity的onCreate中
既然有注入,就一定有资源的释放,释放资源在Application中进行,不要在BaseActivity的onDestroy方法中进行

2.4 使用

2.4.1 简单界面跳转

在目标Activity添加注释(命名规则:/开头并且必须大于两级,/模块/分类/具体名称)
跳转代码:
路由路径建议写成常量,创建路由表进行统一管理。

2.4.2 携带基本参数的界面跳转

传入键值对
目标界面使用 @Autowired 注解进行注入,很像Spring
注意:注入的属性名要和之前携带的key值完全相同

2.4.3 携带对象的界面跳转

💡
总结:Parcelable序列化对象使用withParcelable,Serializable和无序列化对象使用withObject,数组集合等也直接使用withObject
(1)携带Parcelable序列化对象的界面跳转
跳转代码
目标页面
(2)携带无序列化对象和Serializable对象的界面跳转

2.4.4 ARouter跳转Fragment

通过ARouter获取fragment的实例。用法和跳转Activity类似,只需要把结果进行强转即可。

2.5 ARouter拦截器

Arouter拦截器实际上就是提供了AOP功能,可以在路由前中后插入逻辑,对跳转的路由进行统一的控制,这就非常适合我们实现不同角色权限对应的不同展示效果,而且后期维护起来也比较方便,不会在各个界面中产生大量跳转逻辑。
我们先来定义两个拦截器:
定义ARouter拦截器必须要使用Interceptor类注解。注解里面的 priority 这个是声明拦截器的优先级、里面的属性值是int类型,拦截器的优先级不能相同。
可以在跳转逻辑中添加回调,方便我们控制跳转逻辑:

2.6 其他

ARouter还可以设置动画和设置分组,可以看这篇文章
关于Arouter的源码分析可以看这篇

3 ARouter在组件化中的使用

ARouter不仅仅可以页面跳转,上面已经介绍了ARouter在组件化中的使用,下面详细说一下使用流程。
以登录功能为例,首先在基础组件中定义登录服务相关接口
在登录模块中实现该接口
接着在基础组件库中新建一个单例object对象,用于其他模块调用
在init代码块中注入,loginService会自动注入。
最后在其他模块想调用登录的方法子需要使用Provider一行代码:LoginServiceProvider.login(requireContext())

📎 参考文章

ARouter
alibabaUpdated Oct 7, 2023
 
Leetcode总结MVP和MVVM
LuluNotion
LuluNotion
一个普通的干饭人🍚
公告
type
status
date
slug
summary
tags
category
icon
password
🎉NotionNext 4.0即将到来🎉
-- 感谢您的支持 ---
👏欢迎更新体验👏