组件化/模块化的快速入门及使用之: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地址

相关文章
相关标签/搜索