评论

收藏

[Oracle] 阿里两轮面试都被问了组件化问题,你会嘛?,Android插件化 模块化 组件化 热修复

数据库 数据库 发布于:2021-12-25 14:35 | 阅读数:286 | 评论:0


  • 本地广播,也就是 LoacalBroadcastRecevier。更多是用在同一个应用内的不同系 统规定的组件进行通信,好处在于:发送的广播只会在自己的 APP 内传播,不 会泄漏给其他的 APP,其他 APP 无法向自己的 APP 发送广播,不用被其他 APP 干扰。本地广播好比对讲通信,成本低,效率高,但有个缺点就是两者通信机制 全部委托与系统负责,我们无法干预传输途中的任何步骤,不可控制,一般在组 件化通信过程中采用比例不高。
  • 进程间的 AIDL。这个粒度在于进程,而我们组件化通信过程往往是在线程中, 况且 AIDL 通信也是属于系统级通信,底层以 Binder 机制,虽说 Android 提供模 板供我们实现,但往往使用者不好理解,交互比较复杂,往往也不适用应用于组 件化通信过程中。
  • 匿名的内存共享。比如用 Sharedpreferences,在处于多线程场景下,往往会线 程不安全,这种更多是存储一一些变化很少的信息,比如说组件里的配置信息等 等。
  • Intent Bundle 传递。包括显性和隐性传递,显性传递需要明确包名路径,组件 与组件往往是需要互相依赖,这背离组件化中 SOP(关注点分离原则),如果走 隐性的话,不仅包名路径不能重复,需要定义一套规则,只有一个包名路径出错, 排查起来也稍显麻烦,这个方式往往在组件间内部传递会比较合适,组件外与其 他组件打交道则使用场景不多。
说了这么多,那组件化通信什么机制比较适合呢?既然组件层中的模块是相互独 立的,它们之间并不存在任何依赖。没有依赖就无法产生关系,没有关系,就无 法传递消息,那要如何才能完成这种交流?
目前主流做法之一就是引入第三者,比如图中的 Base Module。
基础组件化架构
组件层的模块都依赖于基础层,从而产生第三者联系,这种第三者联系最终会编 译在 APP Module 中,那时将不会有这种隔阂,那么其中的 Base Module 就是 跨越组件化层级的关键,也是模块间信息交流的基础。比较有代表性的组件化开 源框架有得到 DDComponentForAndroid、阿里 Arouter、聚美 Router 等等。
除了这种以通过引入第三者方式,还有一种解决方式是以事件总线方式,但这种 方式目前开源的框架中使用比例不高,如图:
事件总线
事件总线通过记录对象,使用监听者模式来通知对象各种事件,比如在现实生活 中,我们要去找房子,一般都去看小区的公告栏,因为那边会经常发布一些出租 信息,我们去查看的过程中就形成了订阅的关系,只不过这种是被动去订阅,因 为只有自己需要找房子了才去看,平时一般不会去看。小区中的公告栏可以想象 成一个事件总线发布点,监听者则是哪些想要找房子的人,当有房东在公告栏上 贴上出租房信息时,如果公告栏有订阅信息功能,比如引入门卫保安,已经把之 前来这个公告栏要查看的找房子人一一进行电话登记,那么一旦有新出租消息产 生,则门卫会把这条消息一一进行短信群发,那么找房子人则会收到这条消息进 行后续的操作,是马上过来看,还是延迟过来,则根据自己的实际情况进行处理。 在目前开源库中,有 EventBus、RxBus 就是采用这种发布/订阅模式,优点是简 化了 Android 组件之间的通信方式,实现解耦,让业务代码更加简洁,可以动态 设置事件处理线程和优先级,缺点则是每个事件需要维护一个事件类,造成事件 类太多,无形中加大了维护成本。那么在组件化开源框架中有 ModuleBus、CC 等 等。
这两者模式更详细的对比,可以查看这篇文章多个维度对比一些有代表性的开源 android 组件化开发方案
实现方案
事件总线,又可以叫做组件总线,路由+接口,则相对好理解点,今天从阅读它 们框架源码,我们来对比这两种实现方案的不同之处。
组件总线
这边选取的是 ModuleBus 框架,这个方案特别之处在于其借鉴了 EventBus 的思 想,组件的注册/注销和组件调用的事件发送都跟 EventBus 类似,能够传递一些 基础类型的数据,而并不需要在 Base Moudel 中添加额外的类。所以不会影响 Base 模块的架构,但是无法动态移除信息接收端的代码,而自定义的事件信息 类型还是需要添加到 Base Module 中才能让其他功能模块索引。
其中的核心代码是在与 ModuleBus 类,其内部维护了两个 ArrayMap 键对值列 表,如下:
private static ArrayMap<Object,ArrayMap<String,MethodInfo>>
moduleEventMethods = new ArrayMap<>();
private static ArrayMap<Class<?>,ArrayMap<String,ArrayList<Object>>>
moduleMethodClient = new ArrayMap<>()
在使用方法上,在 onCreate()和 onDestroy()中需要注册和解绑,比如
ModuleBus.getInstance().register(this);
ModuleBus.getInstance().unregister(this);
最终使用类似 EventBus 中 post 方法一样,进行两个组件间的通信。这个框架 的封装的 post 方法如下
public void post(Class<?> clientClass,String methodName,Object...args){
if(clientClass == null || methodName == null ||methodName.length() == 0) return;
ArrayList<Object> clientList = getClient(clientClass,methodName)
for(Object c: clientList){ ArrayMap<String,MethodInfo> methods = moduleEventMethods.get(c);
Method method = methods.get(methodName).m;
method.invoke(c,args);
}
可以看到,它是通过遍历之前内部的 ArrayMap,把注册在里面的方法找出,根据传入的参数进行匹配,使用反射调用。
接口+路由
接口+路由实现方式则相对容易理解点,我之前实践的一个项目就是通过这种方 式实现的。具体地址如下:DemoComponent 实现思路是专门抽取一个 LibModule 作为路由服务,每个组件声明自己提供的服务 Service API,这些 Service 都是一些接口,组件负责将这些 Service 实现并注册到一个统一的路由 Router 中去,如果要使用某个组件的功能,只需要向 Router 请求这个 Service 的实现,具体的实现细节我们全然不关心,只要能返回我们需要的结果就可以了。 比如定义两个路由地址,一个登陆组件,一个设置组件,核心代码:
public class RouterPath {
public static final String ROUTER_PATH_TO_LOGIN_SERVICE = "/login/service";
public static final String ROUTER_PATH_TO_SETTING_SERVICE = "/setting/service"; }
那么就相应着就有两个接口 API,如下:
public interface ILoginProvider extends IProvider {
void goToLogin(Activity activity);
}
public interface ISettingProvider extends IProvider {
void goToSetting(Activity activity);
}
}
这两个接口 API 对应着是向外暴露这两个组件的能提供的通信能力,然后每个组 件对接口进行实现,如下:
@Override
public void init(Context context) {
}
@Override
public void goToLogin(Activity activity) {
Intent loginIntent = new Intent(activity, LoginActivity.class);
activity.startActivity(loginIntent);
}
}
这其中使用的到了阿里的 ARouter 页面跳转方式,内部本质也是接口+实现方式 进行组件间通信。
调用则很简单了,如下:
ILoginProvider loginService = (ILoginProvider)
ARouter.getInstance().build(RouterPath.ROUTER_PATH_TO_LOGIN_SERVICE).naviga tion();
if(loginService != null){
loginService.goToLogin(MainActivity.this);
}
还有一个组件化框架,就是 ModularizationArchitecture ,它本质实现方式也是 接口+实现,但是封装形式稍微不一样点,它是每个功能模块中需要使用注解建 立 Action 事件,每个 Action 完成一个事件动作。invoke 只是方法名为反射,并 未用到反射,而是使用接口方式调用,参数是通过 HashMap 传递的,无法传递 对象。具体详解可以看这篇文章 Android 架构思考(模块化、多进程)。,string>
页面跳转
尾声
以薪资待遇为基础,以发展为最终目标,要在高薪资的地方,谋求最好的发展!
下面是有几位Android行业大佬对应上方技术点整理的一些进阶资料。有Android架构视频+BATJ面试专题PDF+核心笔记等资料。希望能够帮助到大家提升技术。如果大家想要获取的话,可以私信我【666】免费获取哦



关注下面的标签,发现更多相似文章