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...