Architecture e-commerce APP component exploration, in-depth explanation by Ali technical experts

Therefore, the MainModule cannot rely on the other three modules, but if I do not reference other modules, it is obvious that I cannot get the references of these four fragments. One thing is clear, that is, the business modules must not be visible during compilation. There is no doubt about this. However, the runtime is visible, because all modules must rely directly or indirectly during the runtime, otherwise some modules are useless. If you get an instance at runtime, you will naturally think of reflection. Yes, it is reflection.

Dependency partition

In addition to the business Module, we also have some common tool classes and resource files, that is, the Base class. For example, the resource files used by multiple modules can be placed in one Module. In addition, there are third-party dependencies. Here I have created two modules, one is BaseModule and the other is LibraryModule. The overall relationship is as follows

Business component——>Routing component——>Basic components 

Mode switching

Define switch

When switching, you need a switch to indicate whether a single Module is running or multiple modules are running. It is easy to think of a cloth boolean flag. You may also think of it. It is defined in gradle.properties, which seems to be done on the Internet. In fact, we can also define it in BaseModule and LibraryModule. The reason is very simple, It only needs to be accessible in all modules. As long as this principle is followed, it is OK, but it is convenient to define and use in gradle.properties.

isDebug=false//Debug or Release
isModuleRun=true//Single Module operation 

I have not only defined isModuleRun but also isDebug here. Is it strange that we can judge whether the current Debug mode is through BuildConfig.Debug, because our url configuration information is written in BaseModule to facilitate all Module calls. It is a Library. There is another problem about Library. Note:, Since the Library Module is packaged in release mode, BuildConfig.Debug is always false, so we need to define an additional variable isDebug, manually switch between Debug and release, and then judge in the gradle of BaseModule

if (isDebug.toBoolean()) {
    //debug mode
    buildConfigField "String", "AlphaUrl", "\"${url["debug"]}\""

} else {
    //release mode
    buildConfigField "String", "AlphaUrl", "\"${url["release"]}\""

} 
Use switch
Application

When isModuleRun is false, both Application and AndroidManifest are compiled in the form of Library. There is no need to start the Activity and custom Application. On the contrary, it is required.

isModuleRun=false

Unordered modification

<application
    android:allowBackup="true"
    android:supportsRtl="true"
    android:theme="@style/AppTheme">
 </application> 

isModuleRun=false

Create a new AndroidManifest.xml file in the main/debug directory

<application
    android:name=".debug.GoodsApplication"
    android:allowBackup="true"
    android:label="@string/goods_name"
    android:supportsRtl="true"
    tools:replace="android:label"
    android:theme="@style/AppTheme">
    <activity android:name=".GoodsActivity">
        <intent-filter>
            <action android:name="android.intent.action.MAIN" />

            <category android:name="android.intent.category.LAUNCHER" />
        </intent-filter>
    </activity>
 </application> 

Reference mode

Refer to the gradle directory of the Module

Modify plug-in

if (isModuleRun.toBoolean()) {
    apply plugin: 'com.android.application'
} else {
    apply plugin: 'com.android.library'
} 

Add applicationId

if (isModuleRun.toBoolean()) {
    applicationId "com.wustor.cartmoudle"
} 

Switch AndroidManifest file

sourceSets {
    main {
        if (isModuleRun.toBoolean()) {
            manifest.srcFile 'src/main/debug/AndroidManifest.xml'
        } else {
            manifest.srcFile 'src/main/AndroidManifest.xml'
            java {
                //Remove the debug directory when compiling all modules together
                exclude '**/debug/**'
            }
        }
    }
} 

Resource conflict

Suppose we define an Application in the CartModule, and then define an app in strings.xml in the current Module_ Name, and this app is also defined in strings.xml in OrderModule_ Name, there will be conflicts when merging you. We can only change the above fields to cart_name and order_name to solve this problem. Under strict development specifications, this differential naming can be used to solve this problem, because the names of resource files of different modules are basically different, and immediate conflicts are also a small number of conflicts, which can be easily solved.

Of course, in addition to this method, you can prefix the resource file name in build.gradle

resourcePrefix "cart_" 

You can forcibly check that the naming requires a price prefix, which goes against the original intention of componentization and makes the operation more troublesome. However, I feel that this method is not very necessary. Of course, sometimes there may be pictures with the same name. In fact, this can be restored to the project before componentization for analysis, which is impossible, Therefore, in the final analysis, there are still no good development specifications and development habits. There is no need to make some modifications for this. After all, the agreement is greater than the configuration.

Dependency configuration

It can be seen from the initial overall architecture diagram that any Module that can switch between Library and Application undoubtedly depends on the two modules of our Base. In fact, it can be combined into one Module. I have two modules here, one is BaseModule and the other is LibraryModule. Let's sort out their dependencies through the configuration in build.gradle:

MainModule
dependencies {
    compile fileTree(include: ['*.jar'], dir: 'libs')
    compile project(':routermodule')
} 

The components are isolated during compilation, so the MainModule only depends on the RouterModule, and the on-demand dependency during run-time, which is controlled through the script of gradle

//Compile time components are isolated, and run-time components are dependent on demand
//mainModule needs to interact with cartmodule, goodsmodule and usersmodule, so dependency is added during runtime
def tasks = project.gradle.startParameter.taskNames
for (String task : tasks) {
    def upperName = task.toUpperCase()
    if (upperName.contains("ASSEMBLE") || upperName.contains("INSTALL")) {
        dependencies.add("compile", project.project(':' + 'cartmodule'))
        dependencies.add("compile", project.project(':' + 'goodsmodule'))
        dependencies.add("compile", project.project(':' + 'usermodule'))
        dependencies.add("compile", project.project(':' + 'ordermodule'))
    }
} 
BusinessModule

This refers to Goods/Cart/User/OrderModule, which is actually parallel

dependencies {
    compile fileTree(include: ['*.jar'], dir: 'libs')
    compile project(':routermodule')
} 

The business Module depends on the RouterModule

RouterModule
dependencies {
    compile fileTree(include: ['*.jar'], dir: 'libs')
    compile project(':modulelib')
    compile 'com.alibaba:arouter-api:1.2.1.1'
} 

RouterModule depends on LibraryModule

BaseModule
dependencies {
    compile fileTree(include: ['*.jar'], dir: 'libs')
    testCompile 'junit:junit:4.12'
    compile project(':librarymodule')
} 

As a basic library, BaseModule relies on LibraryModule

LibraryModule

As the working masses at the bottom, they actually provide a dependency, so they have nothing to rely on and can only play with themselves.

So here, the basic dependencies are very clear. After knowing the whole architecture diagram, it is very simple to carry out construction next

Component communication

In fact, at the beginning, Module division was based on business, so when we enter a Module, most of the logic should still be processed in this Module, but occasionally we still deal with other modules and look at an interface

[the external chain picture transfer fails. The source station may have an anti-theft chain mechanism. It is recommended to save the picture and upload it directly (img-hpelmdr8-163124722684)( https://user-gold-cdn.xitu.io/2018/1/21/161189f8e008ae32?imageView2/0/w/1280/h/960/ignore -error/1)]

Take GoodsModule and CartModule for example. The two modules can jump to each other. Click the shopping cart icon on the list page of GoodsModule to enter the shopping cart list of CartModule. Click the goods in the shopping cart list to enter the commodity details page of GoodsModule. In addition to this jump, there is actually variable acquisition. For example, on the home page, I need to obtain HomeFragment and SortFragment in GoodsModule, CartFragment in CartModule and MineFragment in UserModule at the same time. I directly rely on four business modules in the MainModule. In fact, this can not be the case. We can also use Arouter to obtain Fragment instances.

Get instance

In fact, the examples here refer to Fragment in most cases. Take Fragment as an example below, and other examples can follow suit

  • Reflection acquisition

Because modules are isolated, we can't directly create an instance of Fragment. In fact, it's easy to think of reflection at this time. Emission is omnipotent. Here's the code.

//Get Fragment instance
public static Fragment getFragment(String className) {
    Fragment fragment;
    try {
        Class fragmentClass = Class.forName(className);
        fragment = (Fragment) fragmentClass.newInstance();
    } catch (Exception e) {
        throw new RuntimeException(e);
    }
    return fragment;
} 
  • Arouter

[Arouter](

)It is a routing framework that Alibaba has exited. It is convenient to use the routing operation table in the component. An example is given below

Add comments to the target Fragment

@Route(path = "cart/fragment")
public class CartFragement extends BaseFragment{
} 

Get instances anywhere

Fragmetn fragment = (Fragment) ARouter.getInstance().build("/cart/fragment").navigation(); 
Method call

There are method calls between different modules. We can define an interface in each Module, implement the interface, obtain the interface where we need to call, and then call the method. For unified management, we define the interface of each Module in the RouterModule. Since each business Module depends on this RouteModule, we only need to obtain this interface through reflection and make method calls.

[the external chain picture transfer fails. The source station may have an anti-theft chain mechanism. It is recommended to save the picture and upload it directly (img-ruhkud2j-163124722687)( https://user-gold-cdn.xitu.io/2018/1/21/161189f8e03411d1?imageView2/0/w/1280/h/960/ignore -error/1)]

ModuleCall

Finally, some exclusive dry goods to share with you today:

**[CodeChina open source project: Android learning notes summary + mobile architecture Video + big factory interview real questions + project actual combat source code](

)**

[notes on core knowledge points of Android development]

[Android mind map (skill tree)]

[PDF document of Android core advanced technology, analysis of real interview questions of BAT manufacturers]

[Android advanced architecture video learning resources]

This article has been Tencent CODING open source hosting project: Android learning notes summary + mobile architecture Video + big factory interview real questions + project actual combat source code Collection, self-study resources and series of articles are continuously updated
...(img-XeHhtbIi-1631247226691)]

[PDF document of Android core advanced technology, analysis of real interview questions of BAT manufacturers]

[external chain picture transferring... (img-ttowhr7d-163124722692)]

[Android advanced architecture video learning resources]

This article has been Tencent CODING open source hosting project: Android learning notes summary + mobile architecture Video + big factory interview real questions + project actual combat source code Collection, self-study resources and series of articles are continuously updated

Tags: R Language Android Design Pattern Programmer

Posted on Sat, 20 Nov 2021 07:37:49 -0500 by arunkar