组件化架构笔记(第二章)

组件化通信机制

总所周知,Android提供了很多不同的信息的传递方式,比如在四大组件中本地广播、进程间的AIDL、匿名间的内存共享、Intent Bundle传递等等,那么在这么多传递方式,哪种类型是比较适合组件与组件直接的传递呢。

本地广播,也就是LoacalBroadcastRecevier。更多是用在同一个应用内的不同系统规定的组件进行通信,好处在于:发送的广播只会在自己的APP内传播,不会泄漏给其他的APP,其他APP无法向自己的APP发送广播,不用被其他APP干扰。本地广播好比对讲通信,成本低,效率高,但有个缺点就是两者通信机制全部委托与系统负责,我们无法干预传输途中的任何步骤,不可控制,一般在组件化通信过程中采用比例不高。

进程间的AIDL。这个粒度在于进程,而我们组件化通信过程往往是在线程中,况且AIDL通信也是属于系统级通信,底层以Binder机制,虽说Android提供模板供我们实现,但往往使用者不好理解,交互比较复杂,往往也不适用应用于组件化通信过程中。

匿名的内存共享。比如用Sharedpreferences,在处于多线程场景下,往往会线程不安全,这种更多是存储一一些变化很少的信息,比如说组件里的配置信息等等。

Intent Bundle传递。包括显性和隐性传递,显性传递需要明确包名路径,组件与组件往往是需要互相依赖,这背离组件化中SOP(关注点分离原则),如果走隐性的话,不仅包名路径不能重复,需要定义一套规则,只有一个包名路径出错,排查起来也稍显麻烦,这个方式往往在组件间内部传递会比较合适,组件外与其他组件打交道则使用场景不多。

组件层的模块是相互独立的,他们并不存在任何依赖,没有依赖,就无法传递任何的信息。因此需要第三方协助,而这个第三方就是基础层。

1631343685(1).png

还有一种方式就是以事件总线以及路由+接口的方式。

事件总线

代表为EventBus。

缺点:每个事件都必须自定义一个事件类,造成事件类太多,加大了维护成本。

路由+接口

实现思路是专门抽取一个LibModule作为路由服务,每个组件声明自己提供的服务 Service API,这些 Service 都是一些接口,组件负责将这些Service实现并注册到一个统一的路由Router中去,如果要使用某个组件的功能,只需要向Router 请求这个 Service 的实现。

组件化跳转

在组件化中,两个功能模块是不存在直接依赖的,一般的直接跳转是从一个Activity跳转到另外一个Activity,通过显示Intent,但是在组件化中发现引用不了其他module的Activity类,这个时候采用隐式Intent来跳转。

隐式Intent跳转

(1)Action跳转

先在AndroidManifest,通过intent-filter来限定隐式Action.


 
 

其他module可以使用隐式的Action跳转到相应的Activity.

Intent intent = new Intent("com.setting");
startActivity(intent);

(2)包名加类名的跳转

Intent intent = new Intent();
intent.setClassName("模块包名","Activity路径");
intent.setComponent(new ComponentName("模块包名","Activity路径"));
startActivity(intent);

跳转的时候会崩溃,提示Activity并没有在AndroidManifest中注册,主要原因是setClassName和ComponentName的第一个参数名是App的包名。因为在最终打包合并AndroidManifest的时候,App中只会有一份配置。所以需要转换一下。

Intent intent = new Intent();
intent.setClassName("APP包名","Activity路径");
intent.setComponent(new ComponentName("APP包名","Activity路径"));
startActivity(intent);

需要注意的是,如果移除Activity所在的module,而不移除跳转,Activity会出现崩溃异常。

Android官网提示,使用隐式Intent跳转需要验证是否会接收Intent,需要对Intent对象调用resolveActivity(),如果结果为非空,则至少有一个应用能够处理该Intent,且可以安全调用startActivity();

if(intent.resolveActivity(getPackageManager() != null){
    startActivity(intent);
}
路由跳转

Arouter的使用

Arouter源码分析之初始化

Arouter源码分析之页面跳转

Arouter源码分析之拦截处理

静态常量

lib module 中的静态变量是没有被赋予final属性的。因此会导致一些问题,比如凡是规定必须使用常量的地方都无法直接使用R.java中的变量,例如switch -case 和注解。(可以用if - else 代替switch -case)

还有不同module之间无法保证R.java中的变量对应的数值不同,但不同module的R.java的变量的值可能相同,重复声明将造成资源冲突。

注解中只能使用常量,如果不是常量则会报错。注解中包含资源的问题解决可以参考ButterKnife.

资源冲突

(1)AndroidMainfest冲突

使用tools:replace

(2)包冲突

使用 exclude排除依赖

(3)资源名冲突

使用resourcePrefix

混淆

(1)资源混淆

1、源码级别的修改,将xml中的R.string.xxx替换成R.string.a,并将一些图片资源xxx.png重命名a.png。然后再交给Android进行编译。

2、直接修改resources.arsc的二进制数据,不改变打包流程。在生成resources.arsc之后修改它。同时重命名资源文件。

3、直接处理安装包,解压后直接修改resources.arsc的二进制数据,修改完后重新打包。

1631354226(1).png

(2)组件化混淆

1、直接在Application module中设置混淆,其他module的混淆都关闭。

缺点:当某些模块移除后,混淆规则需要手动移除。不然会对编译效率造成影响。

2、当Application module混淆的时候,启动一个命令将引用多个module的proguard-rules.pro文件合成,然后再覆盖Application module中的混淆文件。

3、Lib module自身拥有将proguard-rules.pro文件打包到aar中的设置。

添加一个属性到Library module的build.gradle文件中:

defaultConfig{
    consumerProguardFiles 'proguard-rules.pro'
}

consumerProguardFiles有以下特性:

proguard.txt文件包含在aar文件中。

proguard配置在混淆时使用。

此配置针对aar进行混淆配置。

此配置只对库文件有效,对应用程序无效。

当Application module将全部的代码汇总混淆的时候,Lib module会被打包为aar,然后被引用汇总,通过proguard.txt文件规则各自混淆,保证值混淆一次。

你可能感兴趣的:(组件化架构笔记(第二章))