Android元件化開發,其實就這麼簡單

語言: CN / TW / HK

我報名參加金石計劃1期挑戰——瓜分10萬獎池,這是我的第3篇文章,點選檢視活動詳情

元件化,在實際的業務開發中,越來越多的會使用這種方式,特別是業務邏輯複雜,功能模組較多的專案,越能凸顯出元件化的優點,比如各個模組拆分,使其業務分明,比如耦合度低,元件之間相互獨立,再比如編譯執行速度大大降低,還有程式碼複用,減少程式碼冗餘,責任明確,減少合併衝突等等,可謂是優點多多,正因為有足夠多的優點,元件化開發,一直是目前專案開發中的所推崇的開發方式之一。

元件化方式的開發,市面上已經有很多的文章去闡述,而關於本章的內容,在於總結,在於有實際的元件化實戰程式碼,有開源的元件化Demo樣例,重在淺顯易懂,重在能夠應用於實際業務,也重在簡單,希望能夠給大家帶來一絲幫助。

本文會從以下四個模組進行闡述,各位老鐵,準備好板凳,我們開始。

1、為什麼要採取元件化

2、如何實現元件化

3、元件化實戰

4、開源及Demo

溫馨提示,開源相關Demo地址,請滑至文末。

一、為什麼要採取元件化

為什麼要採取元件化的方式,這個在文章的開頭已經訴述了部分優點,當然了,在這裡再進行比較詳細的概述一下。

1、提高編譯執行速度

當我們的專案隨著版本的不斷迭代,隨之增加的功能會越來越多,業務也會變得越來越複雜,最終會導致程式碼量急劇上升,相關的三方sdk也會不斷的湧入,以至於,更改一處,就要全量編譯執行,有時候甚至會出現,改一行而等10分鐘的情況,非常的耗時,大大降低了開發效率。

而採取了元件化的方式後,相關業務模組,進行單獨抽取,使得每個業務模組可以獨立當做App存在,和其他模組,互不關聯影響,在編譯執行時期,只考慮本模組即可,從而減少了程式碼的編譯量,提高了編譯執行速度,節約了開發時間。

2、業務拆解,完全解耦

單獨的業務模組進行抽取成一個獨立的元件,也就是相互不關聯的Module,在各自的模組中書寫相關的程式碼,做到,業務拆解,人員拆解,實現真正的解耦。

3、功能複用,節約開發時間

所謂的功能複用,不僅僅是同項目之間的複用,更是以後同樣功能模組的複用,比如A專案中有一個直播模組,後面開發的B專案也有,完全可以移植過來複用,無非就是UI等簡單邏輯的修改。

4、責任明確,分工明確

元件化的專案,各個業務單獨成Module,在獨自的Module中開發相關的業務需求,相對於糅合到一個模組中的專案來說,業務之間拆分更加明確,更加清晰,我負責哪個業務,就去哪個元件下去寫,使得所負責的任務清晰明確,後續定位問題,也能夠第一時間發現並修改。

二、如何實現元件化

曉得了元件化的優點之後,那麼在實際的業務開發中,如何實現呢?首先做為元件化,必須相關業務拆分,單獨成一個Module,並且可以單獨的編譯執行,這是最起碼的一個前提,否則,就不能成為真正意義上的元件化,要實現元件化開發,需要約束且需要的考慮的因素,大概總結如下。

1、程式碼架構拆分,合理規劃

一個專案從0到1的實施,少不了很多基礎的依賴,比如網路,比如圖片載入,比如一些第三方sdk等等,無論你的專案是否是元件化,這些潛在的前提,是必不可少的,可能不是元件化的專案,這些底層的使用會和業務相關的程式碼放到一起,但在元件化的專案,基礎庫和業務層還是要進行剝離的。

首先呢,基礎的依賴是一層,這一層,包含了上層業務層所需要的必須實現,比如網路庫,比如圖片載入庫,比如Dialog載入庫,再比如一些常見的,工具類,資料操作等等,我們可以叫它為基礎庫,基礎庫的存在,除了提供必須的能力之外,更是對能力的封裝,封裝在於,給業務層提供方便的呼叫方式,更是為了可替換,也就是說,後續一旦升級或者更換其他的,直接在基礎庫中更改即可,業務層無需操作,大大減少耦合度,比如圖片載入,一開始我們使用的是Glide,後邊要調整為coil,只需要在基礎庫中更改即可。

基礎庫,在經歷的封裝中,我是把每一個能力項,封裝成了一個Module,比如,網路一個,圖片載入一個等等,這樣做的一個目的,是便於打aar包,也是便於業務層的呼叫。如下圖,是我曾經的封裝,看起來很多,但只向業務層暴露依賴使用方式,畢竟這都是基礎能力,業務層是看不到的,當然,這個看大家的實際業務需求。

image.png

當基礎庫滿足實際的開發需求之後,基礎庫就可以提供給業務層使用,可以以aar的方式,也可以以library的形式,我是比較推薦aar的方式,遠端依賴,方便業務層來呼叫,後期更改,業務層只需要更改版本號即可,對於基礎庫,可以逐個提供,也可以聚合提供。

逐個提供,就是把每個能力項,一個一個的給到業務層,讓業務層進行使用,比較好的一點是方便業務層選擇性使用,需要哪個就用哪個,不會造成記憶體上的浪費。

聚合層提供,就是把所有的能力項糅合到一起,然後進行拓展,給到業務層,優點是隻依賴一個,簡單便捷。

具體的提供,主要還是看實際的業務需求,除了基礎庫之外,在實際的開發中,也就是業務層中,一般還存在一箇中間層,中間層是基礎庫和業務層中間的紐帶,有著承上啟下的作用,一般公共的方法,屬性,資源,資料等都可以放到中間層。

具體的層次劃分,大家可以看下圖,當然了,實際的業務需求,應以本公司的為準。

image.png

在層次劃分中,對於開發者來說,最重要的是業務模組,這是直接和開發相關的,元件化的最直接表現就是這一層次,需要根據不同的業務,來拆分出不同的模組。

2、業務單獨拆分為Module,可單獨編譯執行

上邊已經闡述,元件化的最直接表現就是在業務模組,也就是根據專案的實際功能,拆分出符合的業務模組,比如社群,比如使用者資訊,比如商城等等,拆分之後,一定要能保持單獨執行,本著合則依賴,拆則執行的態度,那麼我們需要解決兩個問題,一個是application和library之間的動態切換,另一個就是需要動態改變清單檔案資源指向,畢竟單獨執行的Module,必須有一個主入口的存在。

application和library之間的動態切換

我們都知道,一個專案在build.gradle中apply plugin只能存在一個application,也就是可執行的模組,一般是我們的主模組,是最終要產出apk包的,而對應的library就是對應的外掛,一般以依賴的方式進行使用,在最終打包的時候進行依賴使用,而在單獨開發的時候就需要單獨執行。

如下舉例,根據動態引數來動態進行配置。

if(is_Module.toBoolean()){ apply plugin: 'com.android.application' }else{ apply plugin: 'com.android.library' }

同樣的,針對applicationId,每個業務元件,如果需要進行區分,也是需要進行判斷的。

if(is_Module.toBoolean()){ applicationId "com.abner.test" }

動態改變清單檔案資源指向

關於主入口,一個專案肯定只有一個,當把元件改為單獨執行的時候,在元件的內部,就不得不去建立一個屬於當前元件的主入口,也就是,單獨執行時使用當前元件的主入口,合併依賴執行時使用主Module裡的主入口。

```xml

            <category android:name="android.intent.category.LAUNCHER" />
        </intent-filter>
    </activity>

```

動態切換清單檔案,也是根據引數來動態進行配置。

sourceSets { main { if (is_Module.toBoolean()) { manifest.srcFile 'src/main/AndroidManifest.xml' } else { manifest.srcFile 'src/main/mainfest/AndroidManifest.xml' } } }

關於業務層的Application,也就是初始化配置的入口,當前元件下的mainfest引入即可,通過以上的配置,只需要改變動態引數值就可以實現,單Module的執行。

3、各模組統一依賴,統一版本號

隨著業務功能的不斷增加,相關的元件也會隨著增加,如果各個元件,都進行單獨依賴,一旦依賴多了之後,就會出現重複依賴,版本號不一致的情況,針對這種問題,最直接的處理方式是,統一gradle檔案,也就是所有的元件統一使用一個,除了一些特殊的依賴之外,其他的都放在統一的檔案之中。

gradle檔案抽取封裝之後,便於所有的依賴管理,也便於統一版本號依賴。如下所示,抽取之後,每個元件下的build.gradle檔案裡,直接使用統一的檔案即可,在程式碼上也是非常的清晰簡單。

app下

image.png

其它Module下

image.png

4、考慮問題一,元件之間頁面跳轉

由於元件之間互不依賴,一個突出的問題就是,頁面之間如何跳轉,比如我A模組要跳轉到B模組中的一個頁面,我該如何跳轉呢?

關於元件間跳轉,這個市場上已經有很多成熟的三方了,比如ARouter ,ActivityRouter,DeepLinkDispatch等等,當然用的比較多的就是ARouter了,已經有了成熟的,我們直接使用即可,沒有必要再重複的造輪子。

通過ARouter 可以很方便的實現元件之間的通訊,更重要的是方便了H5和原生互動之間的跳轉。

官方文件如下

https://github.com/alibaba/ARouter

”一個用於幫助 Android App 進行元件化改造的框架 —— 支援模組間的路由、通訊、解耦“,這是github 上 ARouter 的相關介紹,可以知道,它可以實現元件間的路由功能,路由是指從一個介面上收到資料包,根據資料路由包的目的地址進行定向並轉發到另一個介面的過程,這裡可以體現出路由跳轉的特點,非常適合元件化解耦。

使用起來也是非常的簡單

kotlin ARouter.getInstance().build("/test/test").navigation()

具體使用,看大家可以檢視官網,而關於實際的業務使用,我們放到下面的第3項元件化實戰中。

5、考慮問題二,元件之間資料傳遞

資料之間的傳遞,如果是頁面單純的傳遞資料,直接可以使用ARouter提供的傳遞方式,比如:

kotlin ARouter.getInstance().build("/test/test") .withLong("key1", 666L) .withString("key3", "888") .withObject("key4", new Test("Jack", "Rose")) .navigation();

如果不是頁面之間的傳遞,那麼就需要我們自己定義介面或者通過中間層common來實現了,當然了需要進行邏輯處理。

6、考慮問題三,元件之間Fragment使用

A元件要想使用B元件裡的Fragment,我們可以通過反射的方式進行獲取,既然有了ARouter,我們直接可以使用ARouter提供的方式,非常的簡單。

kotlin fragment = (Fragment) ARouter.getInstance().build("/test/fragment").navigation()

7、考慮問題四,元件之間功能互相呼叫

A元件想要觸發B元件裡一個功能,一個事件,那麼如何處理呢?這個可以利用ARouter的IProvider,具體可以看下面的實戰中程式碼。

8、考慮問題五,元件之間資源命名

元件多了,資源命名難免會出現重複,比如類名,比如layout名字,比如string名字,再比如其他的資源名等等,在實際的開發中,一旦名字重複,有可能造成資源衝突等問題,為了避免這樣的問題出現,一般我們在元件化開發的時候,以元件的名字做為字首,可以進行避免。

團隊協作開發,我們可以進行資源約束,如果不採取約束,就報紅給開發者進行相關提示。

android { .... resourcePrefix "module_xxx" .... }

三、元件化實戰

經過第2項中的闡述,相信對元件化已經有了一個初步的認識,那麼接下來我們就一步一步進入實戰當中,需要注意的是,在實際的業務中,基礎庫肯定是先有的,畢竟是我們開發專案的能力項,因為做為一個Demo,不可能在進行對基礎庫做一個封裝,那樣就太耗時了,所以啊,老鐵們,我們直接進行業務層的書寫,畢竟,元件化,一般就是針對於業務層而言。

1、建立專案

我這裡首先建立一個專案,畢竟不是實際業務,目前就先建立四個模組,app是主模組,common是中間層,account和code是元件,也就是實際的業務模組,如下圖。

image.png

具體的元件架構流程圖如下,common做為中間層,角色承擔十分重要,比如公用的方法,屬性,資料,資源等,都可以放置這層,便於業務模組直接的中轉跳轉或資料獲取。

image.png

2、統一依賴,統一版本號

根專案下新建一個gradle檔案,如下圖

image.png

gradle檔案主要是做為元件之間的統一使用,比如版本號,比如依賴等等,有了這樣的一個公共配置,所有的元件都可以進行統一管理,當然,除了部分無法實現之外。

全部程式碼如下,相關注釋很是齊全。

```

project.ext { //是否允許module單獨除錯 isModuleDebug = false moduleName = ""//單獨除錯module名 //基礎資訊配置 compileSdkVersion = 30 buildToolsVersion = "30.0.2" minSdkVersion = 21 targetSdkVersion = 30 applicationId = "com.abner.assembly" versionCode = 1 versionName = "1.0.0"

//設定app配置
setAppDefaultConfig = {
    extension ->
        //指定為application
        extension.apply plugin: 'com.android.application'
        extension.description "app"

        //公共的apply 主要是用於三方庫
        extension.apply plugin: 'kotlin-android'
        extension.apply plugin: 'kotlin-parcelize'
        extension.apply plugin: 'kotlin-kapt'

        appImplementation = "app"
        //設定專案的android
        setAppAndroidConfig extension.android
        //設定專案的三方庫依賴
        setDependencies extension.dependencies

}

//設定application 公共的android配置
setAppAndroidConfig = {
    extension ->
        extension.compileSdkVersion project.ext.compileSdkVersion
        extension.buildToolsVersion project.ext.buildToolsVersion
        extension.defaultConfig {
            applicationId project.ext.applicationId
            minSdkVersion project.ext.minSdkVersion
            targetSdkVersion project.ext.targetSdkVersion
            versionCode project.ext.versionCode
            versionName project.ext.versionName
            extension.flavorDimensions "versionCode"
            testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"

            javaCompileOptions {
                annotationProcessorOptions {
                    arguments = [AROUTER_MODULE_NAME: project.getName()]
                }
            }
        }

        extension.compileOptions {
            sourceCompatibility JavaVersion.VERSION_1_8
            targetCompatibility JavaVersion.VERSION_1_8
        }
        extension.kotlinOptions {
            jvmTarget = '1.8'
        }

        extension.buildFeatures.dataBinding = true
}

//動態改變,用於單模組除錯
setAppOrLibDefaultConfig = {
    extension ->
        if (project.ext.isModuleDebug && project.ext.moduleName == project.name) {
            extension.apply plugin: 'com.android.application'
            extension.description "app"
        } else {
            extension.apply plugin: 'com.android.library'
            extension.description "lib"

        }
        extension.apply plugin: 'kotlin-android'
        extension.apply plugin: 'kotlin-parcelize'
        extension.apply plugin: 'kotlin-kapt'

        appImplementation = project.name

        //設定通用Android配置
        setAppOrLibAndroidConfig extension.android
        //設定通用依賴配置
        setDependencies extension.dependencies
}

//設定通用的 android配置(可作為project單獨除錯)
setAppOrLibAndroidConfig = {
    extension ->
        extension.compileSdkVersion project.ext.compileSdkVersion
        extension.buildToolsVersion project.ext.buildToolsVersion
        extension.defaultConfig {
            minSdkVersion project.ext.minSdkVersion
            targetSdkVersion project.ext.targetSdkVersion
            versionCode project.ext.versionCode
            versionName project.ext.versionName
            extension.flavorDimensions "versionCode"
            testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
            //ARouter 編譯生成路由
            javaCompileOptions {
                annotationProcessorOptions {
                    arguments = [AROUTER_MODULE_NAME: project.getName()]
                }
            }
        }

        //使用的jdk版本
        extension.compileOptions {
            sourceCompatibility JavaVersion.VERSION_1_8
            targetCompatibility JavaVersion.VERSION_1_8
        }
        extension.kotlinOptions {
            jvmTarget = '1.8'
        }

        //動態改變清單檔案資源指向
        extension.sourceSets {
            main {
                if (project.ext.isModuleDebug && project.ext.moduleName == project.name) {
                    manifest.srcFile 'src/main/manifest/AndroidManifest.xml'
                } else {
                    manifest.srcFile 'src/main/AndroidManifest.xml'
                }
            }
        }

}


//公用的三方庫依賴,慎重引入,主要引入基礎庫依賴
setDependencies = {
    extension ->
        extension.implementation fileTree(dir: 'libs', include: ['*.jar'])
        extension.implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
        extension.implementation 'androidx.core:core-ktx:1.3.1'
        extension.implementation 'androidx.appcompat:appcompat:1.3.1'
        extension.implementation 'com.google.android.material:material:1.4.0'
        extension.implementation 'androidx.constraintlayout:constraintlayout:2.0.1'
        extension.testImplementation 'junit:junit:4.+'
        extension.androidTestImplementation 'androidx.test.ext:junit:1.1.2'
        extension.androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0'
        extension.kapt 'com.alibaba:arouter-compiler:1.5.2'
        if(appImplementation!="common"){
            //common做為中間層,所有的Module都要依賴
            extension.implementation extension.project(path: ':common')
        }
        //針對每個Module單獨進行依賴
        switch (appImplementation) {
            case "app":
                extension.implementation extension.project(path: ':account')
                extension.implementation extension.project(path: ':code')
                break
            case "account":

                break
            case "common"://common元件是一箇中間層,所有的元件都需要依賴此元件,公共的依賴便可放到這裡
                 extension.api 'com.alibaba:arouter-api:1.5.2'//ARouter依賴
                break
        }
}

}

```

相關注釋都有,相信大家一看便懂,無非就是抽取了公共的部分,相當於一個模板,大家完全可以拿走直接用,只需要改成自己的相關依賴即可,不過,針對這個檔案,還是要做一個簡單的概述。

概述一,如何單元件執行

只需要改動下面的兩個引數即可,isModuleDebug引數,true就是開啟單元件執行模式,moduleName就是你要執行的那個Module名字,之所以定義兩個引數,是為了精準到位,元件之間清晰,方便部分元件之間依賴。

//是否允許module單獨除錯 isModuleDebug = false moduleName = ""//單獨除錯module名

概述二,統一管理,以後只維護這個檔案即可

有了這個檔案之後,其他的Module中的build.gradle裡就可以根據需要進行簡寫,比如,app下:

image.png

比如其他元件下

image.png

這樣,不管是依賴,還是版本號,以後統一的在一個檔案裡進行增加和改變,杜絕私自新增三方依賴,便於審閱。

概述三,單個元件如何進行依賴

通過appImplementation引數進行識別是哪一個Module,然後進行單獨區分即可。

image.png

概述四,動態改變清單檔案資源指向

檔案中已經邏輯處理

image.png

3、單Module執行

在第2步中,對所有的元件進行了依賴和版本號管理,同樣也加入了動態改變清單檔案資源指向,那麼一個單獨的元件如何執行呢?我們以Demo中的account模組舉例。

第1步,按照動態改變清單檔案資源指向相關邏輯,新建mainfest目錄,記住,必須和你定義的路徑保持一致,如下:

image.png

第2步,在manifest檔案下複製一份AndroidManifest.xml檔案。

image.png

需要注意,manifest檔案下的AndroidManifest.xml檔案和元件下的AndroidManifest.xml檔案是有區別的,區別就是,當你選擇元件執行時,會編譯manifest檔案下的,當做依賴使用時,走元件下的,除此之外,當你選擇元件執行時,manifest檔案下的AndroidManifest.xml檔案必須有主入口,如下:

image.png

而元件下清單檔案,是不需要這個主入口的。

AndroidManifest.xml檔案建立完之後,如果需要有初始化配置的,大家可以自行建立Application,待相關元件名,樣式引入後,更改統一管理gradle檔案下的引數,如下:

image.png

再看模組目錄,account已經和app保持一致,可以單獨運行了。

image.png

4、元件之間進行跳轉

新建的專案中,我把account和code作為業務元件,兩個元件是互不關聯的,我們要實現的就是這兩個元件之間的跳轉,元件之間跳轉使用的是阿里的ARouter,大家可以按照官網進行一步步依賴,我在第2步中已經依賴進去,最新的版本,如下所示:

image.png

依賴之後,按照官網對其初始化

image.png

在common中間層元件之中,我建立了兩個檔案,一個路由常量類,一個是路由工具類,大家直接可以看原始碼,這裡就不貼程式碼了,就是對ARouter做了一個簡單的封裝而已。

頁面跳轉

從Account元件跳轉到code元件。

給目標頁面設定路由地址

```kotlin @Route(path = CommonRouterConstant.CODE) class CodeActivity : AppCompatActivity() {

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_code)
}

} ```

跳轉目標路由

kotlin CommonRouterManger.get().navigationActivity(CommonRouterConstant.CODE)

頁面帶引數跳轉

已經做了一個簡單的封裝,可通過下面的方式,可變引數,值是Any型別,大家可以參考原始碼。

kotlin CommonRouterManger.get().navigationActivityParams( CommonRouterConstant.CODE, "params" to "引數", "params2" to 100 )

接收引數呢,有兩種形式,一種是intent來接收,一種是Router形式。

intent接收引數

kotlin val stringExtra = intent.getStringExtra("params") val intExtra = intent.getIntExtra("params2", -1)

ARouter形式接收引數

```kotlin @Autowired(name = "params") @JvmField var mParams = ""

@Autowired(name = "params2") @JvmField var mParams2 = -1 ```

ARouter形式接收引數,請一定要記得初始化,一般在父類中即可。

kotlin ARouter.getInstance().inject(this)

5、元件資料共享

資料共享的場景比較常見,比如使用者資訊元件,當用戶登入後,需要儲存使用者的資料,那麼其他相關元件怎麼獲取使用呢,這種時候,我們就可以讓中間元件common,擔負起應有的責任,因為common是所有業務元件都依賴的,使用者資訊元件儲存資料後,在common元件裡寫一個工具類即可,這樣,其他元件都可以通過common元件來獲取資料了。

這種方式比較簡單,大家可以看下原始碼,原始碼中簡單舉了一個例子,在common元件裡定義了工具類,資料模型,提供了儲存和獲取資料的方法,然後account元件裡模擬登入資訊儲存,在code元件裡進行模擬獲取。

當然了除了採用這種方式之外,也可以使用服務的方式進行獲取,首先在common元件定義介面,定義其中自己想要獲取資料的方法,如下:

```kotlin interface AccountUserService : IProvider {

/**
 * AUTHOR:AbnerMing
 * INTRODUCE:獲取使用者資訊
*/
fun getUser(): UserInfo?

} ```

定義好介面之後,同樣也分為兩步,一步是在需要設定資料的元件裡進行傳遞資料,一步是在需要資料的元件裡獲取資料,也就是Demo中的account元件實現其介面,進行傳遞資料,如下:

```kotlin @Route(path = CommonRouterConstant.USER_INFO, name = "AccountUserServiceIml") class AccountUserServiceIml : AccountUserService {

override fun getUser(): UserInfo? {
    //獲取使用者資訊後,轉成需要的物件
    val userJson = DataStoreUtils.getSyncData("user", "")
    if (TextUtils.isEmpty(userJson)) {
        return null
    }
    return Gson().fromJson(userJson, UserInfo::class.java)
}

} ```

哪個元件需要用到資料,就可以如下操作:

kotlin val iml = CommonRouteServiceManager.provide(AccountUserService::class.java) //模擬,通過服務進行獲取使用者相關資訊 iml?.getUser()?.let { Toast.makeText(this, it.data?.nickName, Toast.LENGTH_SHORT).show() }

CommonRouteServiceManager是對ARouter獲取服務做了一個簡單的封裝,大家可以看下原始碼。

6、元件之間呼叫功能

功能的呼叫其實還是用到了ARouter的一個獲取服務的功能,和獲取資料的思路基本一致,這裡舉一個簡單的例子,在Account裡有一個彈出Dialog的功能,但是呢,是在code元件裡進行呼叫,就可以如下操作:

在原有的Service裡增加方法:

```kotlin interface AccountUserService : IProvider {

/**
 * AUTHOR:AbnerMing
 * INTRODUCE:測試彈出Dialog
*/
fun showDialog()

} ```

在account元件裡進行實現方法

```kotlin @Route(path = CommonRouterConstant.USER_INFO, name = "AccountUserServiceIml") class AccountUserServiceIml : AccountUserService { /* * AUTHOR:AbnerMing * INTRODUCE:測試彈窗或其他功能 / override fun showDialog() { AlertDialog.Builder(mContext) .setTitle("測試一個Dialog彈出框") .setMessage("簡單測試以下") .setNegativeButton("取消") { _, _ ->

        }
        .setPositiveButton("確定") { _, _ ->


        }
        .show()
}

private var mContext: Context? = null

override fun init(context: Context?) {
    mContext = context
}

} ```

在code元件裡進行呼叫

kotlin val iml = CommonRouteServiceManager.provide(AccountUserService::class.java) iml?.init(this) iml?.showDialog()

四、開源及Demo

目前呢,原始碼中只是測試的Demo,簡單的舉例了元件化開發的相關流程及所需要,所注意的事項,大家可以做為參考,而實際的開發中,除了業務的不同,但所執行的流程基本是一致的,還有,關於ARouter的使用,其實官網中還有很多的使用方式,這個大家去官網看即可,至於基礎庫的封裝,每個公司所實現的方式不同,最重要的是業務層的元件化實現。

Github地址

https://github.com/AbnerMing888/AndroidAssembly