Android Componentization (組件化架構(gòu)) 演變

1.前言

  • 組件化 在Android開(kāi)發(fā)的近幾年來(lái),已經(jīng)由單純編寫(xiě)代碼的概念(工具類(lèi)、第三方組件等等)遷移并應(yīng)用于項(xiàng)目的架構(gòu)上,而在應(yīng)用項(xiàng)目架構(gòu)過(guò)程中又演變出多種不同的實(shí)現(xiàn)方案,隨著現(xiàn)代APP應(yīng)用市場(chǎng)的快速發(fā)展,應(yīng)用開(kāi)發(fā)的時(shí)間、效率、穩(wěn)定性、可擴(kuò)展性、靈活性都要體現(xiàn)出高標(biāo)準(zhǔn)的行業(yè)水平,因此開(kāi)發(fā)者就想出把項(xiàng)目劃分多個(gè)模塊,并且需求滿足協(xié)同與獨(dú)立開(kāi)發(fā),組件化就由此誕生。
  • 文章中實(shí)例 linhaojian的Github

2.目錄

目錄.png

3.組件化發(fā)展史

  • 項(xiàng)目架構(gòu)發(fā)展過(guò)程中,包含非常多種實(shí)現(xiàn)方式,我將它們劃分了三種 傳統(tǒng)、模塊、組件
    項(xiàng)目架構(gòu)分類(lèi).png

3.1 傳統(tǒng)化項(xiàng)目結(jié)構(gòu)

傳統(tǒng)化結(jié)構(gòu).png
  • 傳統(tǒng)化結(jié)構(gòu):通過(guò) 項(xiàng)目?jī)?nèi)業(yè)務(wù)分包 的方式進(jìn)行開(kāi)發(fā),這種方式 維護(hù)、擴(kuò)展都非常困難,并且不方便團(tuán)隊(duì)開(kāi)發(fā),只適應(yīng)小項(xiàng)目。

3.2 模塊化項(xiàng)目結(jié)構(gòu)

模塊化結(jié)構(gòu).png
  • 模塊化結(jié)構(gòu):在AndroidStudio 開(kāi)發(fā)工具內(nèi),通過(guò) 創(chuàng)建module 的方式進(jìn)行劃分不同的業(yè)務(wù)功能,然后在主項(xiàng)目與module 或者 module間構(gòu)建關(guān)聯(lián)(這種關(guān)聯(lián)方式耦合性高),當(dāng)module不合理設(shè)置的適合,會(huì)出現(xiàn)module之間類(lèi)庫(kù)的冗余或者重復(fù)使用。

3.3 組件化項(xiàng)目結(jié)構(gòu)

組件化結(jié)構(gòu).png
  • 組件化結(jié)構(gòu):組件化就是在模塊化的思想上優(yōu)化演變出來(lái),在模塊化思想上,通過(guò)1.抽出module間公用部分;2.使用路由Router解耦module間的交互;3.gradle集成與獨(dú)立配置;4.代碼與資源的隔離,使得module同時(shí)支持集成開(kāi)發(fā)與獨(dú)立開(kāi)發(fā)。

4.定義

  • 將重復(fù)的代碼進(jìn)行封裝,業(yè)務(wù)功能劃分為最小粒子。

5.作用

  • 1.復(fù)用代碼;
  • 2.降低業(yè)務(wù)功能間的依賴(lài)或者關(guān)聯(lián);
  • 3.提供單獨(dú)業(yè)務(wù)運(yùn)行與調(diào)試;

6.特點(diǎn)

  • 1.module具備獨(dú)立性,可單獨(dú)運(yùn)行或調(diào)試
  • 2.module間高度解耦,通過(guò)路由交互
  • 3.代碼與資源隔離;
  • 4.module劃分盡可能粒子化,便于維護(hù)與復(fù)用;

7.組件化架構(gòu)

  • 借助以下的包含實(shí)例的圖,便于更深入了解 組件化 的架構(gòu);
    組件化分層.png
  • 圖中總共分4層 組件集成、業(yè)務(wù)組件、功能組件、運(yùn)行環(huán)境
    • 組件集成:將所有業(yè)務(wù)組件組合到APP的空殼項(xiàng)目中(空殼項(xiàng)目中只包含啟動(dòng)頁(yè),無(wú)任何業(yè)務(wù)邏輯);
    • 業(yè)務(wù)組件:將項(xiàng)目按照功能需要?jiǎng)澐至6容^小的module;
    • 功能組件:將不同業(yè)務(wù)組件中公用部分封裝為各種類(lèi)庫(kù);
    • 運(yùn)行環(huán)境:項(xiàng)目開(kāi)發(fā)中所依賴(lài)的語(yǔ)言庫(kù)或者開(kāi)發(fā)環(huán)境;
  • 從圖中可以發(fā)現(xiàn),組件化只存在 垂直關(guān)系,使各業(yè)務(wù)功能更獨(dú)立與清晰,更適合現(xiàn)代團(tuán)隊(duì)開(kāi)發(fā)的要求。

8.組件化實(shí)踐

  • 下面簡(jiǎn)單配合例子實(shí)踐組件化開(kāi)發(fā)過(guò)程;
    • 項(xiàng)目:類(lèi)似于便利生活的應(yīng)用;
    • 功能:登錄、注冊(cè)、酒店、外賣(mài);
  • 項(xiàng)目結(jié)構(gòu)如下圖:


    例子項(xiàng)目結(jié)構(gòu).png

8.1 base公用

  • 1.將module間公用的代碼封裝base的庫(kù)(如:Log庫(kù)、Base庫(kù)、網(wǎng)絡(luò)請(qǐng)求庫(kù)等等);
  • 2.在4個(gè)模塊中添加引用;


    base引用.png

8.2 module獨(dú)立與集成

  • 將4個(gè)配置為可以單獨(dú)運(yùn)行或者集成運(yùn)行的狀態(tài):
    • 1.打開(kāi)各種module中 gradle.properties文件,添加如下內(nèi)容:
      集成于與獨(dú)立配置1.png
    • 2.打開(kāi)各種module中 build.gradle文件,添加如下內(nèi)容:
      集成于與獨(dú)立配置2.png

      集成于與獨(dú)立配置3.png
    • 3.在module獨(dú)立運(yùn)行時(shí),需要為其添加對(duì)應(yīng)獨(dú)立運(yùn)行的AndroidManifest.xml文件:


      集成于與獨(dú)立配置4.png
  • 注:可以通過(guò)修改isRunAlone的賦值,就能改變module的運(yùn)行狀態(tài),true:可獨(dú)立運(yùn)行,false:集成運(yùn)行。

8.3 多Application初始化

  • 因?yàn)閙odule已具備獨(dú)立運(yùn)行開(kāi)發(fā)的特點(diǎn),所以開(kāi)發(fā)過(guò)程中module中就會(huì)按照自己功能內(nèi)需求初始化所需的第三方類(lèi)庫(kù)或者工具庫(kù),因此module中就會(huì)存在各自的Application類(lèi),那么在集成開(kāi)發(fā)過(guò)程中,我們也需要把module內(nèi)的Application進(jìn)行初始化調(diào)用,不然就會(huì)與獨(dú)立開(kāi)發(fā)不兼容的問(wèn)題,可以通過(guò) 反射 解決:

8.3.1 實(shí)現(xiàn)原理

  • 主application 中,通過(guò) 反射 把其他module的Application初始化。

8.3.2 實(shí)現(xiàn)過(guò)程

* 1.創(chuàng)建一個(gè)抽象BaseApplication,其他module都繼承于它。
public abstract class BaseApplication extends Application{
    public abstract void init(Context context);// 1
    @Override
    public void onCreate() {
        super.onCreate();
        // 初始化所有module公用的類(lèi)庫(kù)
        initPublic();
        // 初始化不同module的Application
        init(getApplicationContext());// 2
    }
    /**
     * 初始化Module功能的類(lèi)庫(kù)
     */
    public void initPublic(){
        ARouter.init(this);
    }
}
  • 注釋1:提供抽象init方法,使其他module都在init函數(shù)中進(jìn)行初始化。
  • 注釋2:統(tǒng)一和兼容集成與獨(dú)立的2種開(kāi)發(fā)環(huán)境
    • 2.讓Login組件繼承BaseApplication
public class LoginAppcation extends BaseApplication {
    @Override
    public void init(Context context) {
        //初始化 login組件 中使用的類(lèi)庫(kù)
        // dagger2 、rxjava ....
    }
}
* 3.在主項(xiàng)目或者main組件中,通過(guò)反射進(jìn)行初始化
public class MainAppcation extends BaseApplication {
    //module中application類(lèi)的路徑
    private static final String[] MODULESLIST =
            {"com.lhj.component.login.LoginAppcation"};
    @Override
    public void init(Context context) {
        //初始化 main組件 中所需的類(lèi)庫(kù)
        // 初始化其他module的Application
        modulesApplicationInit(context);
    }
    /**
     * 通過(guò)反射的方式,獲取指定Application類(lèi)的實(shí)例,并調(diào)用init函數(shù),解決組件化多appplication獨(dú)立的問(wèn)題
     */
    private void modulesApplicationInit(Context context){
        for (String moduleImpl : MODULESLIST){
            try {
                Class<?> clazz = Class.forName(moduleImpl);
                Object obj = clazz.newInstance();
                if (obj instanceof BaseApplication){
                    ((BaseApplication) obj).init(context);
                }
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            } catch (InstantiationException e) {
                e.printStackTrace();
            }
        }
    }
}
  • 通過(guò) 反射 很好的解決組件獨(dú)立開(kāi)發(fā)的多個(gè)Application初始化問(wèn)題,并且同時(shí)兼容集成開(kāi)發(fā)環(huán)境,但是反射就存在性能的問(wèn)題,但暫時(shí)沒(méi)有想到一個(gè)更好的解決方案,請(qǐng)各位大神可以評(píng)論指教。

8.4 module間界面的跳轉(zhuǎn)

8.5 代碼隔離

  • 在集成開(kāi)發(fā)中,主項(xiàng)目需要對(duì)4個(gè)模塊進(jìn)行引用,但為了防止在主項(xiàng)目編譯時(shí)引用了其他module內(nèi)的類(lèi)的問(wèn)題,所以需要實(shí)現(xiàn)代碼隔離,使得真正意義上獨(dú)立。
  • 可以在引用module時(shí),使用以下方式:


    代碼隔離.png

8.6 資源隔離

  • 在集成開(kāi)發(fā)中,如果module之間存在資源名字相同的情況時(shí),可能會(huì)影響項(xiàng)目的運(yùn)行或者誤導(dǎo)開(kāi)發(fā)人員,
    所以建議為不同module的資源文件添加對(duì)應(yīng)的命名規(guī)則
    • 1.xml內(nèi)(string、colors等資源文件)的命名方式可以通過(guò)如下配置方式;
  • 如:將登錄module的xml文件
android {
    //...
    // 實(shí)現(xiàn)資源隔離
    resourcePrefix "login_"
}
* 2. 對(duì)于控件名稱(chēng)與文件名稱(chēng),可根據(jù)自己的喜歡區(qū)分;

8.7 數(shù)據(jù)復(fù)用

  • 項(xiàng)目開(kāi)發(fā)過(guò)程中,經(jīng)常會(huì)出現(xiàn)數(shù)據(jù)需要全局應(yīng)用,因此在多module間需要實(shí)現(xiàn)數(shù)據(jù)復(fù)用,可以通過(guò)以下方式實(shí)現(xiàn):
    • 1.使用Arouter框架中的Provider功能(將復(fù)用的數(shù)據(jù)保存base庫(kù)的Provider中,然后通過(guò)Arouter的navigation函數(shù)獲?。?/li>
    • 2.base庫(kù)中,可以按需添加對(duì)象全局?jǐn)?shù)據(jù)的管理類(lèi)。

8.8 資源復(fù)用

  • 將可能會(huì)復(fù)用的資源,添加至base庫(kù)中,防止資源重復(fù)的問(wèn)題。

9.總結(jié)

  • 到此,Android項(xiàng)目組件化開(kāi)發(fā)介紹完畢!
  • 如果喜歡我的分享,可以點(diǎn)擊 關(guān)注 或者 ,你們支持是我分享的最大動(dòng)力 。
  • linhaojian的Github

歡迎關(guān)注linhaojian_CSDN博客或者linhaojian_簡(jiǎn)書(shū)!

不定期分享關(guān)于安卓開(kāi)發(fā)的干貨。


寫(xiě)技術(shù)文章初心

  • 技術(shù)知識(shí)積累
  • 技術(shù)知識(shí)鞏固
  • 技術(shù)知識(shí)分享
  • 技術(shù)知識(shí)交流
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容