A Preliminary Study of Android Componentization [With Demo]

Demo address: Click here to find the administrator

Overview

The software development process is also the evolution process of the architecture. Take Android as an example, from the very beginning of MVC, MVP, MVVP, to componentization and plug-inization, but in the final analysis, everything is for better maintenance of the project. , Iterate and reduce development costs.

In the development process of a project, we may put all the functional modules in a moudle in the early stage, so that rapid development can be achieved, but as the project grows, the number of developers and functions increases, the code becomes more and more bloated. , The coupling between the various modules is getting heavier and heavier, which affects the whole body. At this time, in order to ensure the quality of the project, we need to refactor the project.

We can check points according to business modules, put different business modules in different moudles, and realize the structure between each business. They also rely on the underlying public library together. This is the concept of modularity , but when multiple modules are involved When the same function is reached, the coupling of the code will increase. For example, there are two modules that require the function of video playback. Putting the video playback in two components will cause the code duplication problem. Putting it in the public library does not feel very good. At this time, use componentization to solve this problem

Modularization and componentization

Modular

Specific business modules, such as product details module, product release module, search module

Componentization

Single functional components, such as video playback components, sharing components, etc., each component can be developed as a separate module, and can be extracted separately as an SDK for external release

The idea of ​​modularization and componentization is the same, both of which are to split the code, but modularization is to check and divide according to functional modules (business-oriented), and componentization is to check and divide according to functional modules (function-oriented). Modularized particles The degree is larger, and the granularity of the components is smaller. It is very common for modules and components to exist at the same time in a project, and they are responsible for their own affairs.

As shown in the figure above, it is the basic structure of a componentized project

  • Basic library, public library : the basic operation class, tool class, third-party library import package required by the project, app host function, each module, each component all rely on this library
  • Component layer : functional modules or business modules used in the project, such as: login module, video playback component, sharing component, etc.
  • Application layer : host project, APP main project, APP entrance and main shelf

Componentized Demo

Demo address: Click here to ask the administrator to explain from the following aspects based on the demo project

  • 1: Project analysis
  • 2: Dynamic switching between component application and library
  • 3: Data transfer and method calls between components
  • 4: Obtaining component classes (for example: Fragment), and boasting component page jump and communication

1: Project analysis

As shown in the figure above, the main structure of the project

  • Application layer: the main entrance of the app project
  • Component layer: goods login product detail page and login component
  • Basic library layer: assemblebase is used to interact with the data and methods of each component, base is a commonly used tool class, and the package of various class libraries

2: Dynamic switching between component application and library

In the development process, in order to achieve rapid development, it is particularly important that components can run independently. Moudle is generally divided into two types

  • App plug-in, id: com.android.application
  • Library 插件,id: com.android.library

We can dynamically switch between application and library through configuration. We configure a variable to control the switch in the gradle.properties file of each component

Then you can switch between application and library through the isRunAlone variable in build.gradle. There are three main design points.

  • Configuration of plugin attributes
  • Configuration of applicationId
  • Configuration of AndroidManifest
if (isRunAlone.toBoolean()) {
    apply plugin: 'com.android.application'
} else {
    apply plugin: 'com.android.library'
}

android {
    compileSdkVersion 26

    defaultConfig {
        if (isRunAlone.toBoolean()) {
            applicationId "ppzh.jd.com.goods"
        }
        minSdkVersion 15
        targetSdkVersion 26
        versionCode 1
        versionName "1.0"

        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"

    }

    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }

    sourceSets {
        main {
            if (isRunAlone.toBoolean()) {
                manifest.srcFile 'src/main/manifest/AndroidManifest.xml'
            } else {
                manifest.srcFile 'src/main/AndroidManifest.xml'
            }
        }
    }

}

If the above configuration is used, the application and library can be switched

3: Data transfer and method calls between components

Since the main project, components, components and components cannot directly pass data and method calls by reference, then how to transfer data and method calls during the development process can be done through "interface" + "implementation". get on,

The assemblebase base library is used for data transfer and method invocation. It is dependent on all components. Assemblebase provides an abstract service for each component to provide external data and method invocation. At the same time, there is also a serviceFactory to operate the service. Each component is initialized. Implement the respective service. At the same time, the null implementation of all Service will be provided to avoid the null pointer exception caused by

Take the login module as an example, provide two external data

public interface ILoginService {

    /**
     * 是否已经登录
     *
     * @return
     */
    boolean isLogin();

    /**
     * 获取登录用户的 AccountId
     *
     * @return
     */
    String getAccountId();

}

The related serviceFactory classes are as follows, you can pull related service instances through serviceFactory

public class ServiceFactory {

    private ILoginService loginService;
    private IGoodsService goodsService;

    /**
     * 禁止外部创建 ServiceFactory 对象
     */
    private ServiceFactory() {
    }

    /**
     * 通过静态内部类方式实现 ServiceFactory 的单例
     */
    public static ServiceFactory getInstance() {
        return Inner.serviceFactory;
    }

    private static class Inner {
        private static ServiceFactory serviceFactory = new ServiceFactory();
    }

//    ------------------------LoginService------------------------
    /**
     * 接收 Login 组件实现的 Service 实例
     */
    public void setLoginService(ILoginService loginService) {
        this.loginService = loginService;
    }

    /**
     * 返回 Login 组件的 Service 实例
     */
    public ILoginService getLoginService() {
        if (loginService == null) {
            loginService = new EmptyLoginService();
        }
        return loginService;
    }

Only need to implement ILoginService in the login component, and set it through serviceFactory

public class LoginService implements ILoginService {
    @Override
    public boolean isLogin() {
        return false;
    }

    @Override
    public String getAccountId() {
        return null;
    }
}

Set the service in the login appliction

public class LoginApp extends BaseApp {

    @Override
    public void onCreate() {
        super.onCreate();
        initModuleApp(this);
        initModuleData(this);
    }

    @Override
    public void initModuleApp(Application application) {
        ServiceFactory.getInstance().setLoginService(new LoginService());
    }

    @Override
    public void initModuleData(Application application) {

    }
}

But there is such a problem: LoginApp is not executed when integrated into the app. How can this be solved? We can solve it through reflection

public class AssembleApplication extends BaseApp {
    @Override
    public void onCreate() {
        super.onCreate();
        initModuleApp(this);
        initModuleData(this);
        initComponentList();
    }

    @Override
    public void initModuleApp(Application application) {

    }

    @Override
    public void initModuleData(Application application) {

    }

    //初始化组件
    //通过反射初始化
    private void initComponentList(){
        for (String moduleApp : AppConfig.moduleApps) {
            try {
                Class clazz = Class.forName(moduleApp);
                BaseApp baseApp = (BaseApp) clazz.newInstance();
                baseApp.initModuleApp(this);
                baseApp.initModuleData(this);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

}

It's done as shown above

4: Obtaining component classes (for example: Fragment), and boasting component page jump and communication

Fragment acquisition is also done through service

public interface IGoodsService {

    /**
     * 创建 GoodsFragment
     * @param bundle
     * @return
     */
    Fragment newGoodsFragment(Bundle bundle);
}

Related components can implement the interface

The page jump between the various components can be achieved through Ali's ARouter . I did it by setting the ComponentName, but this method does not seem to achieve real code isolation.

 /**
     *
     * 去登陆
     *
     * 跨组件页面跳转
     */
    private void toLogin(){
        Intent intent = new Intent();
        intent.setComponent(new ComponentName(mContext, "ppzh.jd.com.login.LoginActivity"));
        startActivityForResult(intent,LOGIN_REQUEST_CODE);
    }

to sum up

Through the above, the project componentization is realized as a whole, and componentization can be used more for project development in the future.

Author: Brad Nuggets preserved
the original address: https: //juejin.cn/post/6844903978036101128

At last

This article has been included in the open source project: https://github.com/xieyuliang/Android-P7-share/blob/master/ (click here to view
in blue font) , which contains self-learning programming routes and interview questions in different directions Collection/face classics, and series of technical articles, etc. The resources are being continuously updated...

Guess you like

Origin blog.csdn.net/weixin_49559515/article/details/111997332