编程知识 cdmana.com

Android builds componentization step by step

Android component building and the realization of basic functions

1. What is componentization ?

1.1 Learn about componentization :

  • Before you touch componentization , In the process of writing Android projects , All layouts , Logic functions are all in app Module implementation . It's very convenient to write small projects in this way , But some really useful mobile software is done by teams , Due to the complexity of functions , If multiple developers are in app Function development in a module , The code will look bloated , So for better and more efficient division of labor , The realization of componentized function is essential .

1.2 The basic structure of componentization :

  • Componentization is roughly divided into 3 Structures : Base layer , Component layer and application layer . Let's talk about three structures in detail .
  1. Base layer : Base layer , This is where we manually include all the dependencies of the base library that we want to use in the project , Then rely on this in all other components Base Base layer , You can apply the dependencies we added anywhere in the project . This not only needs to develop a set of dependent library code , It also decouples the coupling between basic functions and business functions , It is easier to operate when the base library changes .
  2. Component layer : Component layer can be understood as business layer , For example, a chat software project , Which is divided into login , Chat , Query and other functions , Component layer is to separate these functions one by one , Each function corresponds to a specific component .
  3. application layer : The application layer is app, Before contacting componentization , All our logic , The layout is all in app It says in it , And componentization ,app It can be described as an empty shell , Its dependencies contain other components that we create , It will refer to different modules according to the settings .

1.3 The advantages of componentization :

  • After the introduction just now , We have a general understanding of componentization . I think we know something about him , It is convenient for many people to develop , They don't influence each other , Self developed components can be run independently , Not limited by the outside world , Not because of other module problems and lead to their own module can not run . in addition , When a very large project needs to be modified , You can also easily find the module to be modified , There's no need to look in huge code for .

2. The construction of component framework :

  • Before we say build components , Let me introduce you AndroidStudio Development Android Two kinds of plug-ins are commonly used in projects .
  • application plug-in unit : If a module is declared as aoolication, So it's going to be a apk file , It is a project that can be installed and run directly .
  • library plug-in unit : Be declared library Module , It will become a aar file , It can't be run alone .

2.1 First step : Build the foundation layer

2.1.1 establish config.gradle

 Insert picture description here

  • In this , We write all the dependency Libraries , And in the project sdk And so on , And then just let buil.gradle Go to apply it , If there is any change after that, you can change it directly in here , Such as version number upgrade and so on . Here is the code I added to it :
ext{
   
   

    android = [
            compileSdkVersion :30,
            buildToolsVersion: "30.0.2",
            applicationId :"activitytest.com.example.moduletest",
            minSdkVersion: 29,
            targetSdkVersion :30,
            versionCode :1,
            versionName :"1.0",
    ]

    androidxDeps = [
            "appcompat": 'androidx.appcompat:appcompat:1.1.0',
            "material": 'com.google.android.material:material:1.1.0',
            "constaraintlayout": 'androidx.constraintlayout:constraintlayout:1.1.3',
    ]

    commonDeps = [
            "arouter_api"          : 'com.alibaba:arouter-api:1.5.1',
            "glide"                : 'com.github.bumptech.glide:glide:4.11.0'

    ]

    annotationDeps = [
            "arouter_compiler" : 'com.alibaba:arouter-compiler:1.5.1'
    ]

    retrofitDeps = [
            "retrofit"  : 'com.squareup.retrofit2:retrofit:2.9.0',
            "converter" : 'com.squareup.retrofit2:converter-gson:2.9.0',
            "rxjava"    : 'io.reactivex.rxjava2:rxjava:2.2.20',
            "rxandroid" : 'io.reactivex.rxjava2:rxandroid:2.1.1',
            "adapter"   : 'com.squareup.retrofit2:adapter-rxjava2:2.9.0'
    ]

    androidxLibs = androidxDeps.values()
    commonLibs = commonDeps.values()
    annotationLibs = annotationDeps.values()
    retrofitLibs = retrofitDeps.values()
}
  • Here I write some version numbers ,support library , route , Image loading and other common basic library , The last one 4 That's ok , It's a package for the front , Call this elsewhere 4 That's ok , It's equivalent to calling all the code I've written here . Please see Use config.gradle Unified management of project dependency libraries
  • And then in the project directory build.gradle in apply operation .
     Insert picture description here

2.1.2 Build a library Module as the base layer

  1. Click on file->new->new module, choice library module modular . I name it here Baselibs.
  2. In the module build.gradle in , Add the dependency we just wrote , Note that keyword is used here api To add , Because to do that , When other modules inherit the current module , There's no need to write dependency alone .
dependencies {
   
   

    api rootProject.ext.androidxLibs
    api rootProject.ext.commonLibs
    api rootProject.ext.annotationLibs
    testImplementation 'junit:junit:4.+'
    api 'org.greenrobot:eventbus:3.1.1'
    androidTestImplementation 'androidx.test.ext:junit:1.1.2'
    androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0'
}

2.1.3 All modules need to add dependencies to the base layer modules

  • Here we use app Layer as an example : stay app Module build.gradle Add the following .
dependencies {
   
   
    implementation project(":Baselibs")
}

That's it , The foundation layer is built .

2.2 The second step : Build component layer .

  • Because the component layer is based on integration development and component development , To be in application and library Switch back and forth between . So let's create a module first , Here I build a login modular , It's just login Of build.gradle in , The dynamic rule we want is application still library.
  • Because of the gradle.properties The variables in the , Can be in build.gradle I quote , So in gradle.preperties Set a isModule Variable :
# true Time for component mode development ,false For integrated mode development 
isModule = false
  • And then in the component build.gradle According to the isModule To set the value of :
if(isModule.toBoolean()){
   
   
    apply plugin: 'com.android.application'
}else{
   
   
    apply plugin: 'com.android.library'
}
  • Don't forget to add dependencies to the base library :
dependencies {
   
   
    implementation project(":Baselibs")
 }

2.2.1 Create different Manifest Forms

  • Because there can only be one in a project application, So when we develop components , Make login Module applications exist application Form for , In integrated development , Make login Module application does not exist application Of Manifest Forms .
  1. stay login/src/main Create under directory module file , Create a... In this Manifest Forms , Write forms for integrated development .
  • login/src/main/module In the catalog :
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="activitytest.com.example.login">

    <application
        android:allowBackup="true">
        <activity android:name=".Login"></activity>
    </application>

</manifest>
  • login/src/main In the catalog :
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="activitytest.com.example.login">

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/Theme.ModuleTest">
        <activity android:name=".Login">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

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

</manifest>
  • The difference here is not to say .
  1. There's only one project application, In other words, there is only one project applicationId,applicationId And the selection of forms is in build.gradle Set in the , So we have to base on isModule Value , To set whether there is applicationId, And which one to apply Maniest.xml.
defaultConfig {
   
   

    if(isModule.toBoolean()){
   
   
        applicationId "activitytest.com.example.login"
    }
 }
sourceSets{
   
   
    main{
   
   
        if(isModule.toBoolean()){
   
   
            manifest.srcFile 'src/main/AndroidManifest.xml'
        }else{
   
   
            manifest.srcFile 'src/main/module/AndroidManifest.xml'
        }
    }
}
  • In the way described above , I created another share Components and a mine Components , The following content will be used .

2.3 The third step : build app layer

  • This step is relatively simple , Only need app Modular build.gradle According to the isModule To decide whether to add modules of other component layers .
dependencies {
   
   
    implementation project(":Baselibs")

    if(!isModule.toBoolean()){
   
   
        implementation project(":login")
        implementation project(":share")
        implementation project(":mine")
    }
    testImplementation 'junit:junit:4.+'
    androidTestImplementation 'androidx.test.ext:junit:1.1.2'
    androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0'
}

2.4 Check the build results

  • When isModule Is set to false when , Represents integrated development at this time , Only app Components can run , No other sub business components can be run alone .
     Insert picture description here

  • When isModule The value of is true when , Represents the development of components at this time , All components can be run individually , When you run every component , The main page will show you the page where you run the component .
     Insert picture description here
    notes : Each modification isModule Value and modification of build.gradle when , You have to click sync.

  • Such a simple component-based framework is built . But there should also be communication between components , Please look down on this knowledge .

3. Between components activity Wait for the interface to jump

  • Before we had component-based application development , Interface jump we mainly use explicit Intent And implicit Intent The two methods . But in component development , It is not allowed that the module of component layer depends horizontally , So you can't directly access each other's classes , You can't use explicit Intent To jump , And implicit Intent Jump also needs to go through AndroidManifest centralized management , In collaborative development, it's more troublesome . So here we introduce a new method of interface jump , Use Alibaba Open source ARouter To achieve .

3.1 ARouter Introduce

  • ARouter It's a tool to help Android App The framework for component transformation —— Support routing between modules 、 signal communication 、 decoupling . It can realize the routing function between components . Routing refers to receiving packets from an interface , The process of directing and forwarding a data routing packet to another interface according to its destination address . This can reflect the characteristics of route jump , It is very suitable for component decoupling .

3.2 Use ARouter To prepare

  1. To use ARouter Jump to the interface , We need our components to Arouter Add dependency , Because all the components depend on Base layer Baselibs modular ,Baselibs The module depends on what we write config.gradle, So we are config.gradle Add... To the module ARouter You can rely on .
     Insert picture description here
  2. In addition to adding ARouter Dependence , We also need to add annotation processor dependencies , This is different from ARouter rely on , This needs to be added once in every application component , Not only add this , Also in each application of the components of build.gradle Of defaultConfig The configuration ARouter.
dependencies {
   
   
    implementation project(":Baselibs")
    annotationProcessor rootProject.ext.annotationLibs		// Annotation Processors 

    if(!isModule.toBoolean()){
   
   
        implementation project(":login")
        implementation project(":share")
        implementation project(":mine")
    }
    testImplementation 'junit:junit:4.+'
    androidTestImplementation 'androidx.test.ext:junit:1.1.2'
    androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0'
}
defaultConfig {
   
   
    javaCompileOptions{
   
   				// To configure ARouter
        annotationProcessorOptions{
   
   
            includeCompileClasspath false
            arguments = [AROUTER_MODULE_NAME:project.getName()]
        }
    }
}
  1. Before use , We still have to be in app Layer of application In the initialization ARouter, To initialize the project as soon as it's started , So we are application Medium oncreate method .
public class MainApplication extends BaseApplication {
   
   

    @Override
    public void onCreate() {
   
   
        super.onCreate();

        //ARouter Backstage ILogger Interface , Some output logs are defined 
        if (isDebug()) {
   
              //  These two lines must be written in init Before , Otherwise, these configurations are in init The process will not work 
            ARouter.openLog();     //  Print log 
            ARouter.openDebug();   //  Turn on debugging mode ( If in InstantRun Run in mode , Debug mode must be turned on ! Online version needs to be closed , Otherwise, there is a safety risk )
        }
        ARouter.init(this); //  As early as possible , Recommended in the Application In the initialization ARouter

        init(this);
        initover(this);
    }

    private boolean isDebug() {
   
   
        return BuildConfig.DEBUG;
    }
 }
  • So we're ready for ARouter Configuration of , Then you can start using .

3.3 ARouter Use

  1. We're about to jump activity,service perhaps fragment And so on, the above statement adds comments @Route(path = “/xx/xx”), here path It's a jump path ,/xx/xx It's a secondary directory . Be careful : You can't have the same path , The first level directory of different components cannot be the same , The first level directory of the same component can be the same .
  2. And then when you want to jump , Write the following line of code to jump to the activity of the corresponding path ARouter.getInstance().build("/xx/xx").navigation();build It's filled in with path Address , You can also add the suffix withInteger,withString Wait, pass the data , And then again navigation You can jump .
  • Here we are app Layer sets two jump buttons , stay login and share The annotation is declared in the component , Accept jump .
login.setOnClickListener(new View.OnClickListener() {
   
   
    @Override
    public void onClick(View v) {
   
   
        ARouter.getInstance().build("/login/login1").navigation();
    }
});
share.setOnClickListener(new View.OnClickListener() {
   
   
    @Override
    public void onClick(View v) {
   
   
        ARouter.getInstance().build("/share/share1").navigation();
    }
});
@Route(path = "/login/login1")
public class Login extends AppCompatActivity {
   
   

    @Override
    protected void onCreate(Bundle savedInstanceState) {
   
   
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_login);

    }
}


@Route(path = "/share/share1")
public class Share extends AppCompatActivity {
   
   

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

Running results :
 Insert picture description here

  • Click jump to login
     Insert picture description here

  • Click to jump to share
     Insert picture description here

4. Data transfer between components ( Interface + Realization )

  • Because of the main project and components , Components and components can not directly use class cross reference for data transmission . There are many other ways of data interaction between components , such as EventBus, radio broadcast , Data persistence, etc , But often the interaction in these ways is not so intuitive , So through Service This form of interaction can be implemented , We'd better pass through this interface + To achieve this way .

4.1 ( Interface + Realization ) The general idea of

  • For example, here we are in share Component to get the login related information : Because all components depend on Baselibs Components , So in Baselibs Create an interface in a component ServiceFactroy, And then in login Create a class in the component to implement this interface , Then upload this class to ServiceFactroy, And then in share Components from ServiceFactroy Get the implementation class object from the .

4.2 ( Interface + Realization ) Practical operation of

  1. Create an interface for login Component implementation :
public interface LoginService {
   
   
     boolean isLogin();
     String getPassword();
}
  1. establish ServiceFactroy To manage login The interface implementation class passed by the component , And set up get,set Method :
public class ServiceFactory {
   
   
    private LoginService loginService;
    private ServiceFactory(){
   
   

    }
    public static ServiceFactory getInstance(){
   
   
        return Inner.serviceFactory;
    }
    private static class Inner{
   
   
        private static ServiceFactory serviceFactory = new ServiceFactory();
    }

    public void setLoginService(LoginService loginService){
   
   
        this.loginService = loginService;
    }
    public LoginService getLoginService(){
   
   
        if(loginService == null){
   
   
            return new EmptyService();
        }else{
   
   
            return loginService;
        }
    }
}

This is achieved by static inner classes ServiceFactory Single case , because ServiceFactroy It contains the login information, this important and unique information , So there can only be one ServiceFactroy object , So to implement its singleton creation .

  1. because login The component may not have passed an implementation class ,share Just call get Method , To prevent anomalies , We also need to create an empty implementation of the service , When login When the implementation class was not uploaded ,get Return to this empty implementation .
public class EmptyService implements LoginService{
   
   
    @Override
    public boolean isLogin() {
   
   
        return false;
    }

    @Override
    public String getPassword() {
   
   
        return null;
    }
}
  1. And then there's the login In the component , Achieve this LoginService Interface , And in activity After clicking the login button in , Will store login status and user information , And upload it to the interface implementation class , Then upload the interface implementation class to ServiceFactroy. Here we also created a LoginUtil Class as a bridge to store this data .
  • The first is to implement the interface :
public class AccountService implements LoginService {
   
   

    private boolean login;
    private String password;

    public AccountService(boolean login, String password) {
   
   
        this.login = login;
        this.password = password;
    }

    @Override
    public boolean isLogin() {
   
   
        return login;
    }

    @Override
    public String getPassword() {
   
   
        return password;
    }
}
  • The tool class that stores data :
public class LoginUtil {
   
   
    static boolean isLogin = false;
    static String password = null;
}
  • stay activity Click the login button in the implementation of the operation :
login = (Button)findViewById(R.id.login_text);
login.setOnClickListener(new View.OnClickListener() {
   
   
    @Override
    public void onClick(View v) {
   
   
        LoginUtil.isLogin = true;
        LoginUtil.password = "admin";
        ServiceFactory.getInstance().setLoginService(new AccountService(LoginUtil.isLogin,LoginUtil.password));
    }
});
  • Because we don't know when other components will be in ServiceFactroy Get this class in , So we need to upload this interface implementation class at the beginning of the project , So it's in login Of application Upload in .
public class LoginApplication extends Application {
   
   
    @Override
    public void onCreate() {
   
   
        super.onCreate();
        ServiceFactory.getInstance().setLoginService(new AccountService(LoginUtil.isLogin,LoginUtil.password));
     }
}
  1. The last step is to share Component to get the login information . Here we add a share button to the share component , After clicking , You will be prompted whether the sharing is successful according to the login information .
share = (Button)findViewById(R.id.share_text);
share.setOnClickListener(new View.OnClickListener() {
   
   
    @Override
    public void onClick(View v) {
   
   
        if(ServiceFactory.getInstance().getLoginService().isLogin()){
   
   
            Toast.makeText(Share.this," Share success !",Toast.LENGTH_SHORT).show();
        }else{
   
   
            Toast.makeText(Share.this," Sharing failure , Please log in first !",Toast.LENGTH_SHORT).show();
        }
    }
});

Be careful : There's a problem here , It's when we want to start the project , Will be in login Upload an implementation class to ServiceFactroy in , And wrote this command to login Component's application in , But a project can only have one application, in other words Login In the component application Will not initialize , So we're talking about one Application Dynamic configuration of . The following table of contents 6 How to operate .

5. Data transfer between components (EventBus)

5.1 What is? EventBus?

  • EventBus It's a Android Release / Subscribe to the event bus . It has many advantages : Simplify communication between application components ; Decouple the sender and receiver of the event ; Avoid complex and error prone dependency and lifecycle issues ; Soon , Optimized for high performance and so on .
  • EventBus It's taken by subscribers / The publisher's model , The publisher passed EventBus Release events , Subscriber pass EventBus Subscription events . When the publisher releases an event , The event handling method of the subscriber who subscribes to this event will be called .

5.2 Use EventBus Preparatory work

  1. To use EventBus, The first preparation is to add EventBus Dependence . We are directly here in Baselibs Add .
dependencies {
   
   
    api 'org.greenrobot:eventbus:3.1.1'
}
  1. Just said ,EventBus Using subscribers / Publisher mode , in other words , We need to create an event first , Then you want to create a publisher for the component that sends the relevant information , Then create a subscriber in the component to receive the message and get the message . So the second step is to create an event , Create an arbitrary class , Write the message to be delivered in it , Prior to joining get/set The method can .
public class EventMessage {
   
   

    String account;

    public EventMessage(String account) {
   
   
        this.account = account;
    }

    public String getAccount() {
   
   
        return account;
    }

    public void setAccount(String account) {
   
   
        this.account = account;
    }
}

Because this event may be published or received in every component , In order for all other components to get instances of this class , So it's directly in Baselibs In the component main/java Next create a file EventBus, Write the defined event class in it .
 Insert picture description here

  • That's all the preparatory work .

5.3 EventBus Basic use of

5.3.1 Subscription events

  1. First, we need to register the subscriber in the component that is ready to subscribe to the event . It's in activity Of onCreate Register in , stay onDestroy The cancellation . call EventBus.getDefault().register() and EventBus.getDefault().unregister() Method .
  • Here I have another Mine modular , Similar to the sharing module , It's just that the user's personal information is displayed here , In order to distinguish between EventBus And interface + The difference between the two implementations . So we are Mine Register in the module .
@Route(path = "/mine/mine1")
public class Mine extends AppCompatActivity {
   
   

    TextView textView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
   
   
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_mine);
        textView = (TextView)findViewById(R.id.message);
        EventBus.getDefault().register(this);
    }

    @Override
    protected void onDestroy() {
   
   
        super.onDestroy();
        EventBus.getDefault().unregister(this);
    }
}
  1. Next, the subscriber needs to define the event handling method ( Also known as the subscriber method ). When publishing events of the corresponding type , This method will be called .EventBus Use @Subscribe Annotations to define the subscriber method . The method name can be any legal method name , The parameter type is the type of the subscription event .
@Subscribe(threadMode = ThreadMode.POSTING,sticky = true)
public void showEventMessage(EventMessage message){
   
   
    textView.setText(message.getAccount());
}

as for threadMode and sticky We'll talk about it alone later .

5.3.2 Release events

  1. Post events where needed , All subscribers who have subscribed to this type of event and have registered will receive the event at any time . Here it is login The component uses EventBus.getDefault().post() Method to publish an event .
login.setOnClickListener(new View.OnClickListener() {
   
   
    @Override
    public void onClick(View v) {
   
   
        LoginUtil.isLogin = true;
        LoginUtil.password = "admin";
        EventBus.getDefault().post(new EventMessage(LoginUtil.password));           // send out EventBus
    }
});
  • Come here EventBus The simple use of the . Next is Eventbus Several advanced uses of .

5.4 EventBus Advanced use of

5.4.1 EventBus Thread mode of

  • When you just created the subscription method , In the notes threadMode, This is the threading pattern .EventBus The support subscriber method is called in a thread different from the thread in which the event is published . You can use thread mode to specify the thread that calls the subscriber method .EventBus Total support 5 Thread mode :
  1. ThreadMode.POSTING The subscriber method will be called in the thread where the event is published . This is a Default thread mode . The delivery of events is synchronous , Once the event is released , All subscriber methods of this pattern will be called . This threading pattern means minimal performance overhead , Because it avoids thread switching . therefore , This mode is recommended for simple tasks that do not require to be the main thread and take a short time . Subscriber methods that use this pattern should return quickly , To avoid blocking threads that publish Events , This could be the main thread .
  2. ThreadMode.MAIN The subscriber method will be in the main thread (UI Threads ) In the called . therefore , It can be updated directly in the subscriber method of the pattern UI Interface . If the thread that publishes the event is the main thread , Then the subscriber method of the pattern will be called directly . Subscriber methods that use this pattern must return quickly , To avoid blocking the main thread .
  3. ThreadMode.MAIN_ORDERED The subscriber method will be in the main thread (UI Threads ) In the called . therefore , It can be updated directly in the subscriber method of the pattern UI Interface . Events are queued before they are sent to subscribers , So the call to publish the event will immediately return . This keeps the processing of events in strict serial order . Subscriber methods that use this pattern must return quickly , To avoid blocking the main thread .
  4. ThreadMode.BACKGROUND The subscriber method will be called in the background thread . If the thread that publishes the event is not the main thread , Then the subscriber method will be called directly in that thread . If the thread that publishes the event is the main thread , Then a separate background thread will be used , The thread will send all the events in order . Subscriber methods that use this pattern should return quickly , To avoid blocking background threads .
  5. ThreadMode.ASYNC The subscriber method will be called in a separate thread . therefore , The call to publish the event will immediately return . If the execution of the subscriber method takes some time , For example, network access , Then the pattern should be used . Avoid triggering a large number of long-running subscriber methods , To limit the number of concurrent threads .EventBus A thread pool is used to effectively reuse threads that have completed calling subscriber methods .

5.4.2 EventBus The viscous event of

  • stay EventBus in , If the event is released first , Then a subscriber subscribes to the event , Well, unless the event is released again , Otherwise, the subscriber will never receive the event . here , Sticky events can be used . After releasing a sticky event ,EventBus The sticky event will be cached in memory . When a subscriber subscribes to the sticky event , The subscriber will receive the event .
  1. The comment for the subscription method of sticky events should be written with sticky = true, And then publishing sticky events is different , You don't use EventBus.getDefault().post() Method , It is EventBus.getDefault().postSticky() Method .
@Subscribe(threadMode = ThreadMode.POSTING,sticky = true)		// subscribe 
public void showEventMessage(EventMessage message){
   
   
}

EventBus.getDefault().postSticky(new EventMessage(LoginUtil.password));           // Send stickiness EventBus
  • It's just that we need to get the login information from the beginning , So it's appropriate to release a sticky event .

6.Applicaion Dynamic configuration of

  • In the problem of information transmission between components mentioned above , Using interfaces + When the method of implementation is passed , When we want the project to initialize , stay Login Component to send out the interface implementation class , But there is only one in a project application,Login Component's application It's not initialized . So at this point login Components will not send interface implementation classes .
  • resolvent : Strong reference the class of the component to the main Module Of Application Initialize in , This requires that the main module can directly access the classes in the component . And we don't want the main module to be able to access the classes in the component during the development process , Here you can implement components through reflection Application The initialization . That is to say Application Dynamic configuration of .
  • == Ideas :== Build a BaseApplication Inherit Application, And then make the others application Classes are inherited from BaseApplication, stay BaseApplication There are two ways , One is initialization , One is the function that is called after initialization , And then in app Reflection is used in the main module , obtain Login Medium application class , And then call its initialization method .

6.1 Build a BaseApplication

  • because Bselibs Components are dependent on other components , And ask for inheritance BaseApplication Class of must override method , So we are Baselibs Create an abstract class in BaseApplication Inherit Application. as follows :
public abstract class BaseApplication extends Application {
   
   
    public abstract void init(Application application);         // The method that initiates the current component call 
    public abstract void initover(Application application);               // Other methods that need to be called 
}

6.2 Modify the master Module Of application class

  • Go straight to the code
public class MainApplication extends BaseApplication {
   
   

    @Override
    public void onCreate() {
   
   
        super.onCreate();
        //ARouter Backstage ILogger Interface , Some output logs are defined 
        if (isDebug()) {
   
              //  These two lines must be written in init Before , Otherwise, these configurations are in init The process will not work 
            ARouter.openLog();     //  Print log 
            ARouter.openDebug();   //  Turn on debugging mode ( If in InstantRun Run in mode , Debug mode must be turned on ! Online version needs to be closed , Otherwise, there is a safety risk )
        }
        ARouter.init(this); //  As early as possible , Recommended in the Application In the initialization ARouter

        init(this);
        initover(this);
    }

    private boolean isDebug() {
   
   
        return BuildConfig.DEBUG;
    }


    @Override
    public void init(Application application) {
   
   ...}

    @Override
    public void initover(Application application) {
   
   ...}
}

6.3 modify Login Component's application class

  • Direct code
public class LoginApplication extends BaseApplication {
   
   
    @Override
    public void onCreate() {
   
   
        super.onCreate();
        init(this);
        initover(this);
    }


    @Override
    public void init(Application application) {
   
   
        ServiceFactory.getInstance().setLoginService(new AccountService(LoginUtil.isLogin,LoginUtil.password));
    }

    @Override
    public void initover(Application application) {
   
   

    }
}
  • Here we have done application Configuration of , And then we can use reflection in app Lord Module Of application Get in class Login Component's application class , Implement its approach .

6.4 Use reflection to get the... Of other components application To initialize

  • stay app Module application Two methods rewritten in , Get and initialize .
@Override
public void init(Application application) {
   
   
    for(String moduleApp : AppConfig.moduleApps){
   
   
        try{
   
   
            Class clazz = Class.forName(moduleApp);
            BaseApplication baseApplication = null;
            baseApplication = (BaseApplication) clazz.newInstance();
            baseApplication.init(this);
        }catch (Exception e){
   
   
            e.printStackTrace();
        }
    }
}

@Override
public void initover(Application application) {
   
   
    for(String moduleApp : AppConfig.moduleApps){
   
   
        try{
   
   
            Class clazz = Class.forName(moduleApp);
            BaseApplication baseApplication = null;
            baseApplication = (BaseApplication) clazz.newInstance();
            baseApplication.initover(this);
        }catch (Exception e){
   
   
            e.printStackTrace();
        }
    }
}
  • After doing this , We were at the beginning of the project ,Login The component will send an interface implementation class to ServiceFactroy 了 .

7. The main project uses the methods of each component's class

  • Here are three ways , One is reflection , One is through the interface + Method of implementation , The other is routing .

7.1 The method of reflection

  • And the acquisition just said Login Component's application Class is the same , It's just that this time we use reflection to get fragment instances , Load fragments into activity in , then activity And put it in the right place .

7.2 Interface + Method of implementation

  • Same as before , stay ServiceFactroy Creating a fragment object in , Then add a constructor , The parameter is fragment , Providing a get and set The method is ok .
  • Don't forget it , stay Baselibs Add an empty implementation in , lest get Error in method call .

7.3 The implementation method of routing

  • A simple line of code .
mineFragment = (Fragment) ARouter.getInstance().build("/mine/fragment").navigation();
  • In this way, we can easily get the instance of the component fragment .

版权声明
本文为[osc_bs9rqgec]所创,转载请带上原文链接,感谢

Scroll to Top