美文网首页
Android组件化实践

Android组件化实践

作者: 小豪丶ace | 来源:发表于2018-12-24 10:49 被阅读112次

    前言

    相信各位小伙伴们对组件化开发都不陌生了,本文只对我所理解和使用的组件化开发方案做一个总结,有不正确或者需要改进和优化的地方,望大家及时指出

    如何将一个项目组件化

    下面以我的ModuleDemo举例说明

    架构图

    image

    大致分为4部分:

    1. App壳

    启动页,组件初始化,项目基本框架

    2. 业务组件

    具体的组件,例如上图home,moduleA组件

    3. 组件基础库

    例如上图business
    定义了各个组件对外提供的服务,组件间的共享资源

    4. 通用库,路由库

    全局通用的资源(例如Theme和color等),第三方库
    路由库主要用户业务组件间交互

    调试和发布

    为了避免每个组件都进行重复的一些配置,我这里对gradle做了些封装,下面会给完整的配置,这里我们先来看看大致步骤

    工程 gradle配置

    apply from: "${rootProject.rootDir}/version.gradle"
    

    统一依赖,组件模式开关

    App gradle配置

    dependencies {
        implementation rootProject.ext.dependencies["appcompat-v7"]
        if (rootProject.ext.isModuleADebug){
            implementation project(':modulea')
        }
        if (rootProject.ext.isHomeDebug){
            implementation project(':home')
        }
    }
    

    组件单独运行时,取消app的依赖

    组件 gradle配置

    模式切换
    apply from: "${rootProject.rootDir}/config.gradle"
    def isHomeDebug = rootProject.ext.isHomeDebug
    if (rootProject.ext.isHomeDebug) {
        project.ext.setLibDefaultConfig project
    } else {
        project.ext.setAppDefaultConfig project
    }
    

    通过控制isHomeDebug的值,来导入不同的配置,调试模式引入Application插件,和设置Application相关的配置,组件模式引入library插件,设置library相关配置

    指定资源目录
      sourceSets {
            main {
                if (!isModuleADebug) {
                    manifest.srcFile 'src/main/module/AndroidManifest.xml'
                } else {
                    manifest.srcFile 'src/main/AndroidManifest.xml'
                    //集成开发模式下排除debug文件夹中的所有Java文件
                    java {
                        exclude 'debug/**'
                    }
                }
            }
        }
    

    如图

    image
    当组件作为单独的project运行时,我们需要提供调试相关一些资源,所以我创建了两个文件夹,module文件夹里面提供AndroidManifest为了调试模式时的启动页配置,debug文件夹可以放置调试时需要使用的资源,例如Activity等

    UI跳转

    组件内部,采用原生的跳转方式,不同组件间采用Arouter中的Provider来提供组件的相关跳转,我觉得这样可以很清楚的知道每个模块对外提供的功能,比起在模块上的Activity上加注解跳转方式好一些

    在business组件基础库中,定义home组件的接口

    /**
     * home模块对外暴露功能
     */
    public interface IHomeProvider extends IProvider {
        void goHome(Context context);
    }
    

    在home组件中实现该接口

    @Route(path = RouterHelper.ROUTER_HOME_PROVIDER)
    public class HomeProviderImpl implements IHomeProvider {
        @Override
        public void init(Context context) {
            Log.d("HomeProviderImpl", "home初始化");
        }
    
        @Override
        public void goHome(Context context) {
            Intent intent = new Intent(context, HomeActivity.class);
            context.startActivity(intent);
        }
    }
    

    跳转

    ((IHomeProvider) RouterHelper.getModule(RouterHelper.ROUTER_HOME_PROVIDER)).goHome(MainActivity.this);
    

    组件通信

    组件间都是相互独立的,他们之间不存在任何依赖.没有依赖,就无法产生关系,没有关系就无法传递任何的信息.这个时候我们需要依赖第三方协助我们,也就是业务基础库,所有的业务组件都依赖该库,通过它来进行通信.
    我们可以采用事件总线的方式,例如EventBus,将在业务基础库中定义需要传递的消息对象,在业务组件中订阅该消息,通过这种方式我们就可以实现不同组件中的消息通信,当然我们同样也可以在上面提到的Provider方式,不过我觉得这两种方式没啥区别

    注意点

    组件化过程中还是有许多需要注意的地方,这里主要说三个地方

    1. 依赖冲突

    每个组件都可能引入自己的库,这样合并的时候就会产生冲突,解决这个冲突的方式就是统一依赖管理,后面会给出详细配置

    2. 不要使用butterknife

    相信很多人都喜欢使用这个库,但是组件化中最好还是不要使用了,虽然它提供了R2这种方式解决了lib中的id问题,但是每次单独运行的时候得手动改成R,个人觉得有点麻烦,再说findviewbyid也花不了多少时间,一个插件的就搞定的事,也不容易出问题

    3. 资源冲突

    如果A和B组件中都有同一个名字的资源文件,在集成模式的时候打包就会报错,可以使用在gradle中配置resourcePrefix 来解决

        //设置了resourcePrefix值后,所有的资源名必须以指定的字符串做前缀,否则会报错。
        //但是resourcePrefix这个值只能限定xml里面的资源,并不能限定图片资源,所有图片资源仍然需要手动去修改资源名。
        resourcePrefix "模块名"
    

    当然也可以团队约定好代码规范,那样更好

    详细配置

    version.gradle

    ext {
        isHomeDebug = true
        isModuleADebug = true
    
        android = [
                applicationId    : "com.hc.moduledemo",
                compileSdkVersion: 27,
                minSdkVersion    : 19,
                targetSdkVersion : 22,
                versionCode      : 1,
                versionName      : "1.0",
                supportVersion   : "27.1.1"
        ]
        dependencies = [
                "arouter"     : ["arouter-api"     : "com.alibaba:arouter-api:1.4.1",
                                 "arouter-compiler": "com.alibaba:arouter-compiler:1.2.2"],
                "appcompat-v7": "com.android.support:appcompat-v7:${android.supportVersion}"
        ]
    
    }
    

    config.gradle

    //所有业务模块通用的一些配置
    ext {
        //设置App配置
        setAppDefaultConfig = {
            extension ->
                extension.apply plugin: 'com.android.application'
                extension.description "app"
                setAndroidConfig extension.android
                setDependencies extension.dependencies
                extension.android.defaultConfig {//设置applicationId
                    applicationId rootProject.ext.android.applicationId + "." + extension.getName()
                }
        }
    
        //设置Lib配置
        setLibDefaultConfig = {
            extension ->
                extension.apply plugin: 'com.android.library'
                extension.description "lib"
                setAndroidConfig extension.android
                setDependencies extension.dependencies
        }
    
        //设置Android配置
        setAndroidConfig = {
            extension ->
                extension.compileSdkVersion rootProject.ext.android.compileSdkVersion
                extension.defaultConfig {
                    minSdkVersion rootProject.ext.android.minSdkVersion
                    targetSdkVersion rootProject.ext.android.targetSdkVersion
                    testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
                    javaCompileOptions {
                        annotationProcessorOptions {
                            arguments = [AROUTER_MODULE_NAME: extension.project.getName()]
                        }
                    }
                }
        }
    
        //设置依赖
        setDependencies = {
            extension ->
                extension.implementation fileTree(dir: 'libs', include: ['*.jar'])
                extension.testImplementation 'junit:junit:4.12'
                extension.androidTestImplementation 'com.android.support.test:runner:1.0.2'
                extension.androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
                extension.annotationProcessor rootProject.ext.dependencies["arouter"]["arouter-compiler"]
        }
    }
    

    相关文章

      网友评论

          本文标题:Android组件化实践

          本文链接:https://www.haomeiwen.com/subject/taamkqtx.html