Android组件化初探

来源:互联网 发布:oracle恢复原来的数据 编辑:程序博客网 时间:2024/06/16 01:03

Android组件化初探

1. 现状

随着业务增加,代码量急剧增加,大大延长了编译时间,短则3min,长则7、8min;很多同学为节省开发时间,自己新建新的app,完成开发后,再合并到project中;组件化的目的就是为了解耦,将业务模块独立出来,自成一个apk,这样开发期间能提高效率

2. 原理

编译期间动态设置自己业务Module属性(app/library)
在开发期间,只需要编译自己的业务模块代码,并将自己业务模块Module设置app;这样能很大程度上提高编译速度,提高开发效率;在发版期间将自己业务Module设置为libray模式即可

3. 需要解决的问题

  1. 需要在编译期间动态设置自己业务模块属性(app/library)
  2. 开发模式应该存在一个DebugActivity 以作为app启动页;发布模式应该将其忽略不参与打包
  3. 为保证资源不与其他模块存在冲突,应限定自己module所有资源带有指定前缀
  4. 业务模块可能会存在依赖其他业务模块功能,如何实现?
  5. debug模式和发布模式下清单文件应该单独区分
  6. 业务module在运行期间可能会对debug/发布模式做不同操作处理,java代码层如何区分?
  7. 当自己业务模块代码增加时,如何提高开发效率?

4. 实现

4.1 编辑根目录gradle.properties文件

为了能够区分开发模式和发布模式,我们可以在项目根目录gradle.properties文件中添加一个属于自己业务模块变量,以区分是开发模式还是发布模式(下面以module1为样例进行说明)

    #标识MODULE1以app方式启动,发布时可改为false    MODULE1_IS_APP = true

4.2 编辑settings.gradle文件

让gradle动态指定需要参与编译的module

if(MODULE1_IS_APP.toBoolean()){    include ':module1', ':framework', ':baseresource'}else{    include ':app', ':module1', ':framework', ':baseresource'}

4.3 编辑moudle1工程中build.gradle文件

为能在编译期间动态设置通通花module是以app还是library需要添加如下代码:

//解决问题1if (MODULE1_IS_APP.toBoolean()) {    apply plugin: 'com.android.application'    //解决问题7,关于如何集成freeline    //参见(http://blog.csdn.net/dbs1215/article/details/64166592)此处不再阐述请参考    //apply plugin: 'com.antfortune.freeline'} else {    apply plugin: 'com.android.library'}android {    compileSdkVersion 23    buildToolsVersion "23.0.3"    defaultConfig {        minSdkVersion 14        targetSdkVersion 23        versionCode 1        versionName "1.0"        if (MODULE1_IS_APP.toBoolean()) {            multiDexEnabled true        }    }    buildTypes {        release {            minifyEnabled false            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'        }    }    buildTypes.each {        //解决问题6 代码中可以通过BuildConfig.MODULE1_IS_APP获取        it.buildConfigField "boolean", "MODULE1_IS_APP", MODULE1_IS_APP    }    //解决问题3 (只能做到布局文件,字符串等资源前缀,java类,图片需要自己处理)    resourcePrefix "module1_"    sourceSets {        main {            //解决2、5问题            if (MODULE1_IS_APP.toBoolean()) {                //如果是app启动,使用该清单文件                manifest.srcFile 'src/main/xml/app/AndroidManifest.xml'            } else {                manifest.srcFile 'src/main/xml/library/AndroidManifest.xml'                java{                    //debug包不参与打包                    exclude '**/debug/**'                }            }        }    }    configurations {        all*.exclude group: 'com.android.support', module: 'support-v4'        all*.exclude group: 'com.android.support', module: 'support-annotations'    }}dependencies {    //业务module需要依赖的相关库    compile fileTree(dir: 'libs', include: ['*.jar'])    compile project(':framework')    compile project(':baseresource')}

4.4 问题4如何解决?

可以通过依赖注入来实现

  1. 首先可以声明一个接口IDependService
    添加Module1需要依赖其他Module的方法

  2. 在依赖方Module某个路径下实现该接口

  3. 在Module1添加一个类Module1SDK(单例)对象初始化时通过反射实现依赖注入

具体如何实现可以参见末尾代码链接

依然存在的问题

  1. 当自己的业务module1联调依赖于其他业务module功能时,需要以app为主工程启动,耗费时间,暂时没找到别的有效办法
  2. 当自己的业务module1依赖于公共组件/基础模块,但未下沉,无法引用,尴尬。。。。只能通过copy(简单点)/下沉(改动较大)方式来做

思考

  • 如何定义并剥离Module
  • 组件与组件间通讯(Router)

示例工程链接