組件化/模塊化的快速入門及使用之:Android中經過對gradle的管理實現組件化;並配合ARouter,隨意跳轉切換

前言:這篇模塊化與組件化的文章,用2篇文章介紹。可能有些人以爲網上已經有了文章,爲何還要寫。第一:爲了記錄本身的正常也算當作筆記。第二:網上當然有好文,但最近看了一篇竟然有150多贊,可是介紹的迷迷糊糊,不少知識點略過。本文重點是讓你快速入門,理解以及使用。java

本次模塊化/組件化講解總共分2篇(必須先了解ARouter,或第三方路由框架):
一、阿里路由框架ARouter的基本使用
二、Android中經過對gradle的管理實現組件化;並配合ARouter,隨意跳轉切換android

其實在沒了解過模塊化/組件化以前,我以爲很是高端,甚至不敢觸碰。多是由於其餘人的博客很高端。其實接觸後發現,其實就是經過gradle的管理實現的。高端的只不過是各模塊module之間的通訊,但是ARouter已經幫咱們解決了全部事情。跟着我一步一步。一塊兒實現,末尾加上本文demo。git

在本文文章開始前,先講個小知識點
A module 引入了B module,B module引入了C module,若是使用的是implementation方式,那麼C對於A來講是不可見的;而使用api方式C是能夠被A訪問的。同理,把C換成開源庫、so文件、aar文件、jar包文件結論也適用。 若是是jar包的,父類要引入子類的話必需要加上路勁如: dirs 'libs', '../moduleB/libs' 。父類引入moduleB中的libsgithub

一、本文demo和最終實現的效果

這裏也和大部分網上同樣,以微信爲例。把微信分爲4個模塊module:home、chat、search、mine。api

  • 對於主程序app來講,這個4個module是其library。運行app後生成咱們的主app;

經過對gradle配置開光的更改,咱們能夠單獨把home模塊,chat模塊,search模塊,mine模塊,自身做爲app運行。這樣模塊化的好處是,解耦。把各模塊給開發人員開發,互不影響,且代碼管理也不會起衝突等等。微信

最終效果是這樣,這裏我只寫了home模塊,chat模塊。其實其餘2個是同樣的。(而且這是一個項目,經過gradle生成的)

這些app的生成,只是改變gradle的配置開光便可生成。網絡

完整app home_module單獨運行app chat_module單獨運行app
從最外層看

二、新建一個項目,用config.gradle統一管理版本號,以避免版本衝突

新建項目,我這裏的項目是CatModuleStu,在項目build.gradle的目錄下,new一個config.gradle。不會的直接複製項目build.gradle,改下名字便可。裏面的內容呢,根據咱們的app裏build.gradle進行更改,app裏的build.gradle以下:app

apply plugin: 'com.android.application'

android {
    compileSdkVersion 28
    defaultConfig {
        applicationId "com.lihang.catmodulestu"
        minSdkVersion 22
        targetSdkVersion 28
        versionCode 1
        versionName "1.0"
        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"

    }
    buildTypes {
        release {
            minifyEnabled false proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } } } dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar']) implementation 'com.android.support:appcompat-v7:28.0.0' implementation 'com.android.support.constraint:constraint-layout:1.1.3' testImplementation 'junit:junit:4.12' androidTestImplementation 'com.android.support.test:runner:1.0.2' androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2' } 複製代碼


意思就是把這些具體的引用用常量表示,每一個module都使用這些常量,因此咱們的confing.gradle以下:框架

ext {
    //這裏是配置開關。是否須要單獨運行。注意,這裏只能打開一個。由於一次只能運行一個。。
    //true 表示須要單獨運行。false表示不須要單獨運行。
    isNeedHomeModule = false
    isNeedChatModule = false
    isNeedFindModule = false
    isNeedMineModule = false

    android = [
            compileSdkVersion: 28,
            buildToolsVersion: "28.0.0",
            minSdkVersion    : 22,
            targetSdkVersion : 28,
            versionCode      : 1,
            versionName      : "1.0.0",
            applicationId    : "com.lihang.catmodulestu",
            applicationHomeId: "com.lihang.homemodule",
            applicationChatId: "com.lihang.chatmodule"
    ]

    //這個對依賴庫版本version的管理,就更加細緻化了
    version = [
            androidSupportSdkVersion: "28.0.0"
    ]

    //系統依賴
    dependencies = [
            "support:appcompat-v7": "com.android.support:appcompat-v7:${version["androidSupportSdkVersion"]}",
            "test:runner"         : 'com.android.support.test:runner:1.0.2',
            "test.espresso"       : 'com.android.support.test.espresso:espresso-core:3.0.2',
            "junit"               : 'junit:junit:4.12'
    ]

    //第三方庫(請原諒個人英語)
    //這樣依賴庫看起來比較清晰(dependencies : 表明系統依賴庫;thridencies表明第三依賴庫)
    thridencies = [
            "butterknife"         : 'com.jakewharton:butterknife:8.8.1',
            "butterknife-compiler": 'com.jakewharton:butterknife-compiler:8.8.1',
            "arouter-compiler"    : 'com.alibaba:arouter-compiler:1.1.4',
            "arouter"             : 'com.alibaba:arouter-api:1.3.1',
    ]
}
複製代碼


這些寫好以後,在咱們的項目build.gradle最頂部,引用一下咱們的config.gradle: apply from: "config.gradle"ide


作完這些後,在來看咱們的app的build.gradle

apply plugin: 'com.android.application'

android {
    compileSdkVersion rootProject.ext.android["compileSdkVersion"]
    defaultConfig {
        applicationId rootProject.ext.android["applicationId"]
        minSdkVersion rootProject.ext.android["minSdkVersion"]
        targetSdkVersion rootProject.ext.android["targetSdkVersion"]
        versionCode rootProject.ext.android["versionCode"]
        versionName rootProject.ext.android["versionName"]
        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
    }
    buildTypes {
        release {
            minifyEnabled false proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } } } dependencies {
    implementation fileTree(include: ['*.jar'], dir: 'libs') implementation rootProject.ext.dependencies["support:appcompat-v7"] testImplementation rootProject.ext.dependencies["junit"] androidTestImplementation rootProject.ext.dependencies["test:runner"] androidTestImplementation rootProject.ext.dependencies["test.espresso"] } 複製代碼

三、 新建baseModule。

新建baseModule,把經常使用的網絡請求,圖片加載,意思就是其餘module共用的東西放進去.包括共用的資源文件,BaseActivity,BaseFragment和application也放在這,上篇說的ARouter的使用,初始化也放在這。這個baseModule是徹底做爲library的。被其餘module和app引用。可是這裏有2個坑
一、引入ARouter的時候,在baseModule的build.gradle裏dependencies標籤下加上:

api rootProject.ext.thridencies["arouter"]
annotationProcessor rootProject.ext.thridencies["arouter-compiler"]
複製代碼

在android的defaultConfig標籤加上

javaCompileOptions {
            annotationProcessorOptions {
                arguments = [moduleName: project.getName()]
            }
        }
複製代碼

其餘module引用baseModule的時候,一樣也要在defaultConfig標籤下加上javaCompileOptions。同時還要引入以下依賴,對!你沒有看錯。若是不加,那麼將不成功。:

annotationProcessor rootProject.ext.thridencies["arouter-compiler"]
複製代碼

二、這裏用butterknife。好比baseModule引用了butterknife後,其餘module引用baseModule的時候會出現個bug、錯誤提示:元素必須爲常量。而後butterknife官方提供了一個處理方案,用R2。可是在切換module做爲app運行的時候,R2會報錯,意思做爲app的時候R2要改爲R。假如你module裏都用了R2,這個時候要所有改爲R。因此不建議baseModule引用butterknife。若有好的解決方法,望告知!!


四、新建homeModule

首先看homeModule的build.gradle:

//這裏就用到了config的配置isNeedHomeModule
//開頭設置,若是打開開光,當成項目運行,不然當成library引用
if (isNeedHomeModule.toBoolean()) {
    apply plugin: 'com.android.application'
} else {
    apply plugin: 'com.android.library'
}

android {
    compileSdkVersion rootProject.ext.android["compileSdkVersion"]

    defaultConfig {
        minSdkVersion rootProject.ext.android["minSdkVersion"]
        targetSdkVersion rootProject.ext.android["targetSdkVersion"]
        if (isNeedHomeModule.toBoolean()) {
            //同時在conifg.gradle配置上homeModule的包名。
            //看成爲application運行的時候,給他配置上獨立的包名
            applicationId rootProject.ext.android["applicationHomeId"]
        }
        versionCode rootProject.ext.android["versionCode"]
        versionName rootProject.ext.android["versionName"]
        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
        //ARouter的使用記得要加哦
        javaCompileOptions {
            annotationProcessorOptions {
                arguments = [moduleName: project.getName()]
            }
        }
    }

    buildTypes {
        release {
            minifyEnabled false proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } } sourceSets {
        main {
            if (isNeedHomeModule.toBoolean()) {
                //這裏目前的作法是2套AndroidManifest,做爲app運行的時候要指定啓動頁
                manifest.srcFile 'src/main/buildApp/AndroidManifest.xml'
            } else {
                manifest.srcFile 'src/main/buildModule/AndroidManifest.xml'
            }
        }
    }

}

dependencies {
    implementation fileTree(include: ['*.jar'], dir: 'libs') implementation rootProject.ext.dependencies["support:appcompat-v7"] testImplementation rootProject.ext.dependencies["junit"] androidTestImplementation rootProject.ext.dependencies["test:runner"] androidTestImplementation rootProject.ext.dependencies["test.espresso"] implementation project(':baseModule') annotationProcessor rootProject.ext.thridencies["arouter-compiler"] } 複製代碼

從上代碼中咱們能夠看到有3點注意的地方:

  • 一、經過isNeedHomeModule判斷是做爲app運行仍是library運行
if (isNeedHomeModule.toBoolean()) {
    apply plugin: 'com.android.application'
} else {
    apply plugin: 'com.android.library'
}
複製代碼

  • 二、經過isNeedHomeModule判斷,若是做爲app運行,給其配置appId
if (isNeedHomeModule.toBoolean()) {
            applicationId rootProject.ext.android["applicationHomeId"]
        }
複製代碼

  • 三、經過isNeedHomeModule判斷,配置2個AndroidManifest,一個有啓動頁的,一個是沒有啓動頁的。
if (isNeedHomeModule.toBoolean()) {
                //這裏目前的作法是2套AndroidManifest,做爲app運行的時候要指定啓動頁
                manifest.srcFile 'src/main/buildApp/AndroidManifest.xml'
            } else {
                manifest.srcFile 'src/main/buildModule/AndroidManifest.xml'
            }
複製代碼

這裏2個AndroidManifest就不貼了,能夠經過個人demo本身去看。其實就是指定一個啓動頁Activity。我這裏爲了demo的清晰,就新建了個SelectHomeActivity,而後就是homeModule模塊,用到的全部Activity配置什麼的都放在這裏。若是是做爲library,也是把全部的配置放在這。被主app引用的時候,他會自動來這裏找的,不用咱們擔憂。

作完這些,當homeModule做爲app運行的時候,咱們主app固然也要判斷,就引用不了homeModule了,build.gradle以下:

dependencies {
   ... //省略部分代碼,便於理解
    if (!isNeedHomeModule.toBoolean()) {
        implementation project(':homeModule') } } 複製代碼

作完這些,就完成了。其餘module也是和這個一樣的配置。經過更改config.gradle的配置isNeedHomeModule,就能夠模塊單獨之間運行了。

五、主app裏使用各module類時。

當成library引用後。好比我這個demo是點擊下方按鈕進行切換。由於咱們使用了ARouter,就能夠這樣(固然這裏引用,你也能夠直接用類名):

//這樣就生成了一個HomeFragment的實例
HomeFragemnt fragment_one = (HomeFragemnt) ARouter.getInstance().build(Constance.FRAGMENT_HOME_PATH).withString("wo", "1").navigation();
複製代碼

結束語:至此,關於android中的模塊化和組件化,就到這裏

這裏我說個我本身的理解:
模塊化:就像這樣,把咱們的「微信」,分爲4個模塊。我理解爲模塊化。

組件化:就像這裏的baseModule,或者你封裝的dialog,popwindow。再好比,你用的網上第三方的一些效果。我理解爲模塊化。和模塊化同樣,都是爲了解耦。

你的點贊是我最大的動力,github地址

相關文章
相關標籤/搜索