android module解耦组件化总体概述(推荐)
作者:snsports 发布时间:2021-11-29 19:46:34
原由
移动开发中,随着项目不断的跌代,需求越来越复杂后。项目工程也越来越庞大。那么此时的分module的开发,则是必然的选择了。在最终的组件化之路上,不妨把单一工程比如石器时代,那么接下来简单的拆分工程分多个moudle开来就是铜器时代。
铜器时代之简单分module
演进
由于从复杂的单工程拆分了多个module了,达到了代码及资源的初步的隔离,或需求模块的开发人员,开始专注于自己的需求模块module的开发了。但是随着部分需求有相关性,需要相互调用时。那么问题来了,在AXXX module中
api project(':BXXX')
而在BXXX module中
api project(':AXXX')
这时出现了相互依赖,首先编译器会能不过,会出现Circular dependency,循环相互依赖的问题,这是绝不允许的。
为了解决上述的问题,将AXXX module与BXXX module需要对外提供服务能力支持的,进行封装与抽象。将需要对外暴露接口/协议地方,对其抽象出接口出来。把些这接口独立放在BaseXXXX module中,这样AXXX module与BXXX module,都分别去
api project(':BaseXXXX')
通过BaseXXXX中间module通信去解决AXXX module与BXXX module相互依赖调用通信。
初步的解决方法
为了在BaseXXXX module中,搭建起AXXX module与BXXX module相互通信的桥梁,可以在BaseXXXX module 定义一个通信标识接口:
/**
*
* 跨module通讯的 标识 interface接口
*/
public interface IModuleApi {
}
然后主要通过ModuleApiHelper进行通信
public class ModuleApiHelper {
private static Map<Class<? extends IModuleApi>,IModuleApi> moduleApiMap = new HashMap<>();
private static Map<Class<? extends IModuleApi>,List<IModuleApi>> moduleApiListMap = new HashMap<>();
/**
* 跨module 注册进 IKWModuleApi接口,及实现
* 通常可以在 其它的module中 注册此接口的实现,在用的module中getModuleApi拿到接口实现
* 这样,用的module 不是 必须依赖compile其它module了
* @param clazz
* @param iModuleApi
*/
public static void register(Class<? extends IModuleApi> clazz, IModuleApi iModuleApi){
if (null != iModuleApi && null != clazz){
moduleApiMap.put(clazz, iModuleApi);
}
}
public static void unregister(Class<? extends IModuleApi> clazz){
if (moduleApiMap.containsKey(clazz)){
moduleApiMap.remove(clazz);
}
}
public static void register2List(Class<? extends IModuleApi> clazz, IModuleApi iModuleApi){
if (null != iModuleApi && null != clazz){
if (moduleApiListMap.containsKey(clazz)){
List<IModuleApi> iModuleApis = moduleApiListMap.get(clazz);
iModuleApis.add(iModuleApi);
}else{
List<IModuleApi> iModuleApis = new ArrayList<>();
iModuleApis.add(iModuleApi);
moduleApiListMap.put(clazz, iModuleApis);
}
}
}
public static void unregister2List(Class<? extends IModuleApi> clazz){
if (moduleApiListMap.containsKey(clazz)){
moduleApiListMap.remove(clazz);
}
}
public static void unregisterAll(Class<? extends IModuleApi> clazz){
unregister(clazz);
unregister2List(clazz);
}
public static <T extends IModuleApi> List<T> getModuleListApi(Class<T> clazz){
if (null != clazz){
if (moduleApiListMap.containsKey(clazz)){
List<IModuleApi> iModuleApis = moduleApiListMap.get(clazz);
return (List<T>) iModuleApis;
}else{
return null;
}
}else{
return null;
}
}
/**
* 获取注册绑定过来的IKWModuleApi 实现
* @param clazz
* @param <T>
* @return
*/
public static <T extends IModuleApi> T getModuleApi(Class<T> clazz){
if (null != clazz){
if (moduleApiMap.containsKey(clazz)){
return (T) moduleApiMap.get(clazz);
}else{
return null;
}
}else{
return null;
}
}
}
这样比如在AXXX module中将原有AServiceData类是如下的:
public class AServiceData {
public String getSomeData(){
return "this is some data";
}
public void sayHello(){
System.out.println("hello");
}
}
改造成
public interface IAServiceData extends IModuleApi {
String getSomeData();
void sayHello();
}
public class AServiceData implements IAServiceData{
@Override
public String getSomeData(){
return "this is some data";
}
@Override
public void sayHello(){
System.out.println("hello");
}
}
将IAServiceData接口定义在BaseXXXX module 中。然后AXXX module中进行register相应的服务
public class AModuleService {
public void init(){
ModuleApiHelper.register(IAServiceData.class,new AServiceData());
}
}
这样调用AModuleService的init方法,即可对IAServiceData服务进行注册了。然后即下来,在BXXX module中进行getXXX得到服务即可调用相应的方法了.
在任何需要此服务的方法可如下调用:
IAServiceData iaServiceData = ModuleApiHelper.getModuleApi(IAServiceData.class);
注意
1> register注册时机,需要越早越好,一般建议在各module的有类似的application的onCreate时注册最好。
2> IModuleApi与ModuleApiHelper,和各extends继承IModuleApi接口的接口,需要放在中间通信BaseXXX Module中。各需要通信的module去 compile/api BaseXXX Module即可。
问题
为了保证IModuleApi接口注册有效,需要越早越好进行注册。这样随着项目越来越复杂,需要通信的地方越来越多。统一的ModuleApiHelper,注册的地方将越来越多带的问题也多起来。
1> 注册Map容器占用的内存不断的增多。
2> register注册的地方不统一,有些放在各module的类Application的onCreate中,有些可能是放在其它的类中.
3> 不支持ui页面的跳转,由AXXX module的AxxActtivy页面跳转到BXXX module的BxxActivity页面中。
4> 不支持多进程中应用。
为了解决上述问题,引入了蒸汽时代之ARoute到来。
蒸汽时代之ARoute
由于遍幅的原因,总体概述不详细细述ARoute,下遍再剖析ARoute。总体来说在多module通信中解决了:
1> 解决了ui页面的跳转问题。
2> 根据需要进行register的问题,且register通过静态注解来的,所以register地方统一比如容易维护。
但是依然不能解决多进程中的应用。
电器时代之Andromeda
Andromeda解决了多进程,跨进程ipc之间的通信过程,同样也支持单进程的通信...
来源:https://www.jianshu.com/p/e03255a23083


猜你喜欢
- 1.写个Mybatis-plus配置类:是通过 * 实现分页@Configurationpublic class MybatisConfig
- 1 概述Java虚拟机把描述类的数据从Class文件加载到内存, 并对数据进行校验、转化解析和初始化,最终形成可以被虚拟机直接使用的Java
- 题外话:发现好久都没有上来写博文了,毕业设计加上公司暂时没有Android的项目做,只能去自学web上的知识,摸爬打滚到现在,花了一个多月时
- 前言在这一期的文章中,我将继续介绍 Either,使用它构建树形结构,该结构允许我模拟 Scala 的模式匹配来构建遍历方法。在 Java
- 下面一段代码准确的介绍了java实现单链表逆序,具体内容就不做详解了,有需要的朋友可以直接拷贝了package com.ckw.miansh
- 效果展示在实际项目当中我们经常看到如下各种剪裁形状的效果,Flutter 为我们提供了非常方便的 Widget 很轻松就可以实现,下面我们来
- Android OnCreate()中获取控件高度与宽度试过在OnCreate()中获取控件高度与宽度的童鞋都知道,getWidth()与g
- 1、概念向下转型就是父类对象转成子类对象。我们把一个父类引用 Animal类型的引用 给了一个 Bird类型 的引用,这就是向下转型2、格式
- 概念异常处理的概念起源于早期的编程语言,如 LISP、PL/I 和 CLU。这些编程语言首次引入了异常处理机制,以便在程序执行过程中检测和处
- 本文实例讲述了C#利用System.Uri转URL为绝对地址的方法。分享给大家供大家参考。具体分析如下:在使用ASPOSE.Word生成Wo
- 网上关于如何切换,其实说的很明确,本文主要通过profile进行快速切换已实现在不同场合下,用不同的打包方式。jar到war修改步骤pom文
- 程序目的从java字节码层理解,为何i = i++后,结果是+1之前的数值。而i=++i后,结果是+1之后的值。关键指令iload_<
- 前言C# 语言一贯秉承简洁优美的宗旨,每次升级都会带来一些语法糖,让我们可以使代码变得更简洁。本文分享两个使用 C# 9.0 提升 if 语
- 最近一直都在学习Java,发现目前Java招聘中,mybatis出现的频率挺高的,可能是目前Java开发中使用比较多的数据库ORM框架。于是
- 本文实例讲述了java设置session过期时间的实现方法,分享给大家供大家参考。具体实现方法如下:1、Timeout in the dep
- 一家移动互联网公司,说到底,要盈利总是需要付费用户的,自己开发支付系统对于资源有限的公司来说显然不太明智,国内已经有多家成熟的移动支付提供商
- 一、背景单机节点下,WebSocket连接成功后,可以直接发送消息。而多节点下,连接时通过nginx会代理到不同节点。假设一开始用户连接了n
- C#实现的Check Password,并根据输错密码的次数分情况锁定账户:如果输入错误3次,登录账户锁定5分钟并提示X点X分后重试登录。如
- Android 通过Base64上传图片到服务器之前做上传图片是采用HttpServlet上传,不过用了一下Base64上传图片后,感觉比H
- 我们知道在编程时许多操作(如更新UI)需要在主线程中完成,而且,耗时操作(如网络连接)需要放在子线程中,否则会引起ANR。所以我们常使用Ha