CC 組件化開發

以前開發針對功能較多的應用,一般是通過分包的形式將各個模塊進行解耦,然后將將通用的工具或者邏輯進行封裝供其他模塊使用,但是這樣依然很難進行有效的解耦,因為其他包里面的類依然可以通過new的方式進行創建,很難進行把控,尤其針對各個功能模塊可能需要單獨上線的應用更是無法滿足要求,不經意就會出現空指針異常。

來到現在的項目組之后接觸了一個組件話開發的框架CC,一個可以實現組件動態組冊,完成各個組件很好的隔離的框架,好處自然不用多說,此文章我們先大致介紹一下組件化的基本知識:

第一個問題:什么是組件化?

組件化這三個字顧名思義就是將一個項目拆成多個項目,也就是說一個項目由多個組件組成,就比如一輛汽車,你可以把它拆分成發動機、底盤、車身和電氣設備等四個模塊;又比如一架飛機你可以把它拆分成機身、動力裝置、機翼、尾翼、起落裝置、操縱系統和機載設備等7個模塊,那么你在開發項目的時候是否也應該把你的項目根據業務的不同拆分成不同的模塊,如果不同的模塊可以單獨運行的話,我們就可以叫它組件。

第二個問題:組件化開發有什么好處?

  • 現在市場上的app幾乎都有個人中心這個東西,那么是不是可以把個人中心的所有業務都提到單獨的一個模塊中,當然是可以的,我們將它放在一個單獨的模塊中,這個時候你會發現一些好處:
  • 耦合度降低了
  • 你需要修改個人中心的時候直接從這個模塊中找修改的地方就好了
  • 你需要測試的時候直接單獨運行這個模塊就好了,不需要運行整個項目(測試的效率是不是提高了很多呢)
  • 由于測試的時候可以單獨編譯某個模塊編譯速度是不是提高了呢
  • 如果是團隊開發的話,每個人單獨負責自己的模塊就好了(媽媽再也不用擔心我的代碼被人家修改了)。

第三個問題:組件化開發的步驟(以我的demo目錄為例,我的demo主要有一個主程序【app】和四個組件【component_base,libraryone,librarytwo,xpush】demo地址:


one.png

配置流程

1. 組件化開發肯定是有一個或某兩個組件是各個組件都會引用的,一般我們會把log工具類、網絡請求封裝框架、自定義的view接口類、以及下沉的接口等封裝成base組件供其他組件可以調用,我們可以在這個所有組件都會依賴的組件的build.gradle文件中依賴cc,方式如下:

dependencies {
   ...
    //以下是依賴CC
   *** api 'com.billy.android:cc:2.1.5'***
}

2. 在項目的根目錄下的build.gradle依賴自動注冊插件:

    dependencies {
        classpath 'com.android.tools.build:gradle:3.2.0'
        classpath 'com.billy.android:cc-register:1.0.9'

        // NOTE: Do not place your application dependencies here; they belong
        // in the individual module build.gradle files
    }

3. 在項目的根目錄下新建cc-settings-2.gradle文件,鍵入以下內容:

project.apply plugin: 'cc-register'

4. 在非主項目的組件中替換原來的apply plugin ‘XXX’為以下:

ext.alwaysLib = true
apply from: rootProject.file('cc-settings-2.gradle')

5. 在主項目中替換原來的apply plugin ‘xxx’為以下:

ext.mainApp = true
project.apply plugin: 'cc-register'

6. 最后一步,也是最關鍵的一步,將各組件添加到主項目中(在app的build.gradle中添加),否則調用會失敗:

dependencies {
    ....
    
    api project(':component_base')
    addComponent 'libraryone'
    addComponent 'component_base'
    addComponent 'librarytwo'
    addComponent 'xpush'
}

開發流程

以上是依賴CC進行組件開發的配置流程,下面根據自己的項目說一下開發流程,我們以base組件和libraryone組件為例:

1. 由于在B組件可能存在調用A組件的一些實例,但是各個組件又都是項目獨立的,所以需要將對外開放使用的對象抽象到base組件,我的demo如下:

two.png

其中的三個接口分別是在另外三個組件里面實現的,同時也把各個組件使用的常量也在base組件里面定義了ComponentConst類,方便外部組件調用:

public class ComponentConst {

    public interface Component_A{
        String NAME = "Component_A";

        public interface Action{
            String SHOW = "Component_A_show";
            String HIDE = "Component_A_hide";
        }

    }

    public interface Component_B{
        String NAME = "Component_B";

        public interface Action{
            String SHOW = "Component_B_show";
            String HIDE = "Component_B_hide";
        }

    }

    public interface Component_C{
        String NAME = "Component_C";

        public interface Action{
            String ShOW = "Component_C_show";
            String HIDE = "Component_CChide";
            String CONTENT = "setContent";
        }
    }
}

2. 各個組件需要有個類實現IComponent接口,以libraryone為例:

public class Component_A implements IComponent {
    @Override
    public String getName() {
    //此出的名字是外部調用該組件時傳入的名稱,用于區分不同的組件
        return ComponentConst.Component_A.NAME;
    }

    @Override
    public boolean onCall(CC cc) {
    //此處的action是外部調用該組件內部的方法的標記,用于區分該組件內不同的功能或者方法,由于libraryone依賴了base組件,所以可以直接引用base組件里的常量
        String action = cc.getActionName();
        switch (action) {
            case ComponentConst.Component_A.Action.SHOW:
                ComponentAManager componentAManager = ComponentAManager.getInstance();
                CC.sendCCResult(cc.getCallId(),CCResult.successWithNoKey(componentAManager));
                break;
            case ComponentConst.Component_A.Action.HIDE:
                break;
        }

        return true;
    }
}

3. 在libraryone里面實現base中定義的IComponentAManager接口:

public class ComponentAManager implements IComponentAManager {

    private static final String TAG = "ComponentAManager";
    private static ComponentAManager componentAManager;
    private ComponentAManager(){}
    public static ComponentAManager getInstance(){
        if (componentAManager == null){
            synchronized (ComponentAManager.class){
                if (componentAManager == null){
                    componentAManager = new ComponentAManager();
                }
            }
        }
        return componentAManager;
    }
    
    private UserBean getUserBeanFromComponentA(){
        Log.d(TAG, "getUserBeanFromComponentA: ");
        UserBean userBean = new UserBean("ComponentA",18,180.7f);
        return userBean;
    }

    @Override
    public UserBean show() {
        Log.d(TAG, "show: ");
        return getUserBeanFromComponentA();
    }

    @Override
    public void set(UserBean userBean) {

    }
}

4. 此時我們如果想在其他組件或者任何地方(非libraryone組件內)獲取到ComponentAManager實例,發現new是不行的,getInstance也是不行的,也就是使用CC的一個好處,可以很好的隔離個組件的功能界限,那么我們怎么獲取呢,用如下方法(此處我是在app主程序中獲取的):

          CCResult ccResult = CC.obtainBuilder(ComponentConst.Component_A.NAME)
                        .setActionName(ComponentConst.Component_A.Action.SHOW)
                        .build()
                        .call();
                //是否獲取成功
                if (ccResult.isSuccess()){
                    IComponentAManager componentAManager = ccResult.getDataItemWithNoKey();
                    UserBean userBean = componentAManager.show();
                    if (userBean != null){
                        tv.setText("");
                        tv.setText("name:"+userBean.name+"\n"
                        +"age:"+userBean.age+"\n"
                        +"height:"+userBean.getHeight());
                    }

                }

當然也可以僅僅在libraryone里面進行操作而不是返回一個對象,比較簡單,可以自己琢磨下。今天主要講了CC的使用,下一篇說結合CC的源碼分享一下內部的實現原理。

?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,505評論 6 533
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,556評論 3 418
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,463評論 0 376
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,009評論 1 312
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,778評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,218評論 1 324
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,281評論 3 441
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,436評論 0 288
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,969評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,795評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,993評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,537評論 5 359
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,229評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,659評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,917評論 1 286
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,687評論 3 392
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,990評論 2 374

推薦閱讀更多精彩內容

  • 不怕跌倒,所以飛翔 組件化開發 參考資源 Android組件化方案 為什么要組件化開發 解決問題 實際業務變化非常...
    筆墨Android閱讀 3,001評論 0 0
  • 問題 在已經開發過幾個項目的童鞋,如果這時需要重新開發一個新項目,是否需要自己重新搭建框架呢,還是從老項目中拷貝粘...
    8ba406212441閱讀 43,091評論 84 381
  • MVVMHabitComponent 關于Android的組件化,相信大家并不陌生,網上談論組件化的文章,多如過江...
    goldze閱讀 5,217評論 2 22
  • 1. App項目組件化 做移動開發的同學都會發現這兩年在移動開發圈子里最火的就是組件化了,組件化不同的實現方案也引...
    monkey01閱讀 10,621評論 6 56
  • 黑色情調 有一種感覺莫名其妙, 有一種愛情無法得到。 有一種執著傻的可笑, 有一種調叫黑色情調。 黑...
    生來彷徨ii閱讀 338評論 0 2