CC組件化之實戰項目

CCTrainer

CC老司機 邀你上車一起耍

目的:儘可能幫助更多改造原有項目和新手接入CC,產生的各種困惑

  1. 接入成本是否高
  2. 接入後網絡框架是否可抽離
  3. 接入後消息傳遞是否可解耦
  4. 接入後三方庫怎麼做到抽離、共用
  5. 接入後雜亂的資源是否可分割
  6. 接入後是否會增加編譯耗時

一、接入成本不高

CC的文檔也是極盡詳細,大家按着文檔裏的步驟一步一步來就行了。

  • 這裏我的一個建議是,提前把自己的業務模塊劃分好,確定哪幾個是需要分離,哪些是不確定的。需要分離的moudle可以直接接入CC,不確定的也是可以先放着不動,而不像其他的組件化方案一樣,需要對項目整體進行路由改造,這就是billy大佬強調的可漸進式改造。

二、網絡框架可抽離

現在主流的網絡框架是rxjava+retrofit+okhttp,同時結合mvp模式,可以在界面裏把一個網絡請求做到極簡化。組件化後,網絡框架該怎麼處理呢?怎麼避免接口實現類裏動輒上百個接口和一堆分不清是否重複的數據類?怎麼優雅避免網絡請求帶來的內存泄漏問題?下面就探討下這些問題。(具體詳細用例請看CCTrainer項目)

  • 每個組件都要使用網絡框架請求數據,請求的主體是不變的,而每一個請求的接口實現和返回數據是不同的,那我們就把網絡框架骨幹下沉到公共庫裏,接口實現會在各模塊獨自創建,當然數據類也會寫在各自模塊內,這樣就避免了網絡框架的接口和數據類的混亂。至於怎麼寫,大家可以參考下CCTrainer裏的實現方式,把網絡框架下沉到demo_common_base公共庫裏,裏面封裝retrofit請求單例Http,和泛型靜態方法getApiService,通過這個泛型方法傳入不同模塊的請求接口類,實現各模塊的接口類分離,對應的返回數據類也就在各自模塊創建,再也不會混亂不堪。

    調用例子如下

    @Override
    public Observable<Response<User>> login(String code) {
    
        return Http.getApiService(LoginApiService.class).login(code)
                .subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread());
        }
    }
    
    public static <T> T getApiService(Class<T> tClass) {
            return getRetrofit().create(tClass);
    }
    
  • 網絡請求的內存泄漏問題,處理起來也很麻煩,記得以前最開始的時候需要引入rxlifecycler庫,然後要把基類繼承的activityfragment類替換成rxactivityrxfragment,在每個請求處理上加上.compose(this.bindUntilEvent(ActivityEvent.XXX)),這樣處理起來並不是很贊。在CCTrainer裏,會讓你感覺不到處理的存在。CCTrainer裏封裝了一整套的mvp模式,mvp模式實現網絡請求處理和返回數據的刷新操作,大家應該都很熟悉。通過泛型,在每個界面指定presentermodel和實現view接口。而網絡請求裏通過訂閱觀察者把接口返回的數據刷新到界面上,我們可以自定義一個觀察者類,在類裏通過抽象方法getDisposable向子類暴露當前訂閱事件disposable,然後在presenter類裏通過basepresenter裏的rxmanager類持有當前訂閱事件disposable,而rxmanager類是在basepresenter裏初始化,並在onDestroy方法裏取消全部的訂閱事件,避免內存泄漏。

    public void onDestroy() {
        Log.e("presenter", mContext + "-->>" + mRxManager);
        mRxManager.clear();
    }
    

    onDestroy在什麼時候調用呢?答案肯定是在baseactivityonDestroy裏通過mPresenter去調用。

    @Override
    	protected void onDestroy() {
    	super.onDestroy();
    
    	if (mPresenter != null) {
    	    mPresenter.onDestroy();
    }
    
    

    這樣等於在調用網絡請求的同時,把訂閱事件都給管理起來,在界面銷燬的時候去取消這些訂閱事件。

三、消息傳遞可解耦

事件總線大家一般都採用的eventbus,具體使用就不多說。需要傳遞消息的時候,創建一個事件類去發送。集成CC後,不同模塊間也可以用eventbus那樣去發送消息,CC是支持的。但是在A模塊創建的事件類,發送到B模塊去接收,那B模塊也需要有這個事件類。那怎麼辦,一般大家都會下沉到公共庫裏,這樣所有模塊都可以使用這個事件類。項目越來越大模塊越來越多的時候,公共庫的事件包裏就會越來越臃腫,重複的事件和已棄用的事件相當不好維護。同時也違背了路由的基本原則,業務模塊之間是隔離的。CC的路由方案精妙在於組件總線方案,引用billy的話

2.1 組件總線的本質是轉發調用請求

其工作原理類似於電話接線員(中介者模式):組件總線負責收集所有組件類並形成映射表(Key爲字符串,Value爲組件類的對象)。調用組件時,總線根據字符串找到對應的組件類並將調用信息轉發給該組件類,組件執行完成後再通過組件總線將結果返回給調用方

2.2 組件總線只負責通信,即轉發調用請求和返回執行結果。

當A模塊要發一個事件去B模塊時,需要先找到B模塊的組件類,把對應的要處理的事告訴B模塊的組件類,然後就跟B模塊沒有任何關係了。B模塊的組件類收到這個事件去查找自己是否有這樣的一個事件處理,有就執行。大家會說這只是發消息事件發到B模塊的組件類裏,並沒有發送到對應的類裏,那我們再在B模塊的組件類裏去發送一個事件類去通知B模塊裏對應的類接收,這樣就OK了。整個傳遞過程,A模塊跟B模塊沒有產生任何關聯,沒有共用一個類,但是該做的事我們同樣做到了。同時這樣可以把消息事件類給隔離開,每個模塊下都有屬於自己的事件類,再也不怕事件類太多,看着頭皮發麻了。

四、三方庫的抽離

三方庫的依賴都在公共庫的gradle裏,極光推送接收放在消息模塊下,大家可以把自己的極光key配置到JPUSH_APP_KEY裏,接收消息後需要跳轉到其他模塊,跟消息傳遞一樣處理。

CCTrainer集成幾個通用的三方庫,BUGLY、JPUSH等,如果你用的哪個比較不好劃分可以告訴我。

五、資源文件的劃分

這個是最耗時的操作,當初接入CC的時候,花了我一個週末的時間把各種資源給拆分開,歸置到對應的模塊下。其實沒什麼說的,主要看公司的設計UI,好多資源文件需要共用,drawable裏的shape文件,strings裏的字符串,colors裏的顏色等,大部分要下沉到公共庫裏去,拆分的時候本來想着只有一個模塊用,後來發現其他模塊也需要,所以能下沉就下沉到公共庫,這個也是沒辦法,畢竟UI配色方案什麼的都是一套。至於圖片是最不好處理的,但是圖片資源也是需要拆分下,如果圖標只有一個模塊用那就歸置到對應模塊下。
等你歸置完後,再去看各個模塊下得資源文件,就清爽很多。這只是我個人的做法,僅供參考。

六、編譯跟接入前沒什麼區別

項目變大之後,帶來最直觀的感受就是編譯一次耗時比之前更慢了,依賴庫越來越多,依賴的層級關係越來越複雜,A依賴B、C、D、E、F,BCDEF又依賴着公共庫,公共庫裏又一堆三方庫,公共庫又依賴着網絡庫等等。這就是拖死項目編譯時間鬼畜依賴。如果把項目的模塊都打平,不再存在主殼app,所有的模塊全是平級關係,而公共庫只有一個爲各模塊提供公共依賴,那樣,上面的關係將會變的簡單多。
而CC就是這樣的,CC把所有的模塊拍平,不再存在主次關係,有的只是每個模塊依賴一個公共庫而已。

更新:

這裏再跟大家說個小技巧,集成CC後,組件之間都是平級關係,大家在build variants裏去切換環境的時候,各組件需要一個一個切換,每切一次都要等待很長時間的gradle sync,後來才發現,在右側功能欄Gradle裏,app->install下面,可以一步切換不同環境,另外,如果連着多臺設備,也會同步安裝,真的是省心省力。唯一的不足是安裝後,是不會立馬運行起來,需要手動打開。
在這裏插入圖片描述

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