android电商组件化设计(含源码):MVP+dagger+组件化

起源

在采用组件化之前,我负责的一个电商项目经历了1.0单模块版本、2.0多模块版本,3.0决定采用组件化来重构项目,并将项目开源,可供同样在做电商的android开发者参考、在研究android架构的同行者共同学习进步。在做之前,我们考虑三个问题,what、why和how,什么是组件化?为什么要进行组件化?如何进行组件化?
该电商项目源码请点击

什么是组件化

组件化是指解耦复杂系统时将多个功能模块拆分、重组的过程。在Android工程表现上就是把app按照其业务的不同,划分为不同的Module,每个Module可独立作为一个app运行,也可作为整个app的子模块。

为什么要进行组件化

  1. 为了解耦:把复杂系统拆分成多个组件,分离组件边界和责任,便于独立升级和维护
  2. 各个组件专注自身功能的实现,模块中代码高度聚合,只负责一项任务,也就是常说的单一职责原则;
  3. 各业务研发可以互不干扰、提高协作效率;
  4. 业务组件可进行拔插,灵活多变;
  5. 业务组件之间将不再直接引用和依赖,各个业务模块组件更加独立,降低耦合;
  6. 加快编译速度,提高开发效率

android如何进行组件化

  1. 在gradle.properties文件中增加常量:isModule=false
  2. 在各个组件模块的gradle中增加是否是组件的动态配置
if (isModule.toBoolean()) {
    apply plugin: 'com.android.application'
} else {
    apply plugin: 'com.android.library'
}
  1. 如果需要独立模块运行,则将gradle.properties中的isModule置为true,否则置为false,修改后rebuild一下;当然这样只是简单实现了组件的自动拆分和重组,更详细的实现请继续往下看

电商项目组件化之路

根据电商项目的业务特点,我们设计了如下架构图
android电商组件化设计(含源码):MVP+dagger+组件化_第1张图片
从下往上来看,依次是通用组件、业务组件、业务模块、APP壳四大层。

  1. 通用组件,又称业务无关组件,根据来源分为开源库和基础组件库,开源库是我们在项目中经常会用到的第三方库,比如okhttp、rxJava等,基础组件库是我们自己定义的和业务无关的组件,主要包括BaseMvp、工具类、自定义的Widget、http等
  • common_http: http通信组件
  1. 业务组件,和业务相关的组件
  • lib_push: 推送组件,负责推送服务
  • lib_share: 第三方分享
  • lib_im: 即时聊天的服务
  • lib_webview: 独立进程webview,用于和h5之间进行交互
  1. 业务模块,根据业务的联系紧密程度来拆分
  • module_main: 首页模块,包括启动页、欢迎页、首页等;
  • module_goods: 商品模块,包括商品分类、商品详情、商品搜索等;
  • module_user: 用户模块,包括个人中心、登录等;
  • module_order:订单模块,包括订单确认、订单列表等;
  • module_msg: 消息模块,包括客服消息等;
  1. APP壳,是app的入口模块,包括manifest配置、加载各个模块、打包配置等,基于应用安全考虑,通过调用C层的加密方法将业务模块加密

组件化间通信

同级组件间,因为没有相互依赖关系,所以不能相互调用,那么我们就遇到了通信的问题,如何来解决组件间通信,目前开源的有多种方案可以选择,用的最普遍的是阿里的ARouter,这里我们选择ARouter来解决我们的通信问题。

为了使我们的设计具有更强的灵活性和易用性,我们新增 lib_router 模块来对 arouter 做一层包装。

使用举例:在router模块中定义UserIntent.startLoginActivity,在各个组件中可直接调用

public class UserIntent {
	public static void startLoginActivity() {
        ModuleRouter.newInstance(USER_PROFILE_LOGIN_ACTIVITY).navigation();
    }
}
//任意组件中使用
UserIntent.startLoginActivity();

第三方可选择方案

各个方案比较请点击

  1. 阿里的ARouter
  2. CC
  3. ActivityRouter

组件初始化

  1. 在common层定义接口 IApplication
public interface IApplication {
    void onCreate(Application application);
}
  1. 在各个组件中实现该接口
public class UserApplication implements IApplication {
	public static  Application sApp = null;
    @Override
    public void onCreate(Application application) {
        sApp = application;
        // to do init
    }
}
  1. 在common中新增类ModuleConfig,用来存储各个组件的application路径
public class ModuleConfig {
    public static final String[] MODULE_LIST=
            {
              "com.jackting.module_goods.GoodsApplication",
              "com.jackting.module_user.UserApplication",
            };
}
  1. 在CommonApplication中加载各个组件的application
public class CommonApplication extends Application {
    public void onCreate() {
    	modulesApplicationInit();
    }
    private void modulesApplicationInit(){
        for (String moduleImpl : ModuleConfig.MODULE_LIST){
            try {
                Class clazz = Class.forName(moduleImpl);
                Object obj = clazz.newInstance();
                if (obj instanceof IApplication){
                    ((IApplication) obj).onCreate(this);
                }
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            } catch (InstantiationException e) {
                e.printStackTrace();
            }
        }
    }
}

组件的gradle配置

  1. 资源命名前缀定义:为了防止不同组件间资源命名重复问题,我们对各个组件定义不同的命名前缀,这样不同组件间的资源命名便一定不会重复
resourcePrefix "user_"
  1. 整个项目一起运行和组件单独运行时,AndroidManifest文件中四大组件的配置一定是不同的(比如启动activity的配置),所以两种模式要使用不同的manifest文件
sourceSets{
        main{
            if(isModule.toBoolean()){
                manifest.srcFile 'src/main/debug/AndroidManifest.xml'
            } else {
                manifest.srcFile 'src/main/release/AndroidManifest.xml'
                java{
                    //全部module一起编译的时候剔除debug目录
                    exclude '**/**/debug/**'
                }
            }
        }
    }

MVP+dagger的引入

常用的开发模式有MVC、MVP和MVVM三种,mvc中acitvity太重,model层和view层耦合性太强,mvvm做了双向绑定,但是xml不能复用、调试问题极其不方便,个人对MVP是情有独钟,虽然类会多一点,但是代码结构清晰,便于管理和维护。

dagger2的使用有两种,一种和android平台有关,使用更方便,但是对项目的侵入性很强,不能和组件化结合使用,另一种和android平台无关,但是可以和组件化结合使用,于是我们选择了后者。

  • dagger2的引入
  1. 在CommonApplication定义AppComponent
public class CommonApplication extends Application {
	private static AppComponent appComponent;
	private void initInjector(){
        appComponent = DaggerAppComponent.builder()
                .appModule(new AppModule(sApplication))
                .build();
    }
    public static AppComponent getAppComponent() {
        return appComponent;
    }
}
  1. 在Component在增加注入配置
void inject(XxxActivity activity);
  1. 在activity中初始化注入
DaggerUserComponent.builder()
                .appComponent(getAppComponent())
                .build()
                .inject(this);

butterknife在组件化中的使用

  1. 在项目根目录下的build.gradle中增加classpath
dependencies {
	classpath 'com.jakewharton:butterknife-gradle-plugin:10.1.0'
}
  1. 在各个组件/模块中增加插件配置
apply plugin: 'com.jakewharton.butterknife'
  1. activity/fragment中使用,使用R2,而非R
@BindView(R2.id.et_user_login_username)
EditText etName;

@OnClick({R2.id.btn_login})
public void doClick(View view){
	int id = view.getId();
    if (id == R.id.btn_login) {
    }
}

参考

  1. 知乎 Android 客户端组件化实践
  2. 浅谈项目架构重构之路——组件化与MVP
  3. 架构师的思维,聊一聊APP组件化的那些事儿 备用
  4. WanAndroid架构源码
  5. 仿京东app
  6. MVPArms

联系我们

你可能感兴趣的:(android,架构,组件化)