随着项目的发展,业务逻辑越来越复杂,代码量越来越多,会带来:
组件化:模块组件和通用组件,可分为业务组件和UI组件等等,比如下拉刷新可作为通用ui组件,供多个项目调用,登录模块或者网络模块,可作为通用业务组件存在,供多个项目使用。
在项目开发中,讲项目拆分为不同的组件,开发阶段组件可单独测试,通用组件可进行依赖服用,最后开发结束以后,将各个组件组合在一起,合并成真正的Apk
好处:
插件化:将一个APK划分为不同的"APK",比如常用的App换肤就是一个插件apk。将整个APK划分为主模块和附属模块,每一个模块都是一个apk,开发完成将主模块和附属模块进行打包
好处:
两者最终目的都是为了解耦模块,避免模块之间的依赖耦合,提升团队开发效率,都可以对单独的模块进行开发测试,组件化相对于插件化,开发相对简单,技术成本相对较低
首先创建一个工程,名字叫ComponentApp
组件化和第三方SDK版本控制
组件化模块中含有多个组件和模块,可以将每个模块组件的build.gradle中的各种引用版本进行统一管理,统一配置以后,供其他模块使用
右击项目,创建一个file,命名为config.gradle,作用就是存储通用的引用的版本号,先看一下项目中的Build.gradle文件中的内容:
现在只有一个模块,如果有多个模块,如果一些引用的版本号进行改变,就需要对多个模块分别修改,首先是重复工作,还有就是容易遗漏,所以要将一些通用引用版本放在config.gradle中管理,现在将android和dependencies模块通用版本抽取到config.gradle中
ext{
android=[
compileSdkVersion:26,
applicationId:"drag.mandala.com.componentapp",
minSdkVersion:22,
targetSdkVersion:26,
versionCode:1,
versionName:"1.0"
]
dependencies=[
supportV7:'com.android.support:appcompat-v7:26.1.0',
constraintLayout:'com.android.support.constraint:constraint-layout:1.1.3'
]
}
然后在项目的build.gradle中写入apply from:"config.gradle"进行引用:
在模块的build.gradle中,引用config.gradle中定义的描述:
以后随着项目的扩大,会有更多的组件模块,这样每个模块的通用引用版本都可以抽取到config.gradle中,方便管理
动态切换application和lib模式
我们会将许多功能抽象出来,作为一个模块,这个模块,在单独开发的时候,作为application模式,可以单独运行,开发完成,转换成lib模式,作为主app的一部分,这个的关键,就是要动态的切换模式
先创建两个module,分别命名为modulea,moduleb
创建完以后的项目结构是:
主项目的settings.gradle
为了切换模式,需要在config.gradle中定义一个参数:isApplication=true
modulea和moduleb的build.gradle,和主app一样,根据config.gradle中的通用版本号进行配置,注意,作为lib是没有applicationId这个属性的,只有作为application才有,可以给modulea和moduleb分别取两个包名,作为切换为application的配置,根据apply plugin: 'com.android.application’和apply plugin: 'com.android.library’可以切换application和lib模式,这个modulea的具体配置是:
moduleb只要把包名改成自己的就行了,这样,修改config.build中的isApplication字段的true或false,然后再sync,就可以切换不同的模式了
lib和application模式中的AndroidManifest.xml合并
modulea中已经有一个AndroidManifest.xml,这个只是lib模式的配置,里边内容如下:
这个作为application模式的AndroidManifest.xml是不适用的,作为一个app,图标,启动页之类的是必须的,所以现在要在modulea的src/main文件夹下,建立两个文件夹,一个是debug,一个是release,分别新建两个AndroidManifest.xml,release文件夹下的AndroidManifest.xml,就是lib模式下的配置,debug文件夹下的,要作为application的配置,可以将主app中的AndroidManifest.xml拷贝下来,将所缺的资源文件也拷贝过来,新建一个默认的启动Activity,这里命名为LoginActivity,AndroidManifest.xml配置如下:
主结构如下:
还是根据isApplication字段来切换不同的AndroidManifest.xml,在build.gradle中的切换配置代码:
sourceSets {
main {
if (rootProject.ext.isApplication) {
manifest.srcFile 'src/main/debug/AndroidManifest.xml'
} else {
manifest.srcFile 'src/main/release/AndroidManifest.xml'
//移出debug下无用的资源
java {
exclude 'debug/**'
}
}
}
}
这样,修改isApplication为true,就可以运行modulea,
组件与主app的Application冲突与初始化
在moduleb中,按照以上步骤进行配置,创建一个Activity,名字为RegisterActivity,现在在modulea和moduleb中,分别新建一个debug包,创建一个Application,分别为LoginApplication和RegisterApplication,分别打印一些日志,在AndroidManifest.xml进行配置,
同样的,在主app中,创建一个MyApplication,在AndroidManifest.xml进行配置,打印一些日志,
public class MyApplication extends Application
{
@Override
public void onCreate()
{
super.onCreate();
Log.e("MyApplication","MyApplication");
//可以理解为第三方sdk的初始化
Log.e("LoginApplication","LoginApplication");
Log.e("RegisterApplication","RegisterApplication");
}
}
这些日志可以理解为第三方sdk的初始化,就是LoginApplication和RegisterApplication作为application模式下的Application,会在里边进行一些第三方SDK的初始化,然后作为lib模式以后,要将这些初始化放到主app的Appliction。在主app的build.gradle中对modulea和moduleb进行引用
如果要这个sync成功,需要将isApplication设置为false,将modulea和moduleb作为lib模式
组件之间资源名的冲突
不同的组件,有可能会存在命名一样的资源名,这样在主app中组合的时候,会出现一些问题,最简单的解决方法就是保证命名的唯一性,这个可以在build.gradle中设置 resourcePrefix 属性,定义资源的前缀,这样就会规范命名
组件间的跳转通信
现在组件之间的跳转通信,一个是Intent跳转,一个是ActivityRouter
使用Intent跳转,需要在module中的release文件夹下的AndroidManifest.xml对需要跳转的Activity进行配置,设置一个重要的属性: android:exported=“true”
在主app中,通过Class.forName获取到需要跳转的Class,然后通过Intent进行跳转
可以在跳转到的Activity中接收传入的值
使用ActivityRouter进行跳转
ActivityRouter
在config.gradle中,对ActivityRouter的版本进行配置,
activityrouter : 'com.github.mzule.activityrouter:activityrouter:1.2.2',
activityrouterCompiler:'com.github.mzule.activityrouter:compiler:1.1.7'
在需要跳转的module和主app的build.gradle进行引用
compile rootProject.ext.dependencies.activityrouter
annotationProcessor rootProject.ext.dependencies.activityrouterCompiler
主app的AndroidManifest.xml配置RouterActivity
在需要跳转的module中的Activity进行配置
主app中进行跳转
Routers.open(MainActivity.this,"modulea://LoginActivity?test=you+are+best");
还有一种跳转方法,是通过EventBus,这个可以作为一个选择
组件化开发,将一些共同的库,比如网络库,下拉加载库之类的,封装成一个library,供其他module调用,将一些功能分成module,每个人开发的时候,module作为application进行开发,可以写一个入口Activity,比如入口Activity是MainActivity,用来启动这个module实际的功能,比如启动ActivityB,这个ActivityB就是该module的功能入口,开发完成以后,将module变成library,主app直接调用ActivityB
组件化源码