您的当前位置:首页正文

Android组件化架构实战

2024-11-28 来源:个人技术集锦

说一千道一万不如亲自撸一遍,下面就直接新建项目,一步步搭建一个组件化架构的应用程序。下图为Demo项目整体架构:

简单做一下说明:

App模块为主模块,该模块不处理相关业务逻辑,只需将各个业务组件加以整合即可。另外需要说明的是,如果应用中使用了微信支付等相关SDK,要求相关回调类必须放置在主模块对应的包中,这时候就需要在app模块中添加相关逻辑处理了,不过最后通信一般都是用EventBus通知相关子模块。

中间层为相关业务模块,主要处理应用相关的业务逻辑

common层为公共模块,主要存放一些公共类库、公共资源等

app主模块依赖关系:

业务模块launcher依赖关系(其他业务模块一样):

common模块依赖关系(目前只依赖了Arouter和Glide):

8.1.1 创建公共配置文件

上面介绍了项目整体架构以及相互依赖关系,下面需要添加一些公共配置供所有模块使用,以免每个模块重复添加相同的配置。

新建common_config.gradle文件

project.ext {
	//1. APP全局配置变量
    //2. debug 开关,切换全量编译和分模块编译开关
    //3. app全局默认配置
    //4. app业务模块配置
    //5. lib全局默认配置
    //6. lib业务模块配置
    //7. dependencies公共依赖配置
}

“project”也可以省略,它相当于类中的“this”关键词。按照上面的说明一步步添加配置相关代码

第一步:App全局变量配置

app_compileSdkVersion = 29	//编译SDK版本
app_buildToolsVersion = "30.0.2"	//buildTools版本
app_minSdkVersion = 21	//APP兼容最小版本号
app_targetSdkVersion = 29	//APP目标版本号,在该版本中充分测试
app_versionCode = 1    //APP版本号
app_versionName = '0.0.1'   //APP版本名称
applicationId = ''   //应用包名
prefix_applicationId = ''  //appid前缀,debug模式下动态设置各个业务模块的appid
prefix_outputApkName = 'fanrenke-android-app-'  //生成apk包名前缀,签名打包配置使用
//签名信息配置
keyAlias = ''
keyPassword = ''
storeFile = ''
storePassword = ''

第二步:debug 开关,切换全量编译和分模块编译开关

isDebug = false	//debug模式开关

也可以单独为每一个模块设置一个开关分开控制,这里我设置了统一的开关,debug模式下所有的业务组件模块均可以独立编译运行。

第三步:app全局默认配置

//设置App默认配置,该配置不受isDebug状态影响
setAppDefaultConfig = {
    extension ->
        //引用Application插件库
        extension.apply plugin: 'com.android.application'
        extension.description 'app'
        //配置android.defaultConfig相关属性
        extension.android.defaultConfig {
            applicationId prefix_applicationId + extension.getName()
        }
        //配置android及其子配置相关属性
        extension.android setAndroidDefaultConfig
        //配置相关公共依赖
        extension.dependencies setDependencies
}

之所以不受debug状态影响关键在于extension.android setAndroidDefaultConfig属性,也就是setAndroidDefaultConfig这段代码块配置:

setAndroidDefaultConfig = {
    compileSdkVersion app_compileSdkVersion
    buildToolsVersion app_buildToolsVersion
    defaultConfig {
        minSdkVersion app_minSdkVersion
        targetSdkVersion app_targetSdkVersion
        versionCode app_versionCode
        versionName app_versionName
        testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
        //设置路由模块配置
        javaCompileOptions {
            annotationProcessorOptions {
                arguments = [AROUTER_MODULE_NAME: project.getName()]
            }
        }
    }

这一段配置代码在下面步骤也会用到。

第四步:app业务模块配置

//设置APP全局默认配置,debug模式下各个模块分量编译
setAppConfig = {
    extension ->
        //引用Application插件库
        extension.apply plugin: 'com.android.application'
        extension.description 'app'
        //配置android.defaultConfig相关属性
        extension.android.defaultConfig {
            applicationId prefix_applicationId + extension.getName()
        }
        //配置android及其子配置相关属性
        extension.android setAndroidConfig
        //配置相关公共依赖
        extension.dependencies setDependencies
}

关键配置setAndroidConfig:

setAndroidConfig = {
    compileSdkVersion app_compileSdkVersion
    buildToolsVersion app_buildToolsVersion
    defaultConfig {
        minSdkVersion app_minSdkVersion
        targetSdkVersion app_targetSdkVersion
        versionCode app_versionCode
        versionName app_versionName
        testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
        //设置路由模块配置
        javaCompileOptions {
            annotationProcessorOptions {
                arguments = [AROUTER_MODULE_NAME: project.getName()]
            }
        }
    }
    //设置debug模式下各个模块配置文件路径
    sourceSets {
        main {
            if (isDebug) {
                manifest.srcFile 'src/main/module/AndroidManifest.xml'
            } else {
                manifest.srcFile 'src/main/AndroidManifest.xml'
                //集成开发模式下排除debug文件夹中的所有java文件
                java {
                    exclude 'debug/**'
                }
            }
        }
    }
}

主要区别在于添加了配置文件和debug模式下相关类的引用。

第五步:lib全局默认配置

//设置Lib全局默认配置,该配置不受isDebug状态影响
setLibDefaultConfig = {
    extension ->
        //添加library依赖
        extension.apply plugin: 'com.android.library'
        extension.description 'lib'
        //配置android及其子配置相关属性
        extension.android setAndroidDefaultConfig
        //配置相关公共依赖
        extension.dependencies setDependencies
}

关键配置setAndroidDefaultConfig在上面已经介绍。

第六步:lib业务模块配置

//设置Lib全局默认配置
setLibConfig = {
    extension ->
        //添加library依赖
        extension.apply plugin: 'com.android.library'
        extension.description 'lib'
        //配置android及其子配置相关属性
        extension.android setAndroidConfig
        //配置相关公共依赖
        extension.dependencies setDependencies
}

关键配置setAndroidConfig在上面已经介绍。

第七步:dependencies公共依赖配置

//设置依赖
setDependencies = {
    //设置通用依赖
    implementation fileTree(dir: 'libs', include: ['*.jar'])
    implementation 'androidx.appcompat:appcompat:1.2.0'
    implementation 'com.google.android.material:material:1.2.1'
    testImplementation 'junit:junit:4.+'
    androidTestImplementation 'androidx.test.ext:junit:1.1.2'
    androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0'
    //设置路由依赖
    annotationProcessor 'com.alibaba:arouter-compiler:1.2.1'
}

下面呈上全部配置代码:

// Top-level build file where you can add configuration options common to all sub-projects/modules.
project.ext {
    app_compileSdkVersion = 29
    app_buildToolsVersion = "30.0.2"
    app_minSdkVersion = 21
    app_targetSdkVersion = 29
    app_versionCode = 1    //APP版本号(可配置参数)
    app_versionName = '0.0.1'   //APP版本名称(可配置参数)
    applicationId = 'com.allen.fanrenke'   //应用包名(可配置参数)
    prefix_applicationId = 'com.allen.'  //可配置参数(可配置参数)
    prefix_outputApkName = 'fanrenke-android-app-'  //生成apk包名前缀(可配置参数)
    //签名信息配置
    keyAlias = ''
    keyPassword = ''
    storeFile = ''
    storePassword = ''

    //debug模式下可以分开编译模块
    isDebug = false

    /*------------------------分割线----------------------------*/

    //设置App默认配置,该配置不受isDebug状态影响
    setAppDefaultConfig = {
        extension ->
            //引用Application插件库
            extension.apply plugin: 'com.android.application'
            extension.description 'app'
            //配置android.defaultConfig相关属性
            extension.android.defaultConfig {
                applicationId prefix_applicationId + extension.getName()
            }
            //配置android及其子配置相关属性
            extension.android setAndroidDefaultConfig
            //配置相关公共依赖
            extension.dependencies setDependencies
    }

    /*--------------------分割线-----------------------*/

    //设置APP全局默认配置,debug模式下各个模块分量编译
    setAppConfig = {
        extension ->
            //引用Application插件库
            extension.apply plugin: 'com.android.application'
            extension.description 'app'
            //配置android.defaultConfig相关属性
            extension.android.defaultConfig {
                applicationId prefix_applicationId + extension.getName()
            }
            //配置android及其子配置相关属性
            extension.android setAndroidConfig
            //配置相关公共依赖
            extension.dependencies setDependencies
    }

    //设置Lib全局默认配置,该配置不受isDebug状态影响
    setLibDefaultConfig = {
        extension ->
            //添加library依赖
            extension.apply plugin: 'com.android.library'
            extension.description 'lib'
            //配置android及其子配置相关属性
            extension.android setAndroidDefaultConfig
            //配置相关公共依赖
            extension.dependencies setDependencies
    }

    //设置Lib全局默认配置
    setLibConfig = {
        extension ->
            //添加library依赖
            extension.apply plugin: 'com.android.library'
            extension.description 'lib'
            //配置android及其子配置相关属性
            extension.android setAndroidConfig
            //配置相关公共依赖
            extension.dependencies setDependencies
    }

    //设置Android配置,该配置不受isDebug状态影响
    setAndroidDefaultConfig = {
        compileSdkVersion app_compileSdkVersion
        buildToolsVersion app_buildToolsVersion
        defaultConfig {
            minSdkVersion app_minSdkVersion
            targetSdkVersion app_targetSdkVersion
            versionCode app_versionCode
            versionName app_versionName
            testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
            //设置路由模块配置
            javaCompileOptions {
                annotationProcessorOptions {
                    arguments = [AROUTER_MODULE_NAME: project.getName()]
                }
            }
        }
    }

    //设置Android配置
    setAndroidConfig = {
        compileSdkVersion app_compileSdkVersion
        buildToolsVersion app_buildToolsVersion
        defaultConfig {
            minSdkVersion app_minSdkVersion
            targetSdkVersion app_targetSdkVersion
            versionCode app_versionCode
            versionName app_versionName
            testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
            //设置路由模块配置
            javaCompileOptions {
                annotationProcessorOptions {
                    arguments = [AROUTER_MODULE_NAME: project.getName()]
                }
            }
        }
        //设置debug模式下各个模块配置文件路径
        sourceSets {
            main {
                if (isDebug) {
                    manifest.srcFile 'src/main/module/AndroidManifest.xml'
                } else {
                    manifest.srcFile 'src/main/AndroidManifest.xml'
                    //集成开发模式下排除debug文件夹中的所有java文件
                    java {
                        exclude 'debug/**'
                    }
                }
            }
        }
    }

    //设置依赖
    setDependencies = {
        //设置通用依赖
        implementation fileTree(dir: 'libs', include: ['*.jar'])
        implementation 'androidx.appcompat:appcompat:1.2.0'
        implementation 'com.google.android.material:material:1.2.1'
        testImplementation 'junit:junit:4.+'
        androidTestImplementation 'androidx.test.ext:junit:1.1.2'
        androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0'
        //设置路由依赖
        annotationProcessor 'com.alibaba:arouter-compiler:1.2.1'
    }

}
8.1.2 模块配置

这里的模块主要指三种模块:

第一、需要一直参与编译的模块,如App模块

第二、debug模式下单独编译运行,release模式下以lib包形式被App依赖整体参与编译运行,如main等模块

第三、公共类库框架,这类模块不论debug模式还是release模式都要参与编译运行,如common模块以及其依赖的Glide、ARouter框架等。

下面将分开介绍这三种模块各自的配置方式。

App模块配置

引用common_config并添加相关配置

//引用common_config.gradle
apply from: "${rootProject.rootDir}/common_config.gradle"
//添加相关公共配置
project.ext.setAppDefaultConfig project

由于setAppDefaultConfig中已经有相关公共配置,因此android{}代码块中可以将相关公共通用配置删除,如下为android{}代码块全部内容:

android {
    //配置签名信息
    signingConfigs {
        config {
            keyAlias project.ext.keyAlias
            keyPassword project.ext.keyPassword
            storeFile file(project.ext.storeFile)
            storePassword project.ext.storePassword
        }
    }
    defaultConfig {
    }
    buildTypes {
        release {
            minifyEnabled true
            zipAlignEnabled true
            shrinkResources true
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
            //release模式下添加应用签名信息
            signingConfig signingConfigs.config
        }
        debug {
            //debug模式下添加应用签名信息,兼容相关第三方SDK需要签名才能进行操作的问题
            signingConfig signingConfigs.config
        }
    }
    compileOptions {
        sourceCompatibility JavaVersion.VERSION_1_8
        targetCompatibility JavaVersion.VERSION_1_8
    }
    //输出apk
    applicationVariants.all { variant ->
        variant.outputs.all {
            outputFileName = project.ext.prefix_outputApkName + "${variant.versionName}-${buildTime()}.apk"
        }
    }
}

static def buildTime() {
    def df = new SimpleDateFormat("yyyyMMddHHmmss")
    df.setTimeZone(TimeZone.getDefault())
    return df.format(new Date())
}

dependencies依赖配置:

dependencies {
    implementation 'androidx.constraintlayout:constraintlayout:2.0.4'
    if (project.ext.isDebug) {    //debug状态下分量编译
        implementation project(':commonlib')
    } else {
        api project(':launcher')
        api project(':main')
        api project(':find')
        api project(':mine')
    }
}

呈上全部配置代码:

import java.text.SimpleDateFormat

apply from: "${rootProject.rootDir}/common_config.gradle"
project.ext.setAppDefaultConfig project

android {

    //配置签名信息
    signingConfigs {
        config {
            keyAlias project.ext.keyAlias
            keyPassword project.ext.keyPassword
            storeFile file(project.ext.storeFile)
            storePassword project.ext.storePassword
        }
    }

    defaultConfig {

    }

    buildTypes {
        release {
            minifyEnabled true
            zipAlignEnabled true
            shrinkResources true
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
            //release模式下添加应用签名信息
            signingConfig signingConfigs.config
        }
        debug {
            //debug模式下添加应用签名信息,兼容相关第三方SDK需要签名才能进行操作的问题
            signingConfig signingConfigs.config
        }
    }
    compileOptions {
        sourceCompatibility JavaVersion.VERSION_1_8
        targetCompatibility JavaVersion.VERSION_1_8
    }

    //输出apk
    applicationVariants.all { variant ->
        variant.outputs.all {
            outputFileName = project.ext.prefix_outputApkName + "${variant.versionName}-${buildTime()}.apk"
        }
    }
}

static def buildTime() {
    def df = new SimpleDateFormat("yyyyMMddHHmmss")
    df.setTimeZone(TimeZone.getDefault())
    return df.format(new Date())
}

dependencies {
    implementation 'androidx.constraintlayout:constraintlayout:2.0.4'
    if (project.ext.isDebug) {    //debug状态下分量编译
        implementation project(':commonlib')
    } else {
        api project(':launcher')
        api project(':main')
        api project(':find')
        api project(':mine')
    }
}

main模块配置

直接呈上全部配置代码,这里主要讲讲相关配置文件以及debug状态下相关类的创建。

apply from: "${rootProject.rootDir}/common_config.gradle"
if (project.ext.isDebug) {
    project.ext.setAppConfig project
} else {
    project.ext.setLibConfig project
}

android {

    defaultConfig {
        consumerProguardFiles "consumer-rules.pro"
    }

    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
        }
    }
    compileOptions {
        sourceCompatibility JavaVersion.VERSION_1_8
        targetCompatibility JavaVersion.VERSION_1_8
    }
}

dependencies {
    api project(':commonlib')
}

新建debug模式下相关配置文件:

在main模块main文件夹下新建module文件件,新建AndroidManifest.xml工程配置文件;在main/java文件夹下新建debug包,添加MainApp类,作为debug模式下main模块的程序入口。这里就牵涉到common_config中的相关配置代码:

//设置debug模式下各个模块配置文件路径
sourceSets {
    main {
        if (isDebug) {
            manifest.srcFile 'src/main/module/AndroidManifest.xml'
        } else {
            manifest.srcFile 'src/main/AndroidManifest.xml'
            //集成开发模式下排除debug文件夹中的所有java文件
            java {
                exclude 'debug/**'
            }
        }
    }
}

上面的配置说明debug模式下配置文件取src/main/module路径下的AndroidManifest.xml,否则取src/main路径下的AndroidManifest.xml。release模式下debug包中的相关类不参与编译打包。测试一下。

release模式下:

可见其他业务组件模块不能直接单独编译,配置文件取的是src/main路径下的AndroidManifest.xml。

debug模式下:

可见其他业务组件模块都可以单独参与编译,配置文件取的是src/main/module路径下的AndroidManifest.xml。

common模块配置

直接上代码:

apply from: "${rootProject.rootDir}/common_config.gradle"
project.ext.setLibDefaultConfig project

android {
    defaultConfig {
        versionCode project.ext.app_versionCode
        versionName project.ext.app_versionName
        consumerProguardFiles "consumer-rules.pro"
    }

    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
        }
    }
    compileOptions {
        sourceCompatibility JavaVersion.VERSION_1_8
        targetCompatibility JavaVersion.VERSION_1_8
    }
}

dependencies {
    api 'com.alibaba:arouter-api:1.4.0'
    api 'com.github.bumptech.glide:glide:4.11.0'
}

没啥讲的,就是引用common_config.gradle,删除公共配置,添加独有配置

8.1.3 深入分析

上一节对组件化的相关配置做了详细地介绍,但实际上按照先前的方法去搭建组件化架构是有一些漏洞的,主要体现在两个方面:

第一、debug模式下app模块如果也能直接编译运行,由于此时app模块已经脱离依赖其他业务组件,就会导致在app模块中相关类找不到,这样一来app模块就无法编译运行了

第二、业务组件中,如果入口为Activity还好说,但是如果模块入口就是一个Fragment该怎么办,这样debug模式下业务组件该如何单独运行调试

可能还存在其他问题,以后慢慢发掘。现针对上面两个问题加以分析处理。

app模块处理方式

这里大体有两种处理方式:

① debug模式下禁止app模块单独编译运行

这种处理方式类似于debug模式下将app模块以lib包形式处理,具体实现方式如下:

import java.text.SimpleDateFormat

apply from: "${rootProject.rootDir}/common_config.gradle"
//注释1
if (project.ext.isDebug) {   //debug状态下不能运行
    project.ext.setLibDefaultConfig project
} else {
    project.ext.setAppDefaultConfig project
}

android {

    //配置签名信息
    signingConfigs {
        config {
            keyAlias project.ext.keyAlias
            keyPassword project.ext.keyPassword
            storeFile file(project.ext.storeFile)
            storePassword project.ext.storePassword
        }
    }

    defaultConfig {

    }

    buildTypes {
        release {
            minifyEnabled true
            zipAlignEnabled true
            //注释2
            //一些属性debug模式下是不能使用的
            if (!project.ext.isDebug) {
                shrinkResources true
            }
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
            //release模式下添加应用签名信息
            signingConfig signingConfigs.config
        }
        debug {
            //debug模式下添加应用签名信息,兼容相关第三方SDK需要签名才能进行操作的问题
            signingConfig signingConfigs.config
        }
    }
    compileOptions {
        sourceCompatibility JavaVersion.VERSION_1_8
        targetCompatibility JavaVersion.VERSION_1_8
    }

    //注释3
    //debug模式下不能输出apk
    if (!project.ext.isDebug) {
        applicationVariants.all { variant ->
            variant.outputs.all {
                outputFileName = project.ext.prefix_outputApkName + "${variant.versionName}-${buildTime()}.apk"
            }
        }
    }
}

static def buildTime() {
    def df = new SimpleDateFormat("yyyyMMddHHmmss")
    df.setTimeZone(TimeZone.getDefault())
    return df.format(new Date())
}

dependencies {
    implementation 'androidx.constraintlayout:constraintlayout:2.0.4'
    if (project.ext.isDebug) {    //debug状态下分量编译
        implementation project(':commonlib')
    } else {
        api project(':launcher')
        api project(':main')
        api project(':find')
        api project(':mine')
    }
}

分别注意一下上面代码中注释1,2,3处与先前有什么不同。

经此方式处理之后,release模式下:

debug模式下:

这样就做到了debug模式下无法对app模块单独编译处理,从而解决了上面的问题

② debug模式下为app模块单独创建一个壳子Activity

这种处理方式类似业务组件的处理,相当于也把app模块当成了业务组件,但我个人不是很喜欢这种处理方式,明知是个壳,就算运行了也看不到相关业务板块,但这里还是简单介绍一下。

先呈上app.gradle配置源码:

import java.text.SimpleDateFormat

apply from: "${rootProject.rootDir}/common_config.gradle"
//注释1
if (project.ext.isDebug) {
    project.ext.setAppConfig project
} else {
    project.ext.setAppDefaultConfig project
}

android {

    //配置签名信息
    signingConfigs {
        config {
            keyAlias project.ext.keyAlias
            keyPassword project.ext.keyPassword
            storeFile file(project.ext.storeFile)
            storePassword project.ext.storePassword
        }
    }

    defaultConfig {

    }

    buildTypes {
        release {
            minifyEnabled true
            zipAlignEnabled true
            //注释2
            shrinkResources true
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
            //release模式下添加应用签名信息
            signingConfig signingConfigs.config
        }
        debug {
            //debug模式下添加应用签名信息,兼容相关第三方SDK需要签名才能进行操作的问题
            signingConfig signingConfigs.config
        }
    }
    compileOptions {
        sourceCompatibility JavaVersion.VERSION_1_8
        targetCompatibility JavaVersion.VERSION_1_8
    }

    //注释3
    //输出apk
    applicationVariants.all { variant ->
        variant.outputs.all {
            outputFileName = project.ext.prefix_outputApkName + "${variant.versionName}-${buildTime()}.apk"
        }
    }
}

static def buildTime() {
    def df = new SimpleDateFormat("yyyyMMddHHmmss")
    df.setTimeZone(TimeZone.getDefault())
    return df.format(new Date())
}

dependencies {
    implementation 'androidx.constraintlayout:constraintlayout:2.0.4'
    if (project.ext.isDebug) {    //debug状态下分量编译
        implementation project(':commonlib')
    } else {
        api project(':launcher')
        api project(':main')
        api project(':find')
        api project(':mine')
    }
}

注意注释1,2,3处与上一种方法有什么不同之处,注释1处用setAppConfig替换了setLibDefaultConfig,等于说还是把app模块当成可编译运行的模块而不是一个lib包。

common_config.gradle中的变动:

setAndroidDefaultConfig = {
    compileSdkVersion app_compileSdkVersion
    buildToolsVersion app_buildToolsVersion
    defaultConfig {
        minSdkVersion app_minSdkVersion
        targetSdkVersion app_targetSdkVersion
        versionCode app_versionCode
        versionName app_versionName
        testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
        //设置路由模块配置
        javaCompileOptions {
            annotationProcessorOptions {
                arguments = [AROUTER_MODULE_NAME: project.getName()]
            }
        }
    }
    //注释1
    //release模式下还原资源路径
    sourceSets {
        main {
            manifest.srcFile 'src/main/AndroidManifest.xml'
            //集成开发模式下排除debug文件夹中的所有java文件
            java {
                exclude 'debug/**'
            }
        }
    }
}

注释1处的作用是使app模块在release模式下还原资源加载路径。

另一方面,还需要再在app模块中添加相关文件,如图:

这时,app模块是可以单独编译运行的,只不过此时加载的页面是AppIndexActActivity而不是MainActivity,同时配置文件取的也是module包中的。

release模式下:

此时,APP整体可以正常整体编译运行,入口界面是MainActivity,配置文件取的是src/main文件夹中的。

业务组件模块处理方式

入口为Activity的话无需多说,直接在module中配置文件添加对应Activity并设置action和category,至于如何做到与其他组件之间的通信,在下一节再做研究。这里主要研究一下业务模块入口为Fragment的情况。

Fragment必须依托于Activity才能存在,因此可以在debug包下新建一个入口Activity,然后在入口Activity中实现对应Fragment的加载。这里入口Activity中除了添加Fragment的逻辑之外不再处理其他相关业务逻辑,而Fragment中相关业务操作也可以通过接口与其他模块通信,具体实现在下一节详述。

8.1.4 组件之间通信

这里分为release模式下和debug模式下的通信,debug模式下每一个业务组件都有各自独立的进程,因此在debug模式下组件之间的通信需要用到进程间通信实现方式,这个知识点会单独在Android IPC机制中介绍。但这种通信有一个前提,就是A组件想要调用B组件中的方法,需要A、B组件都处于运行状态,即进程存活状态,否则就算使用AIDL也无法实现组件之间的通信。

因此我们主要讲一下release模式下组件之间通信的实现方式。

第一步、在入口Application中初始化ARouter

public class MyApp extends Application {
    @Override
    public void onCreate() {
        super.onCreate();
        //ARouter设置
        if (BuildConfig.DEBUG) {
            ARouter.openLog();
            ARouter.openDebug();
        }
        ARouter.init(this);
    }
}

这里最终实现app模块和find模块调用main模块中的方法,然后给出一个Toast提示。

第二步、commonlib模块中添加find对外服务接口

/**
 * @Description: main模块对外提供的服务接口
 * @Author: Allen
 * @CreateDate: 2020-11-20 16:55
 * @Version: 1.0
 */
public interface MainExportService extends IProvider {
    //注释1
    String sayHello(String s);
}

注释1处定义了一个方法供其他组件调用。

第三步、main模块中添加MainExportService的实现类,实现具体操作

/**
 * @Description: main模块对外提供服务的实现类
 * @Author: Allen
 * @CreateDate: 2020-11-20 16:57
 * @Version: 1.0
 */
//注释1
@Route(path = RouterConstants.MAIN_SERVICE)
public class MainService implements MainExportService {
    @Override
    public String sayHello(String s) {
        return "我是来自main模块的问候:" + s;
    }
    @Override
    public void init(Context context) {
    }
}

注释1处为MainService指定了Router路由,供其他组件通过ARouter调用。

第四步、在其他组件中添加具体调用

app模块中在MainActivity中调用:

public class MainActivity extends AppCompatActivity {
    //通过ARouter获取MainExportService实例
    @Autowired(name = RouterConstants.MAIN_SERVICE)
    public MainExportService mainExportService;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        //依赖注入该页面
        ARouter.getInstance().inject(this);
    }
    //页面按钮点击事件
    public void testComm(View view) {
        if (mainExportService != null) {
            Toast.makeText(this, mainExportService.sayHello("你好!"), Toast.LENGTH_LONG).show();
        } else {
            Toast.makeText(this, "mainExportService为空", Toast.LENGTH_SHORT).show();
        }
    }
    //跳转到find模块中再次测试find与main之间的通信
    public void goFind(View view) {
        ARouter.getInstance()
                .build(RouterConstants.FIND_TEST)
                .navigation();
    }
}

上面注释的很清晰,需要在MainActivity中将ARouter进行依赖注入,然后通过@Autowired获取到MainExportService的实例,最后在点击事件中调用。至于find模块中的具体实现与MainActivity中一样,这里不多做介绍。

显示全文