The background,
What happens when our projects get bigger, our code gets fatter, there’s more coupling, compilations are slower, and development is less efficient? At this point, we need to refactor the old project, that is, to break up the module, officially known as componentization.
Second, the introduction of
So what is componentization? Its basic idea is: common functions, controls, basic classes, third-party libraries, permissions and other common parts removed from the package, we call it basic components (baselibs); Business is divided into N modules for independent management, and each module is called business component. All business components need to rely on the encapsulated base components, business components do not rely on each other, so that each business module can run independently. The module of the whole project is encapsulated in the APP layer.
The jump between service modules can be realized by Arouter. Communication between business modules can be achieved through messages (EventBus).
Iii. Infrastructure construction
1. Component frame diagram
2. Project structure drawing based on component frame drawing
3. Each module is described next
There are altogether five modules in the project, including three business modules, one basic module and one APP shell module.
After building the project, we need to configure the switch of “integrated development mode” and “Component development mode” for the three modules. We can define the variable isModel in the gradle.properties file. IsModel =false means “integrated development mode”, isModel=true means “component development mode” (note: every change in isModel must be Sysn).
1) APP shell module
Gradle is configured to rely on different business components based on the isModel field in the configuration file.
2) Baselibs module
Mainly responsible for the encapsulation of common parts, such as MVP architecture, BaseView encapsulation, network request library, image loading library, tool classes and custom controls, etc.
To prevent duplicate dependencies, all third party libraries are placed in this module, and the business module does not make any third party dependencies, only relying on the Baselibs module.
The structure of the Baselibs module is as follows:
Gradle library introduced in the Baselibs module
dependencies {
implementation fileTree(include: ['*.jar'], dir: 'libs')
configurations {
all*.exclude group: 'com.android.support', module: 'support-v13'
}
testImplementation rootProject.ext.testDeps["junit"]
androidTestImplementation rootProject.ext.testDeps["runner"]
androidTestImplementation rootProject.ext.testDeps["espresso-core"]
//leakCanary
debugApi rootProject.ext.testDeps["leakcanary-debug"]
releaseApi rootProject.ext.testDeps["leakcanary-release"] / / Support library API rootProject. Ext supportLibs request library API workLibs / / rootProject.ext.net / / network RxJava2 API rootProject.ext.rxJavaLibs // commonLibs api rootProject.ext.commonLibs kapt rootProject.ext.otherDeps["arouter-compiler"]}Copy the code
3) Service modules (module_NEWS, MODULE_VIDEO, module_ME)
Each business module exists as a library in integrated development mode; Exists as an Application in Component development mode and can be run separately.
Since the configuration files of each business module are similar, the module_news module is used as an example.
Here is the gradle configuration file for the module_news module:
if (isModule.toBoolean()) {
apply plugin: 'com.android.application'
} else {
apply plugin: 'com.android.library'
}
android {
if (isModule.toBoolean()) {
applicationId "com.cxz.module.me"
}
compileSdkVersion rootProject.ext.android.compileSdkVersion
defaultConfig {
minSdkVersion rootProject.ext.android.minSdkVersion
targetSdkVersion rootProject.ext.android.targetSdkVersion
versionCode 1
versionName "1.0"
}
}
dependencies {
implementation fileTree(include: ['*.jar'], dir: 'libs')
testImplementation rootProject.ext.testDeps["junit"]
androidTestImplementation rootProject.ext.testDeps["runner"]
androidTestImplementation rootProject.ext.testDeps["espresso-core"]
implementation project(':baselibs')
kapt rootProject.ext.otherDeps["arouter-compiler"]}Copy the code
4) Configuration filesconfig.gradle
, the third library in the project,app
Version and other configurations
ext {
android = [
compileSdkVersion: 28,
buildToolsVersion: "28.0.3",
minSdkVersion : 16,
targetSdkVersion : 27,
versionCode : 1,
versionName : "1.0.0"
]
dependVersion = [
androidSupportSdkVersion: "28.0.0",
espressoSdkVersion : "3.0.2",
retrofitSdkVersion : "2.4.0",
glideSdkVersion : "4.8.0",
rxJava : 2.2.2 "",
rxAndroid : "2.1.0.",
rxKotlin : "2.3.0",
anko : "0.10.7"
]
supportDeps = [
"supportv4" : "com.android.support:support-v4:${dependVersion.androidSupportSdkVersion}"."appcompatv7" : "com.android.support:appcompat-v7:${dependVersion.androidSupportSdkVersion}"."cardview" : "com.android.support:cardview-v7:${dependVersion.androidSupportSdkVersion}"."design" : "com.android.support:design:${dependVersion.androidSupportSdkVersion}"."constraint-layout": "Com. Android. Support. The constraint, the constraint - layout: 1.1.3." "."annotations" : "com.android.support:support-annotations:${dependVersion.androidSupportSdkVersion}"
]
retrofit = [
"retrofit" : "com.squareup.retrofit2:retrofit:${dependVersion.retrofitSdkVersion}"."retrofitConverterGson" : "com.squareup.retrofit2:converter-gson:${dependVersion.retrofitSdkVersion}"."retrofitAdapterRxjava2" : "com.squareup.retrofit2:adapter-rxjava2:${dependVersion.retrofitSdkVersion}"."okhttp3LoggerInterceptor": 'com. Squareup. Okhttp3: logging - interceptor: 3.11.0'."retrofitConverterMoshi" : 'com. Squareup. Retrofit2: converter - moshi: 2.4.0'."retrofitKotlinMoshi" : "Com. Squareup. Moshi moshi - kotlin: 1.7.0"
]
rxJava = [
"rxJava" : "io.reactivex.rxjava2:rxjava:${dependVersion.rxJava}"."rxAndroid": "io.reactivex.rxjava2:rxandroid:${dependVersion.rxAndroid}"."rxKotlin" : "io.reactivex.rxjava2:rxkotlin:${dependVersion.rxKotlin}"."anko" : "org.jetbrains.anko:anko:${dependVersion.anko}"
]
testDeps = [
"junit" : 'junit: junit: 4.12'."runner" : 'com. Android. Support. Test: runner: 1.0.2'."espresso-core" : "com.android.support.test.espresso:espresso-core:${dependVersion.espressoSdkVersion}"."espresso-contrib" : "com.android.support.test.espresso:espresso-contrib:${dependVersion.espressoSdkVersion}"."espresso-intents" : "com.android.support.test.espresso:espresso-intents:${dependVersion.espressoSdkVersion}"."leakcanary-debug" : 'com. Squareup. Leakcanary: leakcanary - android: 1.6.1'."leakcanary-release" : 'com. Squareup. Leakcanary: leakcanary - android - no - op: 1.6.1'."leakcanary-debug-fragment": 'com. Squareup. Leakcanary: leakcanary - support - fragments: 1.6.1'."debug-db" : 'com. Amitshekhar. Android debug - db: 1.0.4'
]
commonDeps = [
"multidex": 'com. Android. Support: multidex: 1.0.3'."logger" : 'com. Orhanobut: logger: 2.2.0'."glide" : 'com. Making. Bumptech. Glide: glide: 4.8.0'."eventbus": 'org. Greenrobot: eventbus: 3.1.1'."spinkit" : 'com. Making. Ybq: Android - SpinKit: 1.2.0'."arouter" : 'com. Alibaba: arouter - API: 1.4.0'
]
otherDeps = [
"arouter-compiler": 'com. Alibaba: arouter - compiler: 1.2.1'
]
supportLibs = supportDeps.values()
networkLibs = retrofit.values()
rxJavaLibs = rxJava.values()
commonLibs = commonDeps.values()
}
Copy the code
And finally, don’t forget that in engineeringbuild.gradle
Import the configuration file
apply from: "config.gradle"
Copy the code
4. Interaction between business modules
The jump between service modules can be realized by Arouter. Communication between business modules can be achieved through messages (EventBus).
1. Arouter realizes the jump between service modules
We have previously relied on Arouter (see github.com/alibaba/ARo…). , it only takes the following two steps to realize the jump:
The first step
gradle
configuration
kapt {
arguments {
arg("AROUTER_MODULE_NAME", project.getName())
}
generateStubs = true
}
dependencies {
...
kapt rootProject.ext.otherDeps["arouter-compiler"]}Copy the code
The second step
- You need to specify the target page and the parameters to take, and then call
navigation()
Methods;
The third step
- First of all in
onCreate
The method callARouter.getInstance().inject(this)
Injection; - And then want to use
@Route
Annotation annotation page, and inpath
Variable to define a path to the page; - Finally, we define a field with the same name for the variable passed through
@Autowired
Variable labeling,Arouter
The field is automatically assigned
2. EventBus implements communication between business modules
Manage messages using a third party such as EventBus. BaseActivity and BaseFragment classes in baselibs components encapsulate the message simply. Subclasses only need to override useEventBus() to return true to register the event.
5. Problems encountered in the construction process
1, the AndroidManifest
We know that when the APP is packaged, all the AndroidManifest is merged, so the Activity of each business component only needs to be registered in its own module.
If the business component is to run separately, it needs a separate AndroidManifest, which can be loaded in Gradle sourceSets.
Gradle configuration
android {
...
sourceSets {
main {
if (isModule.toBoolean()) {
manifest.srcFile 'src/main/module/AndroidManifest.xml'
} else {
manifest.srcFile 'src/main/AndroidManifest.xml'// Exclude all Java files in the debug folder'debug/**'
}
kotlin {
exclude 'debug/**'}}}}... }Copy the code
Note: AndroidManifest in integration mode does not require Application configuration. AndroidManifest in component mode requires Application configuration separately and must inherit BaseApp.
2. Resource file conflicts
Resource files in different business components may have the same name. Therefore, resource file conflicts may occur. You can set resource prefixes to prevent resource file conflicts.
Gradle configuration, using the module_news module as an example
android {
...
resourcePrefix "news_". }Copy the code
After this configuration, if we do not prefix the named resource file, the compiler will tell us that we did not prefix it.
At this point,Android
The basic componentization framework has been built, please correct any mistakes.
Five, the last
Full project address:Github.com/iceCola7/An…