插件化以及组件化笔记整理

组件化:就是将一个app分成多个module,每个module都是一个组件(也可以是一个基础库供组件进行依赖),开发中可以单独调试组件,组件间不需要相互依赖,但可以相互调用,最终发布时所有的组件以lib的形式被主工程依赖并打包成apk
业务隔离,方便开发和调试

插件化:将整个app拆分成多个模块,分宿主和多个插件,每个模块都是一个apk(组件化,每个模块都是一个lib),最终打包的时候将宿主apk和插件apk(或其他格式)分开或者联合打包,

组件化是在编译器分模块,插件化实在运行期。插件化一般用于热修复,和动态更新模块。
组件化开发让每个module都跨源独立运行,开发期间都设置为application。发布时再合并。


重点:

遇到的问题:

阿布他们的项目大量的用了 databinding 和 dagger,然而我们项目并没有用这些,用了这两个库的可以看看他是怎么爬坑的: 魔都三帅
当你采用了组件化开发的时候,一定会遇到这几个问题,这几个问题除了第三个都只能规避,没有好的处理办法:
1、module 中 Application 调用的问题
2、跨 module 的 Activity 或 Fragment 跳转问题
3、AAR 或 library project 重复依赖
4、资源名冲突
1,applcation冲突,因为再debug状态下module是个application,再release状态下它是一个lib,所以获取到的application对象不是同一个类。
所以再application里面尽量不要写方法实现和强转操作,用变量区分业务逻辑

2,module跳转

1, Scheme方式建立映射表,集中处理activity,可以传递一定的数据。
2,github上的一个 url Router ,同时支持http和程序内Activity跳转,而且通过注解的方式进行,使用非常方便,于是引入到了项目中。项目地址 ActivityRouter ActivityRouter 的readme中已经有比较详细的wiki,
3, 类名方式跳转不支持传递数据
首先创建一个所有界面类名的列表
public class RList { public static final String ACTIVITY_MEMORYBOX_MAIN = "com.kymjs.app.memory.module.main.MainActivity"; public static final String FRAGMENT_MEMORYBOX_MAIN = "com.kymjs.app.memory.module.list.MainFragment";}
在获取 Fragment 的时候就可以根据列表中的类名来读取指定的 Fragment 了。
public class FragmentRouter { public static Fragment getFragment(String name) { Fragment fragment; try { Class fragmentClass = Class.forName(name); fragment = (Fragment) fragmentClass.newInstance(); } catch (Exception e) { throw new RuntimeException(e); } return fragment; }}
同理,Activity 其实也可以用这种方法来跳转:
public static void startActivityForName(Context context, String name) { try { Class clazz = Class.forName(name); startActivity(context, clazz); } catch (ClassNotFoundException e) { throw new RuntimeException(e); }}
最后,对于这个 RList 类,我们还可以通过 Gradle 脚本来生成,就像 R 文件一样,这样子开发就要方便很多了。

3.重复依赖
如果是 aar 依赖,gradle 会自动帮我们找出新版本的库而抛弃旧版本的重复依赖。但是如果你使用的是 project 依赖,gradle 并不会去去重,最后打包就会出现代码中有重复的类了。
一种是 将 compile 改为 provided,只在最终的项目中 compile 对应的代码,但是这种办法只能用于没有资源的纯代码工程或者jar包;
可以将所有的依赖写在 shell 层的 module,这个 shell 并不做事情,他只用来将所有的依赖统一成一个入口交给上层的 app 去引入,而项目所有的依赖都可以写在 shell module 里面。
4, resourcePrefix 可以给xml文件加前缀,但所有的图片资源仍需要手动修改资源。


组件化架构:


app  是最终工程的目录
explorer  和  memory-box  是两个功能模块,他们在开发阶段是以独立的 application,在 release 时才会作为 library 引入工程。
router  有两个功能,一个是作为路由,用于提供界面跳转功能。另一个功能是前面讲的 shell ,作为依赖集合,让各业务 module 接入。  base-res  是一些通用的代码,即每个业务模块都会接入的部分,它会在 router 中被引入。

组件化路由架构图
通过上图可以看到,我们在最基础的Common库中,创建了一个路由 Router ,中间有n个模块 Module ,这个 Module 实际上就是Android Studio中的module,这些 Module 都是 Android Library Module ,最上面的Module Main是 可运行的Android Application Module
这几个 Module 都引用了Common库,同时Main Module还引用了A、B、N这几个 Module ,经过这样的处理之后, 所有的 Module 之间的相互调用就都消失了,耦合性降低,所有的通信统一都交给Router来处理分发,而注册工作则交由Main Module去进行初始化 。这个架构思想其实和Binder的思想很类似,采用C/S模式,模块之间隔离,数据通过共享区域进行传递。模块与模块之间只暴露对外开放的Action,所以也具备 面向接口编程思想
图中的红色矩形代表的是行动 Action Action 是具体的执行类,其内部的 invoke方法是具体执行的代码逻辑 。如果涉及到 并发操作 的话,可以在 invoke方法内加入锁,或者直接在invoke方法上加上synchronized描述
图中的黄色矩形代表的是供应商 Provider ,每个 Provider 中包含1个或多个 Action ,其内部的数据结构以 HashMap 来存储Action。 首先HashMap查询的时间复杂度是O(1),符合我们对调用速度上的要求,其次,由于我们是统一进行注册,所以在写入时并不存在并发线程并发问题,在读取时,并发问题则交由Action的invoke去具体处理。 在每一个 Module 内都会有1个或多个供应商 Provider (如果不包含 Provider ,那么这个 Module 将无法为其他 Module 提供服务)。
途中蓝色矩形代表的是路由 Router ,每个 Router 中包含多个 Provider ,其内部的数据结构也是以 HashMap 来存储 Provider ,原理也和 Provider 是一样的。之所以用了两次HashMap,有两点原因,一个是因为这样做, 不容易导致 Action 的重名 ,另一个是因为在注册的时候,只注册 Provider 减少注册代码,更易读 。并且由于HashMap的查询时间复杂度是O(1),所以两次查找不会浪费太多时间。当查找不到对应 Action 的时候,Router会生成一个 ErrorAction ,会告之调用者没有找到对应的 Action ,由调用者来决定接下来如何处理。
一次请求流程
通过Router调用的具体流程是这样的:
Router时序图
Router时序图
  1. 任意代码创建一个RouterRequest,包含ProviderAction信息,向Router进行请求。
  2. Router接到请求,通过RouterRequestProvider信息,在内部的HashMap中查找对应的Provider
  3. Provider接到请求,在内部的HashMap中查找到对应的Action信息。
  4. Action调用invoke方法。
  5. 返回invoke方法生成的ActionResult
  6. Result封装成RouterResponse,返回给调用者。
耦合降低
所有的 Module 之间的相互依赖没有了,我们可以在主app中,取消任意的 Module 引用而不影响整体App的编译及运行。
取消对Module N的依赖
取消对Module N的依赖
如图所示,我们取消了对 Module N 的依赖,整体应用依然可以稳定运行,遇到调用 Module N 的地方,会返回Not Found提示,实际开发中可以根据需求做具体的处理。

Router是JVM级别的单例模式,并不支持跨进程访问

开源库ActivityRouter支持给Activity定义 URL,这样就可以通过 URL 跳转到Activity,并且支持从浏览器以及 APP 中跳入我们的Activity,而且还支持通过 url 调用方法。

接下来我们将声明项目中的业务组件,声明方法如下:
@Module("girls")
public class Girls {
}
在每一个业务组件的java文件的根目录下创建一个类,用 注解@Module 声明这个业务组件;
然后在“app壳工程”的 应用Application 中使用 注解@Modules 管理我们声明的所有业务组件,方法如下:
@Modules({"main", "girls", "news"})
public class MyApplication extends BaseApplication {
}
项目中的任何一个地方通过 URL地址 : module://girls, 调用 GirlsActivity,方法如下:
Routers.open(MainActivity. this , "module://girls" );

APT(Annotation Processing Tool)是一种处理注解的工具,它对源代码文件进行检测找出其中的Annotation,使用Annotation进行额外的处理。 Annotation处理器在处理Annotation时可以根据源文件中的Annotation生成额外的源文件和其它的文件(文件具体内容由Annotation处理器的编写者决定),APT还会编译生成的源文件和原来的源文件,将它们一起生成class文件。

组件间通信可以使用Android广播来解决,也可以使用第三方的事件总线来实现,比如EventBus。

URL Scheme应用场景:
    客户端应用可以向操作系统注册一个 URL scheme,该 scheme 用于从浏览器或其他应用中启动本应用。通过指定的 URL 字段,可以让应用在被调起后直接打开某些特定页面,比如商品详情页、活动详情页等等。也可以执行某些指定动作,如完成支付等。也可以在应用内通过 html 页来直接调用显示 app 内的某个页面。综上URL Scheme使用场景大致分以下几种:
  • 服务器下发跳转路径,客户端根据服务器下发跳转路径跳转相应的页面
  • H5页面点击锚点,根据锚点具体跳转路径APP端跳转具体的页面
  • APP端收到服务器端下发的PUSH通知栏消息,根据消息的点击跳转路径跳转相关页面
  • APP根据URL跳转到另外一个APP指定页面


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值