2017年的时候就想学习学习组件化开发了。当时也看了一些相关文章,只是没有动手实现试试。直到这段时间才静下心来学习,我将自己学习到的东西记录下来,希望对各位感兴趣的同学有所帮助。在学习的过程中,我有一种感觉:学习组件化开发不难,难的是功能的分类。
1.组件化是什么?
组件化开发结构图
普通开发结构图(按自己的理解画的)
之前我们开发的时候,在主App中实现所有的四大组件。网络框架,图片框架,第三方sdk等等一些工具类都放在主App中。这样的后果就是在后期的维护非常困难,不需要的图片代码文件,xml文件等都很难找出,耦合度较高,修改一处地方可能要修改很多处地方。
组件化开发在多人开发中优势非常明显。将网络框架,图片加载框架,第三方sdk,BaseXX等工具放在一个common Module中。根据功能分类成Module分别依赖common Module。最后主app 依赖各个功能Module。在这种开发模式下,每个开发者只需要调试自己的Module。在后期维护的时候也容易找到相应的功能点。
下面我们代码实现:
1.区分使用com.android.library 和 com.android.application。
一般情况下,Module使用的是com.android.library 表示自己是一个library。而主项目使用的是com.android.application 表示自己是一个application。
1.1 为了方便Module 和 App模式间运行的切换,我们需要一个类似开关的东西。在gradle.properties文件上定义一个变量。isModule 为了方便在Module 和 app切换。
1.2 还需要在每个Module中写入
if(isModule.toBoolean()){
apply plugin: 'com.android.application'
}else{
apply plugin: 'com.android.library'
}
需要注意的是 gradle.properties 文件输出的值是String类型的,需要转换成Boolean类型才能做判断。
我们还需要在主app的build.gradle中添加:
当isModule为false时,主项目依赖Module,否则就依赖 librarycommon
注意!注意!注意! 每次isModule 切换时 必须sync project (点击)
2.区分使用AndroidMenifest.xml文件
当我们需要将一个Module当成是一个app做运行的时候,除了上一步使用com.android.application外,还得需要AndroidMenifest.xml文件。但是在各个Module组合在一起的时候,就出现了一个问题: 主app有一个AndroidMenifest.xml文件,各个Module也有一个AndroidMenifest.xml文件,这种情况下就会出现冲突问题。因为主app中AndroidMenifest.xml定义的属性跟其他Module中AndroidMenifest.xml定义的属性发生了冲突。那么该怎么解决呢?这里提供了一个方法:
我们在每个Module的main目录下创建debug目录和release目录。这两个目录都存放着AndroidMenifest.xml文件。当isModule为true时,使用debug目录下的AndroidMenifest.xml文件,当isModule为false时,使用的是release目录下的AndroidMenifest.xml文件。
在每个Module的build.gradle中写着:
sourceSets {
main {
if (isModule.toBoolean()) {
manifest.srcFile 'src/main/debug/AndroidManifest.xml'
} else {
manifest.srcFile 'src/main/release/AndroidManifest.xml'
java {
include 'debug/**'
}
}
}
}
需要注意的是Module中添加的Android四大组件都必须在debug和release目录的AndroidMenifest.xml上注册。另外,debug目录下AndroidMenifest.xml是长这样子的:
<application
android:name="debug.LibraryAApplication"
android:allowBackup="true"
android:label="@string/app_name"
android:supportsRtl="true">
<activity android:name=".LibraryOneActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
relearse目录下 AndroidMenifest.xml是长这样子的:
<application
android:label="@string/app_name"
>
<activity android:name=".LibraryOneActivity"/>
</application>
比较发现:debug下的AndroidMenifest.xml 比 relearse下的AndroidMenifest.xml 属性多。这样做的目的是,在将Module组合在一起的时候,release下的AndroidMenifest.xml与app下的AndroidMenifest.xml定义的属性没有发生冲突。
3.Application问题
对于一个应用应用来说,有且只有一个Application。当开发者没有自定义application时,系统会使用默认的application。
当在AndroidMenifest.xml使用自己定义的application,系统才会调用自定义的。
每个Module创建了application时,将各个Module组合以后就会发生Module的Application 和 主app的Application冲突情况。
这里提供了一种方式解决这个问题:
同解决AndroidMenifest.xml问题类似,我们在java目录下创建一个debug目录并在这个目录下创建application,在debug目录的AndroidMenifest.xml上使用这个application。并在build.gradle中加入
当前app模式运行时,将debug目录下的文件删除掉。
4.实现统一版本
在多人开发的时候总会出现一种情况:我把代码下载下来时大多情况下是不能运行的,我通常需要去修改sdk版本号和编译版本号,当使用多个Module时,还需要一个一个Module去修改。版本统一就显得很有必要了。我们想要的就是在改变一处地方,全部都改变。
4.1 在project中创建一个config.gradle(名字随便)文件。
4.2 配置各种信息
ext{
android = [
compileSdkVersion: 25,
buildToolsVersion:"25.0.2",
minSdkVersion:15,
targetSdkVersion:25,
versionCode:1,
versionName:"1.0"
]
depenVersion = [
support:"25.3.1"
]
dependencies = [
// -------------- Android ------------
appcompatv7 : 'com.android.support:appcompat-v7:25.3.1',
// ----------------- test -------------
junit : 'junit:junit:4.12'
]
}
4.3 在project的 build.gradle文件中引用
apply from :"config.gradle"
4.4 在各个Module中使用
android {
compileSdkVersion rootProject.ext.android.compileSdkVersion
buildToolsVersion rootProject.ext.android.buildToolsVersion
defaultConfig {
minSdkVersion rootProject.ext.android.minSdkVersion
targetSdkVersion rootProject.ext.android.targetSdkVersion
versionCode rootProject.ext.android.versionCode
versionName rootProject.ext.android.versionName
}
}
Module间的跳转是实现组件化开发中很关键的一步。之前我们使用Intent做跳转,但是在组件化时候Module之间是分割开的(没有相互依赖。)。比如说A Module中只能找到本Module实现的Activity,并没有找到其他Module的activity。
我解决的方法是:使用 ActivityRouter 做Module间跳转。
需要了解ActivityRouter的请猛点这里:ActivityRouter
集成ActivityRouter
5.1 在project的build.gradle中
5.2 在每个Module(包括app)的build.gradle中引用:
5.3 在每个Module(包括app)中创建一个类做标记。(类似于说明该Module引用了ActivityRouter功能)
例如:
5.4 app中标识所有的Module标记
“app”是主app标记的,“aModule”和“bModule”分别是其他两个Module标记的。
在主app的AndroidMenifest.xml中添加:
<activity
android:name="com.github.mzule.activityrouter.router.RouterActivity"
android:theme="@android:style/Theme.NoDisplay">
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="assembly" /><!--改成自己的scheme-->
</intent-filter>
</activity>
需要注意的是:scheme的值 是自己填的。它就相当于http一样,在后面的跳转中起到很大的作用。
5.5 在librarya中一个Activity定义路径:
@Router("libraryOne")
public class LibraryOneActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.a_main_activity);
}
public void aClick(View view){
Routers.open(LibraryOneActivity.this,"assembly://libraryTwo");
}
}
我们在主app的界面跳转到
librarya的界面是:
public void main(View view){
Routers.open(MainActivity.this,"assembly://libraryOne");
}
注意我标有红色的地方。
当然 Module间的界面跳转也是可以如此操作的。
需要了解 界面间的传值的可以 看看ActivityRouter的教程,很简单,我就不在这里写了。
Module间的交互可以使用EventBus就可以了。
有需要源码的在这里 组件化开发源码