1, the preface

Recently, due to the change of business requirements, I have considered the use of componentized architecture for development, which I have not touched before. There are a lot of articles about componentization, and all the great gods put forward a variety of componentization schemes. I also read a lot of relevant articles. But as much as you learn something new and watch it, it’s better to just do it once. You don’t have to worry about the complicated stuff, but you have to do a simple Demo first to understand the idea of componentization. Componentization related theoretical knowledge is not talked about here, want to know you can go to search or look at the Android componentization scheme this article. Nonsense not to say, directly begin to open code.

2. Build componentized Demo

Start by opening Android Studio and creating a new project.

Step 1: Create config.gradle and manage build.gradle in a unified manner

Then create a new config.gradle file in the project directory.

Ext {// indicates whether it isModule or application isModule =falseAndroid = [compileSdkVersion: 28, buildToolsVersion: 28, applicationId:"com.example.componenttestdemo",
            minSdkVersion            : 19,
            targetSdkVersion         : 28,
            versionCode              : 1,
            versionName              : "1.0".testInstrumentationRunner: "android.support.test.runner.AndroidJUnitRunner"] // Version number def APPCOMPAT_V7_VERSION ="28.0.0"
    def CONSTRAINT_LAYOUT_VERSION = 1.1.3 ""Dependencies = [appcompatV7:'com.android.support:appcompat-v7:' + APPCOMPAT_V7_VERSION,
            constraintLayout: 'com.android.support.constraint:constraint-layout:' + CONSTRAINT_LAYOUT_VERSION
    ]
}
Copy the code

Because we know that when a project uses a componentized architecture, a single Module Module can be run as a single Application or as a Module within the entire main Application. So in config.gradle, define an isModule to distinguish between these two cases. After componentization, you can change this value to switch between the two cases. All that remains is unified management of applicationId, version number, sdkVersion, tripartite libraries, and so on.

Then modify the Settings in build.gradle in your app

Replace the old compileSdkVersion, applicationId, minSdkVersion, versionCode and tripartite libraries with the values defined in config.gradle.

apply plugin: 'com.android.application'

android {
    compileSdkVersion rootProject.ext.android.compileSdkVersion
    defaultConfig {
        applicationId rootProject.ext.android.applicationId
        minSdkVersion rootProject.ext.android.minSdkVersion
        targetSdkVersion rootProject.ext.android.targetSdkVersion
        versionCode rootProject.ext.android.versionCode
        versionName rootProject.ext.android.versionName
        testInstrumentationRunner rootProject.ext.android.testInstrumentationRunner
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
        }
    }
}
dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar'])
    implementation rootProject.ext.dependencies.appcompatV7
    implementation rootProject.ext.dependencies.constraintLayout

}
Copy the code

Finally, add a line to build. Gradle in your project directory:

apply from : "config.gradle"
Copy the code

Sync Now
AndroidManifest

Step 2: Create the Main module and empty the app shell project

We know that componentization requires an APP shell project. This shell project does not deal with any business, but is just an empty shell, which combines all required components and modules to form a complete application. The app in the project still has the default entry Activity, so create a new ModuleMain and move the default MainActivity and its layout file there.

Then enter the AndroidManifest file of the app and move the code for registering the Activity into the AndroidManifest of the ModuleMain module, leaving only the Application tag.

Note here that each Module in the componentized project will have its own AndroidManifest file, which will be merged into a single file when packaged. Therefore, there will be the problem of duplicate attributes in the application tag. Add the following two lines of code to your app’s AndroidManifest file:

 xmlns:tools="http://schemas.android.com/tools" 
Copy the code
 tools:replace="android:name,android:label,android:icon, android:theme,android:allowBackup"
Copy the code

Name, label, icon, theme, and allowBackup may be duplicated, so separate them all with commas. The full AndroidManifest is as follows:

<? xml version="1.0" encoding="utf-8"? > <manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.sy.modulesimpledemo"
    xmlns:tools="http://schemas.android.com/tools"    >

    <application
        android:name=".application.MyApplication"
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        tools:replace="android:name,android:label,android:icon, android:theme,android:allowBackup"
        android:theme="@style/AppTheme">
    </application>

</manifest>
Copy the code

Then, only the newly modified build.gradle is still in the app shell project. Before deleting it, copy and cover the contents of build.gradle in the app to the build.gradle in the Main module, and make some modifications. Because a single component can be combined as a component module by app shell project, or can be used as an application alone. Gradle defines isModule as Module or Applicaition. ApplicationId is not required for Module but is required for application.

// Check whether isModule is application or moduleif (rootProject.ext.isModule) {
     apply plugin: 'com.android.library'
} else {
    apply plugin: 'com.android.application'} android {compileSdkVersion rootProject.ext.android.com pileSdkVersion defaultConfig {/ / didn't need applicationId is applicationif(! rootProject.ext.isModule) { applicationId"com.example.sy.moduledmain"
        }
        minSdkVersion rootProject.ext.android.minSdkVersion
        targetSdkVersion rootProject.ext.android.targetSdkVersion
        versionCode rootProject.ext.android.versionCode
        versionName rootProject.ext.android.versionName
        testInstrumentationRunner rootProject.ext.android.testInstrumentationRunner
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
        }
    }
    }
}

dependencies {
    implementation fileTree(include: ['*.jar'], dir: 'libs')
    implementation rootProject.ext.dependencies.appcompatV7
    implementation rootProject.ext.dependencies.constraintLayout
}
Copy the code

In this case, the AndroidManifest in ModuleMain will tell you that the resource file is missing. In this case, copy the corresponding file from app to ModuleMain.

Step 3: Create a vmApplicationandAndroidManifestfile

Create a new Application in the App shell project and ModuleMain, since the Moudule also needs to be able to run separately.

AndroidManifest
Module
Application
AndroidManifest
AndroidManifest
AndroidManifest
application

Add the following code to build.gradle to specify which AndroidManifest to use in both cases.

sourceSets {
        main {
            if (rootProject.ext.isModule) {
                manifest.srcFile 'src/main/module/AndroidManifest.xml'
            } else {
                manifest.srcFile 'src/main/application/AndroidManifest.xml'Java {// exclude all files in the Java /module folder'*module'}}}}Copy the code

Add the following code to dependencies in the build.gradle of your app to introduce the ModuleMain module.

if (rootProject.ext.isModule) {
    implementation project(":modulemain")}Copy the code

Now you can click Sync Now again, and after the synchronization, although there is only one shell project and one main Module, you can see the prototype of componentization. You can now switch between Application and Module modes by changing the isModule value in config.gradle to run ModuleMain as a Module of app or as an Application.

Step 4: Create other component modules and resolve resource file conflicts

Then repeat the steps of creating ModuleMain to create other business Modules. Here I create three modules: Business A: ModuleA, business B: ModuleB and A BaseModule. BaseModule stores basic and utility classes and serves only as a Module for upper-layer business modules.

build.gradle

resourcePrefix "modulemain_"
Copy the code

Android Studio will give you a message:

Step 5: Use ARouter for inter-component communication

The next step is to deal with communication between components, using Ali’s ARouter. Integrate ARouter as documented. First add the following code under defaultConfig:

javaCompileOptions {
            annotationProcessorOptions {
                arguments = [AROUTER_MODULE_NAME: project.getName()]
            }
        }
    }
Copy the code

Reintroduce the ARouter dependency:

implementation rootProject.ext.dependencies.arouter
implementation rootProject.ext.dependencies.arouterCompiler
Copy the code

Finally, initialize ARouter in Application:

if(isDebug()) {// These two lines must be written before init, otherwise these configurations will be invalid during init arouter.openlog (); // Prints the log arouter.openDebug (); // Enable debug mode (if running in InstantRun mode, debug must be enabled! } ARouter. Init (mApplication); // As early as possible, it is recommended to initialize in ApplicationCopy the code

Now that ARouter is integrated, create two new activities in MoudleA and ModuleB and use ARouter to jump to the page.

ModuleMain MainActivity. In Java:

public class MainActivity extends BaseActivity  {
    /**
     * toA
     */
    private Button mModulemainA;
    /**
     * toB
     */
    private Button mModulemainB;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.modulemain_activity_main);
        initView();
        initEvent();
    }

    private void initEvent() {
        mModulemainA.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { ARouter.getInstance().build(ARouterPath.PATH_MOUDULE_A).navigation(); }}); mModulemainB.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                ARouter.getInstance().build(ARouterPath.PATH_MOUDULE_B).withString("key"."Transmitted data").navigation(); }}); } private voidinitView() { mModulemainA = (Button) findViewById(R.id.modulemain_a); mModulemainB = (Button) findViewById(R.id.modulemain_b); }}Copy the code

ModuleA ModuleAActivity. In Java:

@Route(path = ARouterPath.PATH_MOUDULE_A)
public class ModuleAActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.modulea_activity_module_a); }}Copy the code

ModuleB ModuleBActivity. In Java:

@Route(path = ARouterPath.PATH_MOUDULE_B)
public class ModuleBActivity extends AppCompatActivity {
    @Autowired(name = "key")
    String data;
    /**
     * TextView
     */
    private TextView mTextViewB;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.moduleb_activity_module_b);
        ARouter.getInstance().inject(this);
        initView();
    }
    private void initView() { mTextViewB = (TextView) findViewById(R.id.textViewB); mTextViewB.setText(data); }}Copy the code

Operation effect:

3. Use Module as remote Maven repository

In development, you might upload some public Modules to a private server and rely on them directly in your project. Now upload the Module to Github as a remote Maven repository and reference it directly in the project. First create a new project, creating a UtilModule.

Move the utility class from the original project to UtilModule, then add the following code to build.gradle for UtilModule:

apply plugin: 'maven'
uploadArchives {
    repositories.mavenDeployer {
        def mavenDirPath = file('\\Users\\sy\\AndroidProjects\\UtilModule') // Local repository(url:"file://${mavenDirPath.absolutePath}")
        pom.project {
            groupId "com.example.utilmodule"/ / package name artifactId"utilmodule"// Module name version"1.0.0"// Version number}}}Copy the code

Then click on uploadArchives in Gradle:

Go to the directory you set up to see that the AAR is already packed.

Then open Github and create a new repository:

Upload the locally packaged UtilModule to Github by following the command on Github:

github.com
raw.githubusercontent.com
/master
build.gradle

build.gradle

utilmodule      : 'com.example.utilmodule:utilmodule:' + UTIL_MODULE_VERSION
Copy the code
implementation rootProject.ext.dependencies.utilmodule
Copy the code

Here is the package name set earlier: Module name: version number. SyncNow then removes the utility classes from the original project and tests the remote repository’s utility classes in the code:

D/com.example.modulemain.MainActivity: onCreate:false
Copy the code

This indicates that the classes and methods in the remote repository have been successfully used.

4, summarize

This article mainly records the process of my first knowledge of componentization and the construction of componentization Demo. Demo is very helpful for my understanding and experience of componentization. There are many things that are not considered in Demo, such as dynamic configuration merging of Application, Fragment and the confusion of componentization. That’s what I’m learning. This article is mainly for the novices who do not know much about componentization as I do, hoping to be helpful to novices.

Finally, I will attach some links to the open source componentization scheme that are well summarized, which is also the scheme I plan to study later: compare some representative open source Android componentization development scheme AppJoint scheme ArmsComponent scheme from multiple dimensions

Demo source address: github.com/syDeveloper…