Android组件化架构学习笔记——组件化编程之通信机制

一个项目的开启时,需要深入评估工具在编程中的代价和实现成效。工具直接影响着工作效率,首先要知道有什么工具(工具类及库)?怎么选择这些工具?怎么使用这些工具?使用这些工具有什么好处?怎么做才能做到更加高效,以减少工具消耗和人力消耗的计量?

时间维度:沟通时间,决策时间,编码时间,维护时间;

空间维度:产生工程包大小,运行内存,方法量。

一.本地广播:

LocalBroadcastManager是Android support包提供的一个工具包,用来在同一个应用内的不同组件间Broadcast进行通信,好处:

  • 发送广播只会在自己的app内传播,不会泄露给其他的app,确保隐私信息回不泄露;
  • 其他app无法向自己的app发送广播,不用被其他app干扰;
  • 比全局广播更加高效。
        //注册广播
        BroadcastReceiver receiver = new BroadcastReceiver() {
            @Override
            public void onReceive(Context context, Intent intent) {
                // TODO: 2019-07-10 接收广播的信息
                String action = intent.getAction();
            }
        };
        localBroadcastManager.registerReceiver(receiver,new IntentFilter("LOCAL_ACTION"));


        //注销广播
        localBroadcastManager.unregisterReceiver(receiver);

        //发送广播消息
        localBroadcastManager.sendBroadcast(new Intent("LOCAL_ACTION"));

 

二.组件之间通信机制:

  • 事件总线EventBus:

Android中activity/fragment/service信息传递相对复杂,一开始考虑用广播的方式进行传递,但是系统的广播传递是耗时的而且非常容易被捕获。事件总线机制通过记录对象/使用监听者模式来通知对象各种事件。不需要原生过重的事件Broadcast机制的管理,并可以将信息传递给原生以外的各种高对象。

EventBus:是一款针对Android优化的发布/订阅事件总线,主要功能是代替Intent/Handler/Broadcast,在Fragment/Activity/Service/线程之间传递消息。优点是开销小,代码更优雅,以及将发送者和接收者解耦。EventBus框架中涉及四个部分——订阅者/发布者/订阅事件和事件总线。订阅者可以订阅多个事件,发送者可以发布任何事件,发布者同时也可以是订阅者。

    //定义事件
    public class MessageEvent{
        //Additional fields if needed
    }
    
    //注册订阅者
    EventBus.getDefault().register(this);
    
    //订阅事件
    @Subscribe
    public void onEvent(AnyEventType eventType) {
        //Do something
    }
    
    //发布事件
    EventBus.getDefault().post(object);
    
    //注销订阅
    EventBus.getDefault().unregister(this);

在使用EventBus时一定要注意,订阅事件的对象在依附的activity/fragment/service一定要取消订阅,因为register是强引用,如不取消订阅,那么强引用会让对象无法得到内存回收,导致内存泄露。

  • EventBus3.0:

EventBus3.0使用的方式和EventBus2.x是一致的。没开启索引系统的3.0版其反射效率比EventBus2.x版要低1-3倍,而开启索引系统,3.0版的速度要比2.x版快很多。

EventBus2.0使用的是运行时注解,运行时注解很大基础上是依赖于Java的反射规则,Java的反射是耗费效率的,采用反射的方式对整个注册的类所有方法进行扫描来进行注册。所以在一些低端Android手机中频繁使用反射,会对性能产生一定影响。

EventBus3.0使用的是编译时注解,Java文件在编译的时候,会将其编译为.class文件,再对class文件进行打包等一系列处理。而编译时注解在Java编译生成.class文件时就进行操作。可以想象是在代码编写完后,就创建出对文件或类的索引关系,将索引关系编入到apk中。具体是提供了EventBusAnnotaionProcessor注解处理器,在编译期通过读取@Subscribe()注解并解析/处理其中所包含的信息,然后生成Java类来保存所有订阅者关于订阅的信息,这样就比在运行时使用反射来获取这些订阅者信息的速度更快。

RxBus一开始并不是一个库,它是基于RxJava响应式编程衍而来的,它是一种要引入RxJava和RxAndroid就可以简单地编写一个RxBus的事件总线。

/**
 * @author wangyongyao
 * @package com.example.demo1.demo
 * @date 2019-08-11 10:48
 * @decribe TODO
 * @project
 */
public class RxBus {
    private final Subject bus;

    private RxBus() {
        bus = new SerializedSubject<>(PublishSubject.create());

    }

    //创建单例模式
    public static RxBus getInstance() {
        return RxBusHolder.mInstatnce;
    }

    static class RxBusHolder{
        private static RxBus mInstatnce = new RxBus();

    }

    //发送消息
    public void post(Object object){
        bus.onNext(object);

    }

    //接收消息
    public <T> Observable <T> toObservable(Class<T> eventType) {
        return bus.ofType(eventType);
    }
}


//发送消息
RxBus.getInstance().post(new XXXEvent(long id));

//接收消息
Subscription rxScp = RxBus.getInstance().toObservable(XXXEvent.class)
                            .subcrible(new
    Action1<XXXEvent>() {
        public void call(XXXEvent event){
            
        }
});

这里使用了静态内部类的单例,由于内部静态类只会被加载一次,所以实现方式线程安全的,比double check +volatile方式更加优雅。rxScp是Subscription的对象,方便生命周期结束时取消订阅事件。

  • 组件化事件总线的考量:

传递消息时,三种工具需要先设定信息装载的容器,将XXXEvent的类作为信息装载的容器。这些信息容器的模版需要放在一个公共位置才能告诉其他功能模块,不同的信息的类型对应哪些信息。

通信事件都需要放到公共Base模块中,Base模块也需要依赖于事件总线框架。信息组件都需要放在Base模块中,其通信需要依赖于Base module,这样设计是不合理的。组件化要求功能模块独立,从设计的角度考虑,应该尽量少影响App module和Base module。

Base module需要做到尽量通用,不受其他功能模块的影响。而这个事件总线放在Base module中,每个模块增删时都需要添加或者删除事件信息模型到Base module中,而增删事件代码会让其它模块索引到这个事件的代码,造成错误,也需要删除,这样会破坏组件化的设计原则。虽然删除模块时并不一定需要删除Base module中的信息事件模型,但这会让事件总线的整个架构更加臃肿。

这就是目前组件化通信会遇到的瓶颈问题,如动态地将信息模块添加到公共的地方,然后被其他模块索引到,这是非常值得深究的问题,你也无法用编译时注解完成这一步骤,因为无法完成对编译前提供事件类的索引。

现阶段比较合适的组件化通信方式

  • ModuleBus:能传递一些基础类型的数据,而并不需要在Base module中添加额外的类,所以不会影响Base模块的框架,但是也无法动态移除信息接收端的代码。而自定义的事件信息模型还是需要添加到Base module中才能让其它模块索引。
  • 组件化架构的Modularizationarchitecture库:每个功能模块中需要使用注解建立action事件,每个action完成一个事件动作。invoke只是方法名为反射,并为用到反射,而时使用接口方式调用,参数时通过HashMap<String,String>传递的,无法传递对象。

 

文章:Android架构思考(模块化、多进程)​​​​​​​

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章