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架構思考(模塊化、多進程)​​​​​​​

 

 

 

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