Android componentized development framework

Android componentized development framework

Welcome to reprint, please indicate the source and author of the reprinted: kerwin original address:

####Build your own componentized development framework

Why there is this article: Long-term builds, repeated bugs, irritability of repeated development

### Introduction to componentization
####0 What is componentization

Componentization is the process of splitting the project into independent sub-projects according to different attributes.

Components are the output product of componentization, and the final assembly of different components is a complete project.

####1. Why do componentization

One idea of thinking with products is to make it easier for users (developers and testers) to do the right things . Because as the business becomes more and more complex and the amount of code becomes larger and larger, developers sometimes accidentally modify other normal functions to create new bugs when developing new features or modifying bugs. After componentization, each component is independent and does not affect each other. After the development is completed, a single component can also be released separately, and testers can test the component independently without being affected by other unrelated components.

####2, the difference between componentization and modularization and plug-inization

The difference between componentization and modularization

(Image source:
The granularity of components is larger than that of modules, and components are assembled from several different modules on demand.

The difference between componentization and plug-inization

(Image source: The
difference is that componentization is merged into the main project at compile time, and plug-inization is loaded into the main project at runtime

###3, the advantages and disadvantages of componentization

Separate compilation, easy to develop, and speed up compilation.
The components are separated to facilitate maintenance and improve the efficiency of reuse.
Release separately for easy testing and improve testing accuracy.
higher requirements for development management

### . Component-based architecture design ####0. Design requirements
1. Stable and highly available 2. Flexible release
3. Reusable

####1. Overall architecture design diagram
1. let's take a look at the conventional architecture design

Look at the architecture design after business modularization

Finally, the componentized architecture design

####2, component interaction

Because components and components cannot refer to each other, the interaction between components and components requires a middleware Router. Before components interact, they need to pass each other's interfaces through the Router to address and transfer. ####3, project release flow diagram

The same as the normal publishing process, the components are packaged first, and then the components are merged in the App and packaged as an apk file for publishing.

### Componentization of technical difficulties
####0. The realization of
hot swap Hot swap is not a new word. There is still a certain difference between the hot swap here and the conventional one.
Hot swap: Add dependency (plug), and the database, component initialization, and component interface of this component will be automatically available. Remove dependency (plug), and all functions of this component will be removed without affecting the compilation and release of other components. Look at the following database and App initialization workflow in detail

####1. Database merge and split

Implementation method:
Method 1. Add the configuration file to the App, and add the TableSetHelper of the corresponding component to the configuration file. When the database is initialized, the content in the configuration file is read and the method of calling the TableSetHelper in the component through reflection.
Compatible method 2. (Execute only if there is no configuration file) When the database is initialized, scan all Classes , find out all extends TableSetHelper and the Class annotated with **@TableSetLibrary**, and call the methods in it by reflection.

Database design uml class diagram

Database merge and upgrade flowchart

####2, component Application life cycle

Implementation method:
Method 1: Add the configuration file to the App, and add the application of the corresponding component to the configuration file. When the App is initialized, the content in the configuration file is read and the life cycle method of the Application in the component is called by reflection.

Compatibility Method 2: (Execute only if there is no configuration file) When App is initialized, scan all Classes , find out all extends Application Classes annotated with **@Applibrary**, and call the life cycle methods in them by reflection.

App initialization process design uml class diagram

App initialization process

####3. Decoupling and interaction between components

In order to achieve decoupling between components, the components cannot be directly dependent, and the router middleware is used for switching.

Interaction flow diagram between components


Add the corresponding interface in the Router module

 public interface ISum{
      int sum(int a , int b);

Add the corresponding implementation in the implemented Module (ModuleA)

public class SumImp implements ISum{
     int sum(int a , int b){
       return a+b;

When compiling, the IOC framework will scan to obtain the Data annotation, and automatically generate a class in the corresponding ModuleA

public class ISumImpFactory {

  public ISumImpFactory() {


  public static final ISum generator() {
   return new SumImp();

When calling this interface in another ModuleB,
DataRouter.findApi(ISum.class) DataRouter will try to call
ISum sum = ISumImpFactory.generator();
back to ModuleB. ModuleB can be used sumto interact with ModuleA.

####4, android.library dependency injection problem

In the Library type Module, the ID of the R file is not constant, which will cause the ioc injection framework to not be used normally. The solution here is to use Gradle to dynamically copy a copy of the R class to generate a new R file (, use When using the newly generated K file.

if ("Resources") &&"process")) {
        def taskName ="process", "").replace("Resources", "")
        def taskR2 = task("build" + taskName + "K", dependsOn: tsk) {}
        taskR2.doLast {
        tsk.doLast {
            println "doLast:" + name

####5, Activity interactive callback

The data interaction between Activity, Service, etc. are all transmitted using Bundle, and Bundle can only pass basic data types and Serializable serialized objects, which has relatively large limitations, especially if an Activity needs to receive multiple data callbacks It is especially inconvenient at times.

A new way is studied here: use Java's dynamic proxy to pass a proxy interface callback to Bundle, and then use the proxy's callback object to interact with the caller.

Code example:

public <T> T newProxy(Class<T> t, T o) {
    MyHandle handle = new MyHandle(toString());
    T callBack = (T) Proxy.newProxyInstance(getClass().getClassLoader(), new Class[]{t},
    ProxyStore.callBack.put(toString(), new WeakReference<Object>(o));
    return callBack;

private class MyHandle implements InvocationHandler, Serializable {
    String generator;
    MyHandle(String generator) {
        this.generator = generator;
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        return method.invoke(ProxyStore.callBack.get(generator).get(), args);

###4. development management

Having said so much, it seems so complicated, will it be difficult to develop, and will it be troublesome to release? In fact, there is no difference from a normal release.

Source code implementation: stitcher framework