catalogue
- 1. Why componentization
- 1.1 Why componentization
- 1.2 Problems encountered at the present stage
- 2. The concept of componentization
- 2.1 What is componentization
- 2.2 Distinguishing between modularization and componentization
- 2.3 Componentization Benefits
- 2.4 Distinguish between componentization and plug-in
- 2.5 the application and the library
- 2.6 Splitting the third-party SDK
- 3. Create a componentization framework
- 3.1 Traditional APP architecture Diagram
- 3.2 Issues to be considered for componentization
- 3.3 Architecture design drawings
- 3.4 Component communication is forwarded through routing
- 3.5 Solution consideration
- 3.6 Life Cycle of Service Components
- 3.7 Fragment Communication difficulties
- 4. Actual development cases
- 4.1 Open source projects for componentization practices
- 4.1 How To Create a Module
- 4.2 How Do I Create A Dependency
- 4.3 How can I Unify configuration Files
- 4.4 Componentized basic libraries
- 4.5 How can I Switch between the Component Mode and integration Mode
- 4.6 Componentization Solve repeated dependencies
- 4.7 Componentization Points
- 4.8 Resource Name Conflict during Componentization
- 4.9 Componentized development encountered problems
- 5. Communication between components
- 5.1 Select the Open source routing library
- 5.2 Basic principles of Arouter
- 5.3 Precautions for using Arouter
- 6. About Others
- 6.1 Refer to the blog link
- 6.2 Introduction to my blog
- 6.3 Open Source Project Address
0. Componentized development case open source address
Github.com/yangchong21…
1. Why componentization
1.1 Why componentization
- The cost of APP iterative maintenance increases
- APP itself such as the investment community, buds, project plant in rapid development, version iterated, new features continue to increase, increasing number of business module, business processing logic becomes more and more complex, each module code is also becoming more and more at the same time, this will cause a problem, the code maintenance cost is higher and higher, a slightly changes may be extremely important, Changing a small feature point requires retesting the entire APP, which can be challenging for development and maintenance.
- Multiple groups require componentization
- APP architecture way is single engineering mode, expand business scale, then there is the team scale, it involves the collaboration problem, each mobile software developers must be familiar with so many code, if not according to certain module component mechanism to divide, it will be hard for many people collaborative development, as a single project, In addition, Andorid projects can become very slow in compiling the code. The single engineering code is heavily coupled, and every change in the code requires recompiling and packaging tests, which can be very time-consuming.
1.2 Problems encountered at the present stage
- Combined with the investment community, new client analysis
- Code volume ballooning, not good for maintenance, not good for new feature development. Project construction speed is slow, write two sentences of code on some computers, recompile the whole project, test the compilation speed at least 10-20 minutes, some even longer.
- Code coupling between different modules is severe, and sometimes a change in one piece of code affects many modules. Each module has a reference to a third-party library, but some of the third-party library versions are inconsistent, resulting in code redundancy when packaging the APP and easy to cause version conflicts.
- The existing projects are developed on the basis of previous projects of others, and there are too many person-times. There are different code styles. The code specifications in the projects are disorderly, but the writing methods of similar functions are different, resulting in disunity.
2. The concept of componentization
2.1 What is componentization
- What is componentization?
- A Component is a simple encapsulation of data and methods with a single function, high cohesion, and the smallest granularity that a business can divide into.
- Componentization is the purpose of the reusable component based on, will be a large software system according to the form of separation of concerns, split into multiple independent components, make the software system also do circuit board, is a single or multiple components components assembled, which component is broken, the whole system can continue to run, but not collapse or not normal phenomenon, Achieve less coupling and higher cohesion.
2.2 Distinguishing between modularization and componentization
- modular
- Modularity is to split a program into independent modules according to its function, so that each module contains only the content related to its function. Modules are relatively familiar to us, such as login function can be a module, search function can be a module, and so on.
- componentization
- Componentization is more concerned with reusability, more concerned with separation of concerns, if from the perspective of collection, it can be said that often a module contains one or more components, or a module is a container, assembled from the components. In simple terms, componentization is smaller than modularization. The essential idea of both is the same, which is to split the large to small direction for reuse and decoupling. However, modularization focuses more on the division of business functions and tends to reuse, while componentization focuses more on the cohesion of single functions and tends to decouple.
2.3 Componentization Benefits
- In short, it is to improve work efficiency and liberate productivity. The benefits are as follows:
- 1. Improve the compilation speed to improve the efficiency of parallel development.
- Question: So how to improve compilation speed? Componentization frameworks allow modules to be compiled and debugged individually, effectively reducing compilation time.
- 2. Stable public modules rely on libraries
- Provide to each line of business use, reduce repeated development and maintenance workload. Code concise, less redundancy, easy maintenance, easy to extend new functions.
- 3. Each component has its own version that can be compiled, tested, packaged, and deployed independently.
- For companies with many developers, componentization is necessary. Each person is responsible for his/her own module, which can reduce the number of code conflicts.
- For the new business integration at any time to provide a foundation, all business can be up and down, flexible.
- Business line R&D can not interfere with each other, improve collaboration efficiency, and control product quality.
- 4. Avoid cross-dependence between modules and achieve low coupling and high cohesion.
- 5. Unified code management of referenced third-party libraries to avoid version unification and reduce the introduction of redundant libraries.
- This can create a public gradle managed file, such as a project has a dozen components, you want to change a library or version number, not all of them. At this time it is necessary to extract the public
- 6. Customized projects can be loaded on demand and components can be flexibly built to quickly generate different types of customized products.
- 1. Improve the compilation speed to improve the efficiency of parallel development.
2.4 Distinguish between componentization and plug-in
- The difference between componentization and plug-in
- Componentization is not pluginization, pluginization is at run time, and componentization is at compile time. In other words, pluginization is based on multiple APKs, whereas componentization is essentially a single APK.
- The biggest (and probably only) difference between componentization and pluginization is that componentization does not have the ability to dynamically add and modify components at run time, whereas pluginization does.
- The goal of componentization
- One of the goals of componentization is to reduce the dependencies between the overall project (APP) and the components, without which any component can exist and function. App master project has the function of binding and unbinding components.
2.5 the application and the library
- In Studio, the two modules are distinguished, as shown below
- One is the base library, such as common third-party libraries called Lib, whose code is directly referenced by other components.
- The other is application, also called Component, which is a complete functional module. For example, a shared Module is a Component.
- For convenience, the library is called a dependency and the Component is called a Component. The componentization described below is mainly for the Component type.
- In your project’s build.gradle file
// Control the component pattern and integration patternif(rootProject. Ext. IsDouBanApplication) {/ / Component, can run independently apply the plugin:'com.android.application' } else{// the apply plugin is dependent on the lib plugin:'com.android.library' } Copy the code
2.6 Splitting the third-party SDK
- I read a lot of blogs, and almost none of them have any problems with third-party SDK integration when breaking down business components. For example: when your app can use wechat login, in the app main project, login is normal, this time you are through the main project app package name to wechat open platform to apply for ID and key values. However, when you split the login registration into a separate business component, the package name of the component is different from the name of the app main project package, so at this time, if you switch to the component mode, the third party login may have problems.
- In other words, when you use some third-party SDKS, you initially apply for the key value with the package name of the app [this value is generated based on the package name], and then when you break up the business components, the package name of the component is not the same as the package name of the app, so when you switch to the component and the application can run independently, there may be a bug. Problem caused by package name. Personal advice, when it comes to third-party SDKS split, can be encapsulated as lib dependencies, or you deliberately make the package name the same.
3. Create a componentization framework
3.1 Traditional APP architecture Diagram
- Traditional APP architecture diagram
- As is shown in the picture,…
- Existing problems
- In the widely used Android APP technical architecture, there is usually a large amount of business logic in one interface, which is full of various network requests, data operations and other behaviors. There is no concept of modules in the whole project, only simple folders divided by business logic. And businesses are directly called to each other and highly coupled together. Business relationships under a single engineering model are, in general, interdependent and inseparable. The diagram below:
3.2 Issues to be considered for componentization
- Questions to consider
- Divide and conquer, parallel development, everything is components. In order to achieve componentization, no matter what technology is adopted, the following seven aspects need to be considered:
- Code decoupling.
- How to divide a huge project into organic whole? This needs to be done step by step!
- The existing project is divided into two types of modules. One is functional component module, which encapsulates some common methods and services and provides them as dependency libraries. The other is the business component module, which deals with functions such as business logic, and these business component modules are ultimately responsible for assembling the APP.
- Components run separately.
- Since each component is highly cohesive and an integral whole, how do you get it to run and debug separately?
- Gradle script configuration method, to switch between different environments, my own operation is to add a Boolean value switch. For example, just switch the Apply plugin: ‘com.android.library’ to the Apply plugin: ‘com.android.application’.
- Note: when switching to an application running independently, you need to set it up in the AndroidManifest file, because a separate debug requires an Activity with an entry.
- Communication between components.
- Since the implementation details of each component are unknown to the other, but each component needs to provide services to other callers, how does the main project communicate with the component, and with the component?
- This I am direct use Ali open source routing framework, of course, you can according to the need to choose other big factory open source routing library. Using ARouter framework of Ali, jump to the page by annotating.
- Component life cycle.
- The life cycle here refers to the time that the component exists in the application. Whether the component can be used on demand and dynamically will involve the management issues such as component loading and unloading.
- Integration debugging.
- How do you compile components on demand during development? It is possible to integrate one or two components at a time, which can greatly reduce compilation time and improve development efficiency.
- Code isolation.
- If the interaction between components is still direct reference, then the components are not decoupled at all. How to avoid direct reference between components? The current practice is that both the main project and the business component depend on the common base component library, and the business component finds on demand by routing the service dependency library for communication between different components.
- Business components can be developed independently in the component mode. In the integration mode, business components can become AAR packages and be integrated into the “APP Shell Project” to form an APP with complete functions.
- Code decoupling.
3.3 Architecture design drawings
- Componentized architecture diagram
- Business components are independent and not related to each other. In the integration mode, these business components are libraries, which are dependent on the APP shell project and constitute an APP with complete business functions. However, in the component development mode, business components become applications. They can be developed and debuggable independently, and because in component development mode the amount of code the business components use is far less than the full project, they can significantly reduce compile time at runtime.
3.4 Component communication is forwarded through routing
- Traditional previous engineering under modules
- I remember that when I first entered the Android development work, there was only one app main project, and almost all the requirements were written in the app main project. There are simply folders divided by business logic, and the businesses are directly called and highly coupled to each other.
- As a result, it was very painful to change the project into componentization in the later stage. There were too many business logic connections between different modules, but there was still no way to do it, so the directory 4 steps were put into practice step by step. The ultimate goal is to move away from the bloated structure and make each business relatively independent, with business components developing independently in component mode.
- How to communicate in componentized mode
- This is the business relationship under the componentized engineering model, the business will no longer refer to and depend on each other directly, but indirectly through a “route” such a relay station. In this open source project, I used the Ali open source routing framework. For more information on the basic use and code analysis of Arouter, see my blog: Arouter Use and Code parsing
3.6 Life Cycle of Service Components
- In terms of the ideal
- There are no dependencies between the business components. At this time, we can treat each independent business component as a running app, so the life cycle of the business component should be consistent with that of the independent app.
3.7 Fragment Communication difficulties
- I see a lot of blogs on the Internet saying how to break components, break them by module, or break them by function. I was surprised at how few references were made to the question of fragmentation of components by fragments.
- First, let’s talk about a business requirement, such as a shopping mall app, which has 4 modules, usually an activity+4 fragments, which we are familiar with. These four modules are: home page, Discovery, shopping cart, mine. Then these pages are written with fragments and share a host activity. So when doing componentization, I want to divide it into the home page according to business, and found that the shopping cart and my four independent business modules.
- Encounter questions:
- If it is divided into four independent business modules, then the corresponding fragment must be placed in the corresponding component, so this operation, when the main project and the business component unbound, how to get the fragment and pass parameters for communication.
- Start an Activity with requestCode in the Fragment. After the started Activity is closed, the onActivityResult in the Fragment will not be called back. Only onActivityResult is called for the Activity where the Fragment is located.
- Multi-fragment single activity interceptor does not work, can only be used to block the activity jump? So if you want to implement login interception, doesn’t it have to be done in the PathReplaceService?
- Network solutions
- The first question: because I use Ali route, so I see zhi1ong big guy said: use Router jump to this Activity, and then take a parameter, such as TAB =2, and then in their own onCreate inside the switch. But then I tried to ask programmers if there was a better way.
- The second question: or Zhi1ong big guy said, through the broadcast, or forward the event in the Activity, for example, let Fragment unified rely on an interface, and then forward in the Activity.
4. Actual development cases
4.1 Open source projects for componentization practices
- A few thoughts on componentized development
- There are many blogs on the web about componentization, explaining what it is, why it is necessary, and the benefits of componentization. Most of the articles provided componentization ideas, which provided a lot of convenience for me to start componentization development. Thanks for sharing! There are some gains, but few articles provide an overall and effective solution, or a concrete Demo.
- But after all, reading blogs is also to prepare for practice. When I started to change the previous open source cases into componentized cases, a lot of problems appeared and some problems were solved. Mainly learned some componentized development process.
- Most companies start componentization development slowly. In small companies, some people try componentization because they have not done componentization development before. In large companies, some people are only responsible for a certain module, and maybe the componentization has already been done at the beginning, so it is faster to learn and practice the componentization. Amateur practice, open source project before revision, writing this blog took a lot of time, if it helped you, then I’m happy. Because I am also a small person, so write of bad, do not spray, welcome to put forward suggestions!
- About componentized open source projects
- The overall architectural pattern of the project is: componentization +MVP+Rx+Retrofit+ Design +Dagger2+VLayout+X5
- Modules included: wanAndroid [Kotlin] + dry goods concentration camp + Zhihu Daily + Tomato Todo+ selected news + Douban music film novel + novel reading + simple notebook + funny video + classic game + more and more
- This project is a part-time practice project, and the interface data are all from the network. If there is any infringement, please inform me immediately. This project is only used for learning and communication. The ownership of API data content belongs to the original company. Do not use it for other purposes.
- Open source componentization project address: github.com/yangchong21…
4.1 How To Create a Module
- It can be known according to 3.3 Architecture design drawings
- The main project:
- It does not contain any business code except for some global configuration and the main Activity. Some, also called shell apps, rely on business components to run.
- Business components:
- At the top level of business, each component represents a complete line of business and is independent of each other. In principle: there should be no direct dependencies between business components! All business components need to be able to operate independently. For testing, when you need to rely on the capabilities of multiple business components for integration testing. You can use the App shell for multi-component dependency management.
- This case is divided into: work concentration camp, playing Android, Zhihu Daily, wechat News, headlines, funny videos, Baidu music, my Notebook, Douban Music reading movies, game components and so on.
- Functional components:
- In this case, there is a sharing component, a comment feedback component, a payment component, a gallery component, and so on. Also note that there may be multiple business components that depend on a functional component!
- Base components:
- Basic business services that support upper-layer business components. These components provide basic functional support for upper-layer service components.
- In this case: in the basic component library are mainly, network request, image loading, communication mechanism, tool class, sharing function, payment function and so on. Of course, I put some public third-party libraries into this base component!
4.2 How Do I Create A Dependency
- The following figure shows the component dependency structure in the project
- Complete configuration code for the service module
// Control the component pattern and integration patternif (rootProject.ext.isGankApplication) { apply plugin: 'com.android.application' } else { apply plugin: 'com.android.library' } android { compileSdkVersion rootProject.ext.android["compileSdkVersion"] buildToolsVersion rootProject.ext.android["buildToolsVersion"] defaultConfig { minSdkVersion rootProject.ext.android["minSdkVersion"] targetSdkVersion rootProject.ext.android["targetSdkVersion"] versionCode rootProject.ext.android["versionCode"] versionName rootProject.ext.android["versionName"] if(rootProject. Ext. IsGankApplication) {/ / component mode setting applicationId applicationId"com.ycbjie.gank" } javaCompileOptions { annotationProcessorOptions { arguments = [AROUTER_MODULE_NAME: project.getName()] } } } buildTypes { release { minifyEnabled false proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'}} // compileOptions {sourceCompatibility JavaVersion.VERSION_1_8 targetCompatibility JavaVersion.VERSION_1_8 } sourceSets { main { if (rootProject.ext.isGankApplication) { manifest.srcFile 'src/main/module/AndroidManifest.xml' } else { manifest.srcFile 'src/main/AndroidManifest.xml' } jniLibs.srcDirs = ['libs'] } } } dependencies { implementation fileTree(dir: 'libs', include: ['*.jar']) implementation project(':library') annotationProcessor rootProject.ext.dependencies["router-compiler"]}Copy the code
4.3 How can I Unify configuration Files
- Since there are many modules in the componentization practice, it is necessary to consider simplifying the work when configuring Gradle and adding dependent libraries. So how do you do that?
- As a first step, create a yc.gradle file in the project root directory. In the actual development, you only need to change the version information in the file.
- The vast majority of cases I see on the Internet are through a switch control component mode and integration mode switch, but here I configure multiple component switches, respectively to control the corresponding component switch state.
ext { isApplication = false //false: exists as a Lib component,true: exists as application isAndroidApplication =false// Play the Android module switch,false: exists as a Lib component,true: exists as application isLoveApplication =false// Love expression module switch,false: exists as a Lib component,true: exists as application isVideoApplication =false// Switch the video module,false: exists as a Lib component,true: exists as application isNoteApplication =false// Switch the notepad module,false: exists as a Lib component,true: exists as application isBookApplication =false// Switch the book module,false: exists as a Lib component,true: exists as application isDouBanApplication =false// Switch the douban module,false: exists as a Lib component,true: Exists as application isGankApplication =false// Dry cargo module switch,false: exists as a Lib component,true: exists as application isMusicApplication =false// Switch the music module,false: exists as a Lib component,true: exists as application isNewsApplication =false// Switch the news module,false: exists as a Lib component,true: isToDoApplication = exists as applicationfalse// Todo module switch,false: exists as a Lib component,true: Exists as application isZhiHuApplication =false// Zhihu module switch,false: exists as a Lib component,true: exists as application isOtherApplication =false// Other module switches,false: exists as a Lib component,true: Exists as application Android = [compileSdkVersion: 28, buildToolsVersion:"28.0.3", minSdkVersion : 17, targetSdkVersion : 28, versionCode : 22, versionName : "1.8.2"// Must be int orfloat, otherwise affect online upgrade] version = [androidSupportSdkVersion:"28.0.0", retrofitSdkVersion : "2.4.0", glideSdkVersion : "4.8.0", canarySdkVersion : "1.5.4", constraintVersion : "1.0.2" ] dependencies = [ //support "appcompat-v7" : "com.android.support:appcompat-v7:${version["androidSupportSdkVersion"]}"."multidex" : "Com. Android. Support: multidex: 1.0.1." ", //network "retrofit" : "com.squareup.retrofit2:retrofit:${version["retrofitSdkVersion"]}"."retrofit-converter-gson" : "com.squareup.retrofit2:converter-gson:${version["retrofitSdkVersion"]}"."retrofit-adapter-rxjava" : "com.squareup.retrofit2:adapter-rxjava2:${version["retrofitSdkVersion"]}"// omit part of the code here]}Copy the code
- Step 2, then add the code to the lib in your project, as shown below
apply plugin: 'com.android.library' android { compileSdkVersion rootProject.ext.android["compileSdkVersion"] buildToolsVersion rootProject.ext.android["buildToolsVersion"] defaultConfig { minSdkVersion rootProject.ext.android["minSdkVersion"] targetSdkVersion rootProject.ext.android["targetSdkVersion"] versionCode rootProject.ext.android["versionCode"] versionName rootProject.ext.android["versionName"] } } dependencies { implementation fileTree(dir: 'libs', include: ['*.jar']) api rootProject.ext.dependencies["appcompat-v7"] api rootProject.ext.dependencies["design"] api rootProject.ext.dependencies["palette"] api rootProject.ext.dependencies["glide"] api (rootProject.ext.dependencies["glide-transformations"]){ exclude module: 'glide' } annotationProcessor rootProject.ext.dependencies["glide-compiler"] api files('libs/tbs_sdk_thirdapp_v3. 2.0. The jar') api "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"// Omit part of the codeCopy the code
- The third step is to add dependencies to the other Models
- Implementation Project (‘:library’) will do.
4.4 Componentized basic libraries
- Basic library component encapsulation
- The basic library component encapsulation library mainly includes some commonly used frameworks for development. Can directly see my project more intuitive!
- Network requests (using Retrofit+RxJava framework), interceptors
- 2. Image loading (strategic mode, switching between Glide and Picasso)
- 3, communication mechanism (RxBus), routing ARouter simple encapsulation tool class (communication between different models)
- 4, MVP framework, commonly used base classes, such as BaseActivity, BaseFragment and so on
- 5, general tool classes, such as cutting rounded corners, animation tools and so on
- 6, custom view(including dialog box, ToolBar layout, circular picture and other view customization)
- 7. Common shape, drawable, Layout, color and other resource files
- 8, global initialization asynchronous thread pool encapsulation library, all components can use
- Component initialization
- For example, if you switch the news component in this case to a standalone app, the news Jump details page needs to use the X5 WebView, so it needs to be initialized. The initial approach is to configure a separate application for each component that can be switched to an APP, and then initialize the tasks that the component needs to initialize. But there’s a little bit of a problem with that, because it’s not very manageable. Later, after seeing the componentization practice scheme of Zhihu, the scheme proposed to develop a set of multi-threaded initialization framework, each component only needs to create several start Task classes, and declare the dependency in the Task. But how to use the code in the later period to achieve!
- How to make it easier for people unfamiliar with componentization to quickly adapt to components running independently
- Set multiple component switches. Change which component you need to switch. If you set a switch that either cuts all the components into integration mode or cuts all the components into component mode, it’s a bit of a problem. Read more below!
- Strictly limit the growth of common base components
- As development progresses, be careful not to add too much to the underlying common components. You have to reduce the volume! If the underlying component is too large, then running the component is slow!
4.5 How can I Switch between the Component Mode and integration Mode
- Build. Gradle file under Android components, similar to other components.
- This is controlled by a switch. If the module is a library, it uses the com.android.library plugin. If it is an application, use the com.android.application plugin
// Control the component pattern and integration patternif (rootProject.ext.isAndroidApplication) { apply plugin: 'com.android.application' } else { apply plugin: 'com.android.library' } Copy the code
- The integration pattern is shown below
- First you need to set isApplication=false in the yc.gradle file. After Sync, the component is found to be library
ext { isAndroidApplication = false //false: exists as a Lib component,true: exists as ApplicationCopy the code
- The component pattern is shown below
- First you need to set isApplication=true in the yc.gradle file. After Sync, the component is found to be Application, and you can run the module
ext { isAndroidApplication = true //false: exists as a Lib component,true: exists as ApplicationCopy the code
- One thing to note, this is very important
- First of all, look at the vast majority of online practices, thank you very much for the selfless dedication of these great gods! I think it’s ok to use one switch for multiple components, but when switching to a component app from sourceSets, you can reuse Java and RES files.
- Here’s how I did it:
- The following configuration is important. When the Android component switches from Library to Application, since it can run as a standalone app, it sets the applicationId and configures the manifest file, as shown below!
- To switch between library and application, the manifest file also needs to provide two sets
android { defaultConfig { if(rootProject. Ext. IsAndroidApplication) {/ / component mode setting applicationId applicationId"com.ycbjie.android"}}sourceSets { main { if (rootProject.ext.isAndroidApplication) { manifest.srcFile 'src/main/module/AndroidManifest.xml' } else { manifest.srcFile 'src/main/AndroidManifest.xml' } jniLibs.srcDirs = ['libs']}}}Copy the code
- The details in the project are shown below
- First of all, look at the vast majority of online practices, thank you very much for the selfless dedication of these great gods! I think it’s ok to use one switch for multiple components, but when switching to a component app from sourceSets, you can reuse Java and RES files.
4.6 Componentization Solve repeated dependencies
- Repeat dependency problem description
- Repeated dependencies happen A lot in development, if your project implements an A, and then you implement A B in the library, and then you implement the same B in your project, and you rely on it twice.
- By default, if it is an AAR dependency, Gradle will automatically find the new version of the library and discard the duplicate dependencies of the old version. However, if you use a project dependency, Gradle will not redo it and you will end up with duplicate classes in your code.
- The solution, for example
api(rootProject.ext.dependencies["logger"]) { exclude module: 'support-v4'// Exclude exclude group from component name:'android.support.v4'// exclude by package name}Copy the code
4.7 Componentization Points
- Linkage between business components causes severe coupling
- For example, in actual development, the shopping cart and the front page items are two components. However, in case of product demand, such as doing an activity on a holiday or issuing shopping vouchers, there are activities in both the shopping cart and the product details page, so the components will often be linked. If this is not done properly, the code boundaries of each line of business will deteriorate over time just like the main project before componentization, and the coupling will get worse and worse.
- The first solution is to use sourceSets to put different business code into different folders, but the problem with sourceSets is that it does not limit the various sourceSets to reference each other, so it is not very friendly!
- The second solution is to extract requirements as tool classes and pass values from different components to achieve the calling relationship. In this way, only the tool classes can be changed to change the requirements. But this is just the same as the requirements, but used in different module scenarios.
- Database separation for componentized development
- For example, the video module I am developing now wants to be used by others. Because the database is needed for caching and so on, do I need to rely on a large third-party database for this lib? But using the system native SQL database is not very convenient, how to do? I haven’t found a way yet…
4.8 Resource Name Conflict during Componentization
- What are the resource name conflicts?
- For example, color, shape, drawable, image resources, layout resources, or anim resources can cause resource name conflicts. Why is this? Sometimes people are responsible for different modules, and if they are not named according to a common specification, this problem will occasionally occur.
- Especially if the string, color, and Dimens resources are distributed in various parts of the code, it is very tedious to dismantle them one by one. You don’t have to do that. Because Android will merge and shrink resources at build time. Res/values under the various documents (styles. Should pay attention to XML) eventually will only be put to use in intermediate/res/merged /.. /valus.xml, the useless will be automatically deleted. And finally we can use Lint to automatically delete. So don’t spend too much time on this place.
- The solution
- This is not a new problem. Third-party SDKS typically encounter this problem and can be avoided by setting resourcePrefix. When this value is set, all of your resource names must be prefixed with the specified string, otherwise an error will be reported. However, the resourcePrefix value can only limit XML resources, not image resources, all image resources still require you to manually change the resource name.
- Personal advice
- Put color, Shape, etc. in the base library component because all business components depend on the base component library. In styles. XML, be sure to prefix property names with qualifiers. If not, there is a possibility that the property name will be repeated when packaged as an AAR and used by other modules. Why? Because the name BezelImageView simply won’t appear in the intermediate/res/merged /.. /valus.xml, so don’t think this is a attribute qualifier!
4.9 Componentized development encountered problems
- How can each componentized module obtain the global context
- Scene reappearance
- For example, if an online project is initially created in the app main project, then the context in the application class of the main project cannot be obtained in the Lib or later partitionalization. This is the time
- The solution
- It’s easy to write a utility class for Utils in Lib and then initialize utils.init (this) in the main project application to get the global context in lib and all business components that already depend on the common base library.
- Scene reappearance
- ButterKnife use problem
- Although there are several blogs on the web that say butterKnife can resolve references between different components. However, during actual development, I encountered a compilation error when switching states between component mode and integration mode. Let me know if that person solves the butterKnife citation problem in componentization, thanks very much!
- When componentization is lib
- Switch (R.I.D.xx) cannot be used. You need to use if.. Else.
- Don’t send bus messages
- If you use A lot of EventBus in your project, you’ll see a class with a lot of onEventMainThread() methods, which are fun to write but painful to read.
- Although it is very convenient and simple to use EventBus or RxBus to send messages to realize the communication between components in the early stage, with the increase of business and the continuous update in the later stage, some of them have been modified by multiple programmers, which will reduce the amount of code reading. There are many places in the project to send this Event, and many places to receive this Event. Later on, when you want to improve your development to componentize and split your code, you don’t dare to do anything in case something is not received.
- The page is displayed incorrectly
- If (isLogin()) {// jump to the page}else{// jump to the login page}, write the same logic for each operation.
- Native startActivity jump, unable to listen to the jump state, such as jump error, success, exception and other problems.
- Later, the background will control from clicking the button [under different scenarios] jump to different pages, if the background configuration information is wrong, or less parameters, then jump may not succeed or cause a crash, this also does not have a good processing mechanism.
- Arouter, an open source framework launched by Ari, can solve the page jump problem, can add interception, or even if the background configuration parameters are wrong, when listening to jump exception or jump error state, can directly default jump to the home page. That’s what I did in the open source case!
- About jump parameters
- Let’s take a look at how this code is written. This code is fine, but in multiplayer development, if someone wants to jump to a page in your development module, it’s easy to pass the wrong value. It’s recommended to write the value of key as a static constant and put it in a special class. Convenient for yourself, also convenient for others.
/ / jump intent. SetClass (this, CommentActivity. Class); intent.putExtra("id",id); intent.putExtra("allNum",allNum); intent.putExtra("shortNum",shortNum); intent.putExtra("longNum",longNum); startActivity(intent); Intent = getIntent(); int allNum = intent.getExtras().getInt("allNum"); int shortNum = intent.getExtras().getInt("shortNum"); int longNum = intent.getExtras().getInt("longNum"); int id = intent.getExtras().getInt("id"); Copy the code
- Let’s take a look at how this code is written. This code is fine, but in multiplayer development, if someone wants to jump to a page in your development module, it’s easy to pass the wrong value. It’s recommended to write the value of key as a static constant and put it in a special class. Convenient for yourself, also convenient for others.
5. Communication between components
5.1 Select the Open source routing library
- The most representative componentized open source framework has been DDComponentForAndroid, ali Arouter, jumei Router and so on.
- Get DDComponentForAndroid: a set of complete and effective android componentization solution, support components of the components of complete isolation, separate debugging, integration debugging, component interaction, UI jump, dynamic loading and unloading functions.
- Ali Arouter: A middleware that provides routing to pages and services. It is simple and useful. There are a lot of introduction blogs on the Internet, and I used this one in this componentization case.
- Router: a routing framework supported by single products, components, and plug-ins
5.2 Basic principles of Arouter
- This is just the basic idea
- The @route annotation added to the code will generate class files that store the mapping between path and activityClass at compile time via apt. The app process will then fetch these class files when it starts and read the mapping data into memory (stored in a map). Then, when a route jump is made, the route address to reach the page is passed in through the build() method.
- Add the @route annotation and compile it to generate the class, and then take a look at the class. As follows:
/** * DO NOT EDIT THIS FILE!!! IT WAS GENERATED BY AROUTER. */ public class ARouter$$Group$$video implements IRouteGroup { @Override public void loadInto(Map<String, RouteMeta> atlas) { atlas.put("/video/VideoActivity", RouteMeta.build(RouteType.ACTIVITY, VideoActivity.class, "/video/videoactivity"."video", null, -1, -2147483648)); }}Copy the code
- Class (activity.class = map.get(path))), and then new Intent(), When calling ARouter’s withString() method, its interior calls intent.putextra (String name, String Value), and navigation(), It jumps internally by calling startActivity(Intent), so that two modules that do not depend on each other can start each other’s activities.
- Look at the _navigation method code in the _ARouter class, line 345.
private Object _navigation(final Context context, final Postcard postcard, final int requestCode, final NavigationCallback callback) { final Context currentContext = null == context ? mContext : context; switch (postcard.getType()) { case ACTIVITY: // Build intent final Intent intent = new Intent(currentContext, postcard.getDestination()); intent.putExtras(postcard.getExtras()); // Set flags. int flags = postcard.getFlags(); if(1! = flags) { intent.setFlags(flags); }else if(! (currentContext instanceof Activity)) { // Non activity, need less one flag. intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); } // Set Actions String action = postcard.getAction();if(! TextUtils.isEmpty(action)) { intent.setAction(action); } // Navigationin main looper. runInMainThread(new Runnable() { @Override public void run() { startActivity(requestCode, currentContext, intent, postcard, callback); }});break; casePROVIDER: // Omit the code herecase BOARDCAST: case CONTENT_PROVIDER: caseFRAGMENT: // Omit the code herecase METHOD: case SERVICE: default: return null; } return null; } Copy the code
- The @route annotation added to the code will generate class files that store the mapping between path and activityClass at compile time via apt. The app process will then fetch these class files when it starts and read the mapping data into memory (stored in a map). Then, when a route jump is made, the route address to reach the page is passed in through the build() method.
5.3 Precautions for using Arouter
- Use Ali route extraction tool class, convenient maintenance!
- So let’s first look at a way to write it on the Internet.
// Add the following code @route (path =)"/test/TestActivity"Public class TestActivity extends BaseActivity {} // jump arouter.getInstance ().inject()"/test/TestActivity"); Copy the code
- The optimized writing
- The following approach is convenient for later maintenance.
Public class ARouterConstant {// Jump to the video page public static final String ACTIVITY_VIDEO_VIDEO ="/video/VideoActivity"; // omit the part of diamagnetic} // Save all route hops, Public class ARouterUtils {/** * @param String String Navigation (string) public static void navigation(string) string){if (string==null){ return; } ARouter.getInstance().build(string).navigation(); }} @route (path = arouterconstant.activity_video_video) public Class VideoActivity extends BaseActivity {} ARouterUtils.navigation(ARouterConstant.ACTIVITY_VIDEO_VIDEO);Copy the code
- So let’s first look at a way to write it on the Internet.
06. About other content
6.1 About blog summary links
- 1. Tech blogs
- 2. Open source project summary
- 3. Lifestyle blogs
- 4. Himalaya audio summary
- 5. Other summaries
6.1 Refer to the blog link
- Android completely modular solution practice: www.jianshu.com/p/1b1d77f58…
- Teach you how to create an Android componentized framework: blog.csdn.net/cdecde111/a…
- Android componentized framework design and practice: www.jianshu.com/p/1c5afe686…
- Zhihu Android client componentization practice: www.jianshu.com/p/f1aeb0369…
- Jumei componentized practice: juejin.cn/post/684490…
- Android componentization – routing design best practices: www.jianshu.com/p/8a3eeeaf0…
6.2 About my blog
- My personal site: www.yczbj.org, www.ycbjie.cn
- Github:github.com/yangchong21…
- Zhihu: www.zhihu.com/people/yang…
- Jane: www.jianshu.com/u/b7b2c6ed9…
- csdn:my.csdn.net/m0_37700275
- The Himalayan listening: www.ximalaya.com/zhubo/71989…
- Source: China my.oschina.net/zbj1618/blo…
- Soak in the days of online: www.jcodecraeer.com/member/cont.
- Email address: [email protected]
- Blog: ali cloud yq.aliyun.com/users/artic… 239.headeruserinfo.3.dT4bcV
- Segmentfault headline: segmentfault.com/u/xiangjian…