天天看點

Android元件通信方式:元件間的架構設計

作者:Android不是安卓

前言

因為之前被問到過,最近突然有點興趣上頭,是以想簡單做一個總結,現在開發基本都會用到元件化,那麼大家有沒有想過在不使用别人寫的架構的情況下,自己如何去實作元件化。

本次主要講兩個互不依賴的元件之間的通信,而如果兩個元件之間存在依賴,那就可以直接去調用,這種情況就不說了。本次主要講的是技術層面的實作,不講架構層面的,因為這個功能如果要做架構設計,那将會是一個大工程,對于元件間的架構設計,很多大佬也有講。但是具體的技術實作,卻很少有人提到,我這裡就簡單做個總結。

元件間控件的跳轉

比如說元件A的一個Activity跳轉到元件B的一個Activity,具體是如何實作的。

這裡我們可以用ARouter來分析,我之前也有一篇文章簡單寫過,感興趣的可以去看看juejin.cn/post/714936…

這裡就直接給出結論:顯式跳轉

簡單來說就是元件A拿到元件B的Class之後進行顯示跳轉。

Android元件通信方式:元件間的架構設計

資源調用

資源調用就更簡單了,雖然在不同的子產品, 但是AssetManager會統一加載路徑,是以直接用Resource就能加載資源了。

元件通信

這個才是我這次要講的重點,舉個栗子,互不依賴的子產品A調用子產品B的一個方法,如何去調用?

其實說到這個,很多人第一反應就是EventBus,那除了EventBus,還有其它的能實作這個功能的方式嗎?他們究竟是如何實作的?

反射

讓我們請出今天的一号選手,反射

反射選手馳騁Android界可謂是無所不能,如果時間回到很早很早以前,沒有ARouter,沒有各種Bus,你讓我來做,我可能第一個想到的就是反射。

Android元件通信方式:元件間的架構設計

反射可以實作這兩個子產品不引用相同子產品的情況下,能讓其中一個子產品調用另一個子產品的方法、屬性等。

隻要能拿到Class對象,你就可以做到任何你想做的事,這裡我們的元件同屬一個包的情況下,你可以通過類名等方式去擷取到Class對象,哪怕是不同包,你也可以通過ClassLoader去拿到Class對象。

EventBus

讓我們請出二号選手EventBus,EventBus可謂是Android界的當紅炸子雞,它試用簡單,隻需要一個方法一個注釋,便能快速的實作元件間的跳轉。

但是它也有壞處,如果你隻會濫用EventBus的話,我相信接手你項目的那位老兄十分的想感謝你的全家。當項目變得越來越大的時候,功能變得越來越大的時候,漫天亂飛的EventBus會讓開發者活着煎熬中。

接下來可以簡單看看EventBus是如何在元件間進行穿梭的(我現在項目沒用到這個,因為我這今天網慢,下不下來,我直接github上拿代碼講)。

直接看post,不用管細節,這裡不是源碼解析EventBus,隻是為了找核心,是以跟進主線任務

Android元件通信方式:元件間的架構設計
Android元件通信方式:元件間的架構設計
Android元件通信方式:元件間的架構設計
Android元件通信方式:元件間的架構設計
Android元件通信方式:元件間的架構設計

簡單瞟一眼,發現有關線程什麼的,然後最後調到subscription.subscriberMethod.method.invoke(subscription.subscriber, event),我第一眼就感覺是用了反射,沒關系,可以再進去詳細看看。

Android元件通信方式:元件間的架構設計

果然是反射,是以結論就是:EventBus是基于反射來實作元件間通信

沒想到這2号選手是1号選手的小弟。

ARouter

有請3号選手ARouter,嗯?不對,3号選手不是做跳轉用的嗎?當然不是,ARouter同樣是可以實作元件通信的,可不隻是能做Activity跳轉。

我們可以看看Warehouse,它還有provider和interceptor

class Warehouse {
    // Cache route and metas
    static Map<String, Class<? extends IRouteGroup>> groupsIndex = new HashMap<>();
    static Map<String, RouteMeta> routes = new HashMap<>();

    // Cache provider
    static Map<Class, IProvider> providers = new HashMap<>();
    static Map<String, RouteMeta> providersIndex = new HashMap<>();

    // Cache interceptor
    static Map<Integer, Class<? extends IInterceptor>> interceptorsIndex = new UniqueKeyTreeMap<>("More than one interceptors use same priority [%s]");
    static List<IInterceptor> interceptors = new ArrayList<>();

    static void clear() {
        routes.clear();
        groupsIndex.clear();
        providers.clear();
        providersIndex.clear();
        interceptors.clear();
        interceptorsIndex.clear();
    }
}           

我們主要是講元件通信,這裡就不源碼解析ARouter了。

那一般ARouter怎麼實作呢,其實ARouter内部有個IProvider,我們可以寫一個接口繼承IProvider,這個就相當于一個服務的意思,我們給這個元件寫一個或多個服務,然後将服務提供給其它元件去調用,服務裡面實作自己想要實作的功能。

Android元件通信方式:元件間的架構設計
Android元件通信方式:元件間的架構設計

然後ARouter有一部分操作就是經典的添加到路由表的操作,這個我也不多說了,看到這裡的如果還不知道ARouter的路由表的操作的話,可以先去了解一下,如果想簡單了解,可以看我之前寫的這篇文章juejin.cn/post/714936… ,這裡還是主要講重點代碼

Android元件通信方式:元件間的架構設計

看到上面的代碼,拿到Class,然後調用Class的newInstance,這裡就是反射建立一個對象。是以可以得出結論:ARouter實作元件間通信的方式就是反射

好家夥,沒想到3号選手也是1号選手的小弟。

有點不一樣的是,navigation方法的傳回值return (T) postcard.getProvider();可以看出,雖然它是用了反射,但是還是會讓一個子產品拿到另一個子產品的接口,而要拿到接口,除了兩個子產品有依賴關系的做法之外,還有一個做法就是兩個子產品都共同依賴一個子產品,接口定義在那個子產品裡面。

那有人可能會想,用反射不都可以實作互不依賴的情況下通信了嗎,為什麼還要這樣做。其實這就是一個架構層面的設計,我們這裡隻講技術實作層面的,就不詳細去說。但你可以想想他和2号選手eventBus有什麼不同,為什麼當功能多時,當代碼多時,eventBus可能會看起來覺得很亂,但是ARouter不會。

局部廣播

4号選手局部廣播LocalBroadcastManager,也能實作元件間的通信,它不會也是1号選手反射的小弟吧?

來看看它的做法,首先要有個概念,局部廣播,是不能和普通的廣播一樣做到程序間通信的,其實,它是一個單例。

public void registerReceiver(@NonNull BroadcastReceiver receiver,
        @NonNull IntentFilter filter) {
    synchronized (mReceivers) {
        ReceiverRecord entry = new ReceiverRecord(filter, receiver);
        ArrayList<ReceiverRecord> filters = mReceivers.get(receiver);
        if (filters == null) {
            filters = new ArrayList<>(1);
            mReceivers.put(receiver, filters);
        }
        filters.add(entry);
        for (int i=0; i<filter.countActions(); i++) {
            String action = filter.getAction(i);
            ArrayList<ReceiverRecord> entries = mActions.get(action);
            if (entries == null) {
                entries = new ArrayList<ReceiverRecord>(1);
                mActions.put(action, entries);
            }
            entries.add(entry);
        }
    }
}           

看到注冊廣播的做法,就是把廣播放到一個HashMap裡面

private final HashMap<BroadcastReceiver, ArrayList> mReceivers = new HashMap<>();

至于是什麼HashMap,你可以先不用管,好奇的話可以自己去分析源碼,它的源碼也很簡單,這裡隻為了講重點。再看看發送消息的操作

Android元件通信方式:元件間的架構設計

方法是sendBroadcast,太長了我就截取一部分,從中看得出,它是用了Handler。是以可以得出結論:局部廣播實作元件間通信的方法是Handler+數組+單例

Android元件通信方式:元件間的架構設計

總結

這次主要從技術層面去檢視一些實作元件間通信的方式具體是如何實作的,總共有4位選手:反射、EventBus、ARouter、局部廣播。他們形成了正義的三打一,其實這說明實作元件間通信的方式無外乎兩種,反射和Handler。

反射作為Android中的萬金油,這是類和類加載機制的展現。而Handler是Android程序内通信的橋梁。這些元件哪怕互不依賴,也存在于同一個程序中,是以Handler對他們有效,如果在不同的程序,那當然就要用Binder了。

技術層面的實作,就是這兩種方式,而架構層面去實作元件間的通信,那方式就多了,也更為複雜,雖然直接用反射、EventBus、ARouter都是用了反射,但他們在架構上的設計不同,最終實作的效果也非常的不同。

如果你還有什麼其它元件間的通信方式,可以留言告訴我,如果我感興趣的話,也會再去看看它内部是怎麼去實作。

作者:流浪漢kylin

連結:https://juejin.cn/post/7166632593230659591

來源:稀土掘金

繼續閱讀