Activity 组件化分发结构

背景

在 Android 应用开发中,我们经常能看到下面的页面:

Activity 组件化分发结构_第1张图片
Activity 组件化分发结构_第2张图片
人人视频

这些页面有以下几个共同特征:

1.一个 Activity 中包含多个子业务(以下称为子模块)。如上面 App 消息页,包含了消息、简信俩个模块;
2.多个子模块之间不存在依赖关系,相互独立即可运行;
3.子模块的生命周期与 Activity 相关联,且不能超过 Activity 的生命周期。

本文探讨的就是如何将上述类型的 Activity 代码组件化、模块化,使其易于阅读、开发、维护。

探索

实际开发中,如果将多个独立的功能代码全部嵌入同一个 Activity 类中,该 Activity 必定会越来越复杂冗余,维护性、可读性也会越来越差。

于是为了解决这个问题,我们可以将一个个独立的功能抽成一个个子模块,在子模块中完成各自的功能;由于子模块之间有其相同特性:比如都需要 context 上下文,都跟随 Activity 生命周期。于是我们将这些相同特性抽出,创建模块抽象类;一个 Activity 的子模块数量是不能保证的,将多个模块交给 Activity 管理显然不合适,为了项目扩展性和可复用性,我们需要一个模块管理类,来有序的创建、初始化、向子模块分发生命周期等等。

这时我们心中大概有如下的组织结构:

Activity 组件化分发结构_第3张图片
初步结构

下面就以 App 消息页面为例,编写组件化代码。

编码

在 App 消息页面,我们将会按如下方式重构,其中除实体 module 与业务相关联外,其它都是无关 Activity 可复用的。建议看完后面代码再回顾下面结构。

Activity 组件化分发结构_第4张图片
结构分析

对于子模块,有至少三个依赖需要外部注入:

1.Activity:上下文对象;
2.ViewGroup:布局对象,决定了子模块在哪里布局;
3.SaveInstanceState:保存状态的对象。

所以首先创建 Bean 类:ModuleContext 来表示一个模块需要的依赖参数合集。

public class ModuleContext {
    private Activity context; //上下文对象
    private Bundle saveInstance; //保存状态的对象
    private SparseArrayCompat viewGroups = new SparseArrayCompat<>();
    
    public Activity getContext() {
        return context;
    }

    public void setContext(Activity context) {
        this.context = context;
    }

    public Bundle getSaveInstance() {
        return saveInstance;
    }

    public void setSaveInstance(Bundle saveInstance) {
        this.saveInstance = saveInstance;
    }

    public SparseArrayCompat getViewGroups() {
        return viewGroups;
    }

    public void setViewGroups(SparseArrayCompat viewGroups) {
        this.viewGroups = viewGroups;
    }
}

ModuleContext 表示一个子模块需要注入的参数,其中 viewGroups 表示该子模块所拥有的所有布局 ViewGroup(一个模块可以有多处布局)。

有了参数,就可以开始创建模块抽象类:AbsModule

AbsModule 作为基类至少要有以下功能:

1.初始化模块功能(上面定义的 ModuleContext 在这里注入)。
2.生命周期触发;
3.保存状态触发;

public abstract class AbsModule {

    //初始化将AbsModule的参数传入
    public abstract void init(ModuleContext moduleContext);

    public abstract void onSaveInstanceState(Bundle outState);

    public abstract void onResume();

    public abstract void onPause();

    public abstract void onStop();

    public abstract void onOrientationChanges(boolean isLandscape);

    public abstract void onDestroy();
}

模块管理类将会对其下所有的模块 AbsModule 执行初始化、生命周期分发等。这里为了扩展性,模块管理类将派生出以下俩个类:

ModuleManager:抽象管理类,仅做模块的相关方法分发;

public class ModuleManager {
    private List modules = new ArrayList<>(); //模块类全限定名
    protected HashMap allModules = new HashMap<>(); //模块实体

    public List getModuleNames() {
        return modules;
    }

    public void moduleConfig(List modules) {
        this.modules = modules;
    }

    public AbsModule getModuleByName(String name) {
        if (!allModules.isEmpty()) {
            return allModules.get(name);
        }
        return null;
    }

    public void onResume() {
        for (AbsModule module : allModules.values()) {
            if (module != null) {
                module.onResume();
            }
        }
    }

    public void onPause() {
        for (AbsModule module : allModules.values()) {
            if (module != null) {
                module.onPause();
            }
        }
    }

    public void onStop() {
        for (AbsModule module : allModules.values()) {
            if (module != null) {
                module.onStop();
            }
        }
    }

    public void onDestroy() {
        for (AbsModule module : allModules.values()) {
            if (module != null) {
                module.onDestroy();
            }
        }
    }

    public void onConfigurationChanged(Configuration newConfig) {
        for (AbsModule module : allModules.values()) {
            if (module != null) {
                module.onOrientationChanges(newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE);
            }
        }
    }
}

ActivityModuleManager:Activity 模块管理类,负责模块的初始化,然后将初始化成功的模块交给父类 ModuleManager 进行相关方法分发。

ActivityModuleManager 一共完成了如下功能:

1.创建指定模块;
2.指定模块依赖注入;
3.初始化指定模块;
4.纳入方法分发管理。

简单来说一句话,模块依次初始化。

public class ActivityModuleManager extends ModuleManager {

    public void initModules(Bundle saveInstance, Activity activity, HashMap> modules) {
        if (activity == null || modules == null) {
            return;
        }
        //配置Activity下的所有module全限定名 后续可以根据名称还原module实体(实体才包含ViewGroup、Activity等参数)
        moduleConfig(new ArrayList<>(modules.keySet()));
        //依次给所有module初始化:1.创建实体 2.传递参数 3.调用初始化 4.纳入生命周期管理
        for (String moduleName : modules.keySet()) {
            //创建对应module
            AbsModule module = ModuleFactory.newModuleInstance(moduleName);
            if (module != null) {
                //创建参数
                ModuleContext moduleContext = new ModuleContext();
                moduleContext.setContext(activity);
                moduleContext.setSaveInstance(saveInstance);
                SparseArrayCompat viewGroups = new SparseArrayCompat<>();
                ArrayList mViewIds = modules.get(moduleName);
                if (mViewIds != null && mViewIds.size() > 0) {
                    for (int i = 0; i < mViewIds.size(); i++) {
                        viewGroups.put(i, (ViewGroup) activity.findViewById(mViewIds.get(i)));
                    }
                }
                moduleContext.setViewGroups(viewGroups);
                //调用初始化(参数传递)
                module.init(moduleContext);
                //纳入管理
                allModules.put(moduleName, module);
            }
        }
    }
}

上面类使用了 ModuleFactory 创建实体模块,其实现如下:

public class ModuleFactory {

    //反射初始化对应module
    public static AbsModule newModuleInstance(String moduleName) {
        if (TextUtils.isEmpty(moduleName)) {
            return null;
        }
        try {
            Class moduleClzz = (Class) Class.forName(moduleName);
            return moduleClzz.newInstance();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        }
        return null;
    }
}

使用反射获取实体对象的意义主要在于 ModuleFactory 可以不依赖具体模块,在组件化编程中,ModuleFactory 作为 Base 模块的一员不依赖任何功能模块的类非常必要。

现在,模块管理类和模块已经有了关联关系,下面只需要通过 Activity 分发事件到 ActivityModuleManager,进而就可以分发到子模块中。这样就可以专注子模块的功能开发,事件分发全权交给模块管理类。

创建 Activity 的抽象类 ModuleManagerActivity,负责与模块管理类通信:

public abstract class ModuleManagerActivity extends Activity {

    private ActivityModuleManager moduleManager;

    @Override
    protected void onCreate(final Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        //布局 onLayout 时初始化
        ViewTreeObserver viewTreeObserver = getWindow().getDecorView().getRootView().getViewTreeObserver();
        if (android.os.Build.VERSION.SDK_INT > Build.VERSION_CODES.JELLY_BEAN_MR2) {
            viewTreeObserver.addOnWindowAttachListener(new ViewTreeObserver.OnWindowAttachListener() {
                @Override
                public void onWindowAttached() {
                    if (moduleManager == null) {
                        initModuleManager(savedInstanceState);
                    }
                }

                @Override
                public void onWindowDetached() {

                }
            });
        } else {
            viewTreeObserver.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
                @Override
                public void onGlobalLayout() {
                    if (moduleManager == null) {
                        initModuleManager(savedInstanceState);
                    }
                }
            });
        }
    }

    private void initModuleManager(Bundle saveInstance) {
        moduleManager = new ActivityModuleManager();
        moduleManager.initModules(saveInstance, this, moduleConfig());
    }

    public abstract HashMap> moduleConfig();

    @Override
    protected void onResume() {
        super.onResume();
        if (moduleManager != null){
            moduleManager.onResume();
        }
    }

    @Override
    protected void onStop() {
        super.onStop();
        if (moduleManager != null){
            moduleManager.onStop();
        }
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        if (moduleManager != null){
            moduleManager.onDestroy();
        }
    }

    @Override
    public void onConfigurationChanged(Configuration newConfig) {
        super.onConfigurationChanged(newConfig);
        if (moduleManager != null){
            moduleManager.onConfigurationChanged(newConfig);
        }
    }
}

至此组件化分发结构代码开发完毕,下面开始测试实践。

测试

创建一个简单的模块类 BodyAModule(可以当作模拟上面 App 简信模块,在这里编写业务代码)

public class BodyAModule extends AbsModule {

    private Activity activity;
    private ViewGroup parentViewGroup;

    @Override
    public void init(ModuleContext moduleContext) {
        activity = moduleContext.getContext();
        parentViewGroup = moduleContext.getViewGroups().get(0);
        initView();
    }

    private void initView() {
        LayoutInflater.from(activity).inflate(R.layout.content_body_a, parentViewGroup, true);
    }

    @Override
    public void onSaveInstanceState(Bundle outState) {

    }

    @Override
    public void onResume() {

    }

    @Override
    public void onPause() {

    }

    @Override
    public void onStop() {

    }

    @Override
    public void onOrientationChanges(boolean isLandscape) {

    }

    @Override
    public void onDestroy() {

    }
}

布局也很简单:



    

同理创建 BodyBModule

MainActivity 继承自 ModuleManagerActivity,并引入 BodyAModuleBodyBModule

public class MainActivity extends ModuleManagerActivity {

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

    @Override
    public HashMap> moduleConfig() {
        HashMap> map = new HashMap<>();
        map.put(PageConfig.BODY_A, new ArrayList() {{
            add(R.id.al_fl_bodyA);
        }});
        map.put(PageConfig.BODY_B, new ArrayList() {{
            add(R.id.al_fl_bodyB);
        }});
        return map;
    }
}

其中 PageConfig 仅为方便管理模块类,代码如下:

public class PageConfig {

public class PageConfig {

    public static final String BODY_A = "com.example.activitysend.BodyAModule";
    public static final String BODY_B = "com.example.activitysend.BodyBModule";
}

MainActivity 布局如下:



    

    


这样就将布局与实体 module 类关联了起来,实际运行效果如下图:

Activity 组件化分发结构_第5张图片
效果

总结

上面示例中的模块划分清晰易懂,Activity、module 简洁明了、功能专一,在阅读、开发、扩展上都大有益处。

组件化分发结构的思想是将功能模块化分割,分割后的多模块负责业务,由专门的管理类维护生命周期。而 Activity 或其他类则负责与管理类进行生命周期的分发交互,完全隔离业务处理。

上面的代码参考自 一书,我做了修正和部分修改。实际开发中,我确实也有将功能模块化、然后创建 Manager 进行管理、Activity 与 Manager 交互的编码习惯,但是我有个严重的编码误区:Activity 直接通过控制 Manager 执行相关模块的一些业务方法,而不是通过生命周期控制、让模块自身独立完成业务功能,这样是不对的,需要反思。

举个栗子,电商 App,在支付完成之后,刷新购物车页面数据。错误编码可能是,EventBus 触发购物车 Activity 调用该页的 Manager 执行刷新对应模块数据的方法。但是在组件化分发结构上,Activity 只负责模块的生命控制,如初始化、生命周期分发,不负责任何相关模块的业务功能,所以正确的做法是,Activity 什么都不做,EventBus 直接在相关模块中注册,由相关模块直接接收 EventBus 事件并处理。

区别在于,误区 “Activity 通过控制 Manager 执行相关模块的业务方法” 本质只是对功能的封装,不是分割。封装的结果会保留调用入口供其它类使用,分割在于尽可能的完全解耦,将逻辑从 Activity 或其他地方剥离,业务功能上完完全全自我掌控、自我维护,Activity 不调用也不参与。

可以理解为将一个 Activity 分解成了无数小 activity,这些小 activity 只接收生命周期管理,而业务上完全自我维护,不受原本 Activity 的任何管制。

上述组件化分发架构就是分割的良好体现,通过生命周期分发控制,实现业务代码的完全剥离。

以上仅为个人理解。

你可能感兴趣的:(Activity 组件化分发结构)