MVC、MVP、MVVM的选择

一开始我们在这几种框架上的选择上就没花太多的心思,因为他们都只是为了实现清晰的分层逻辑,差异化的地方无非是讲UI逻辑、交互逻辑、数据绑定逻辑、业务逻辑堆放在那一层的问题。UI逻辑我们定义为UI控件长什么样,放在那里的逻辑。交互逻辑指的是跟用户互动所需要的逻辑。数据绑定逻辑指数据怎么呈现在界面上的逻辑。业务逻辑指的是因为当前业务不同,跟UI无关的一些程序控制逻辑。

只是看起来很美好的MVC

Live1.0架构上看,MVC的架构能够帮助我们进行良好的分层。Activity(或者Fragment)承担了粘合剂的作用,数据请求后的结果也放在里面。控件的交互交互逻辑虽然收敛在对应的Controller里面了,但是Controller之间的交互逻辑需要放在Fragment中,通过Fragment来调用其他Controller的接口。Live业务是一个典型的业务逻辑简单,UI逻辑、交互逻辑多的场景。各种控件之间的交互很频繁,很快的作为粘合剂的Fragment就不可控地膨胀到2000多行。这时候,添加新的功能或者做修改已有的功能,已经显得很吃力,特别各个组件中因为数据、状态而耦合在一起。在交互复杂的情况下,Activity中因为组件交互的接口越开越多,另外接口也有自己特定的业务名称,除了作者别人改动起来很吃力。这时候,我们又意识到交互逻辑必须要细分为组件自身的交互逻辑,以及组件之间的交互逻辑。

另一方面,粘合剂Fragment中装载的数据是几乎每一个Controller都需要的,往往就在初始化的时候将数据注入进Controller中,来完成数据绑定的逻辑。一不小心,数据绑定的逻辑就从Controller中跑到Fragment了。

开发流程

Live1.0架构中,开发一个组件,需要实现View、Controller、Model,另外Controller还需要在粘合剂Fragment中找到对应的回调实现响应的逻辑,跟其他组件互动的部分需要持有其他组建的View(或Controller).

Live2.0架构

Live2.0架构主要想解决三个问题:

  • 每个组件能够独立地变化,状态可以被收敛在组件中。
  • 用最少量的、统一的接口来解耦组件间的交互,数据的绑定。
  • 交互逻辑、数据请求、业务逻辑、UI逻辑可以复用。

模块化

很自然地,我们就想到可以通过模块化、事件通知机制来解决以上的问题。关键的问题在于如何解决Acitivity中存在大量粘合剂代码。传统的MVC框架只解决了分层的问题,并没有指明模块化的方式。另外我们希望模块化不要造成使用上的难度,接口应该统一、简单易学。玩弄过Google官方出的架构Demo,然而他View、Present的接口也是强业务相关的,并不能实现接口的统一化。

我们最后构想的方案是:既然所有的View在onCreateView的时候都要绑定特定的交互逻辑,onDestroy的时候都要进行销毁,那么每个Controller中实现Fragment的生命周期函数回调就是一件很自然的事情。所以最终的解决方案是Fragment只做生命周期函数的分发,所有的Controller实现Fragment的生命周期回调。

调整后,Fragment彻底变成一个生命周期分发的空壳,每一个View对应一个ViewController,View的绑定交互逻辑、交互逻辑都单独地在Controller中变化.

public class TMVerticalVideoFragment extends Fragment{

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        mRootView = View.inflate(this.getActivity(), R.layout.fragment_vertical, null);
        for (LiveFragmentInterface item :
                mViewControllerInterfaceMap.values()) {
            item.onCreateView(inflater, container, savedInstanceState);
        }
        return mRootView;
    }

    @Override
    public void onPause() {
        for (LiveFragmentInterface item :
                mViewControllerInterfaceMap.values()) {
            item.onPause();
        }
        super.onPause();
    }

    //省略onViewCreated()、onStop()、onResume()等一大波生命周期函数...

    @Override
    public void onDestroy() {
        super.onDestroy();
        for (LiveFragmentInterface item :
                mViewControllerInterfaceMap.values()) {
            item.onDestroy();
        }
    }
}

事件分发

之前提到,Live业务的各个组件间的交互逻辑频繁(注意:这里说的不是组件自身的交互逻辑,而是组件与组件间因自身状态变化,而需要控制其他组件同时进行变化的组件间交互。我数了一下一共有26种组件间交互)。显然,这些交互逻辑并不复杂,但是常变。使用事件分发就是最好的选择,接口就不允许常常变化。因此我们实现了简单的事件总线来解耦组件间的交互。

数据绑定

Live业务的数据只依赖少量的Mtop接口,但是这些数据却需要共享给各个组件。我们希望每个组件不要关注数据请求的细节,在数据来的时候,只关注自己需要的数据。另外,Live业务有多个数据源(N个Mtop、配置中心数据、PowerMessage).然而并不是所有的组件都需要关注这么些数据。

解决方案:我们认为数据的请求和处理过程同用户的交互一样,是一种特殊的交互逻辑,数据请求的成功与失败回调也是一种事件通知。数据的绑定固化成特定的接口,对数据感兴趣的Controller只需要实现对应的数据接口,就可以接收到对应的数据。所有Controller中数据绑定的逻辑也固化在特定的数据回调接口中。

/**
 * MinSk数据读取Controller
 * Created by kaihuan on 16/8/18.
 */
public class MinSkConfigurationController implements LiveFragmentInterface {
    public static final String TAG = "live.MinSkConfigurationController";
    protected IGetController mFragment;

    @Override
    public void onCreate(@Nullable Bundle savedInstanceState) {
        JSONObject refreshConfigJson = TMConfigCenterManager.getInstance().getConfigDataObject(getConfigName());
        if (refreshConfigJson ==null ){
            return;
        }

        //分发数据
        Map<String, LiveFragmentInterface> viewControllerInterfaceMap = mFragment.getViewControllerInterfaceMap();
        if (viewControllerInterfaceMap != null) {
            for (LiveFragmentInterface item : viewControllerInterfaceMap.values()) {
                if (item != null && item instanceof IMinskDataListener) {
                    ((IMinskDataListener) item).onMinskData(getConfigName(),refreshConfigJson);
                }
            }
        }
    }

    @NonNull
    protected String getConfigName() {
        return LiveVerticalConstants.MINSK_CONFIG_KEY;
    }
        // 省略一大波生命周期回到函数..

    @Override
    public void onFragemntCreated(Fragment fragment) {
        this.mFragment = (IGetController) fragment;
    }

}

开发流程

Live2.0架构中,开发一个特定的组件就只需要实现自己的View、Controller、Model,在自己的Fragment生命周期回调、数据回调中实现自己的逻辑、改变自己的状态。对组件中需要联动的部分,只需要发送事件通知别人改变。

从切身的体会来说,Live2.0架构简化了开发成本,在View产生的方法,在特定的回到生命周期回调函数中只专心地做自己业务相关的部分,而不需要考虑别人的状态变化。在开发过程中,甚至都见不到别人一丝丝的代码.

双十一我们需要实现三个不同的Live间,由于逻辑的切割足够细,代码方面近乎达到100%的复用。对开发、测试同学来说,工作量至少减少2~3倍。

android的Live架构的更多相关文章

  1. [转]Android App整体架构设计的思考

    1. 架构设计的目的 对程序进行架构设计的原因,归根到底是为了提高生产力.通过设计使程序模块化,做到模块内部的高聚合和模块之间的低耦合.这样做的好处是使得程序在开发的过程中,开发人员只需要专注于一点, ...

  2. Android入门(二):Android的系统架构

    android的系统架构和其操作系统一样,采用了分层的架构.从架构图看,android分为四个层,从高层到低层分别是应用程序层.应用程序框架层.系统运行库层和linux核心层.   从技术方面看,An ...

  3. Android系统的架构

    android的系统架构和其操作系统一样,采用了分层的架构.从架构图看,android分为四个层,从高层到低层分别是应用程序层.应用程序框架层.系统运行库层和linux核心层. 1.应用程序 Andr ...

  4. fir.im Weekly - iOS/Android 应用程序架构解析

    假如问你一个iOS or Android app的架构,你会从哪些方面来说呢? 本期 fir.im Weekly 收集了关于  iOS/Android 开发资源,也加入了一些关于 Web 前端方面的分 ...

  5. Android 控件架构及View、ViewGroup的测量

    附录:示例代码地址 控件在Android开发的过程中是必不可少的,无论是我们在使用系统控件还是自定义的控件.下面我们将讲解一下Android的控件架构,以及如何实现自定义控件. 1.Android控件 ...

  6. Android 的系统架构

    Android 的系统架构 Android其本质就是在标准的Linux系统上增加了Java虚拟机Dalvik,并在Dalvik虚拟机上搭建了一个JAVA的application framework,所 ...

  7. Android App的架构设计:从VM、MVC、MVP到MVVM

    随着Android应用开发规模的扩大,客户端业务逻辑也越来越复杂,已然不是简单的数据展示了.如同后端开发遇到瓶颈时采用的组件拆分思想,客户端也需要进行架构设计,拆分视图和数据,解除模块之间的耦合,提高 ...

  8. Android系统四层架构分享

    Android系统四层架构 个人网站:http://www.51pansou.com Android视频下载:Android视频 Android源码下载:Android源码 如果把Android系统看 ...

  9. Android的系统架构

    转自Android的系统架构 从上图中可以看出,Android系统架构为四层结构,从上层到下层分别是应用程序层.应用程序框架层.系统运行库层以及Linux内核层,分别介绍如下:     1)应用程序层 ...

  10. 实时Android语音对讲系统架构

    本文属于Android局域网内的语音对讲项目系列,<通过UDP广播实现Android局域网Peer Discovering>实现了局域网内的广播及多播通信,本文将重点说明系统架构,音频信号 ...

随机推荐

  1. centos7+ansible自动化工具使用

    一.基础介绍 ========================================================================================== 1. ...

  2. Date对象和正则对象

    1.Date对象 创建 var date1 = new Date(); var date2 = new Date(12983798123);//填一个毫秒值,应该是距离1970年1月1日.....多少 ...

  3. python 字典操作方法详解

    字典是一种通过名字或者关键字引用的得数据结构,key 类型需要时被哈希,其键可以是数字.字符串.元组,这种结构类型也称之为映射.字典类型是Python中唯一內建的映射类型. 注意,浮点数比较很不精确, ...

  4. Spring 当 @PathVariable 遇上 【. # /】等特殊字符

    @PathVariable注解应该不是新鲜东西了Spring3.0就开始有了 URL中通过加占位符把参数传向后台 举个栗子,如下比较要说的内容比较简单就大概齐的写一下 画面侧 $.ajax({ typ ...

  5. ------- 软件调试——还原 QQ 过滤驱动对关键内核设施所做的修改 -------

    -------------------------------------------------------------------------------- 在前一篇博文中,我们已经处理完最棘手的 ...

  6. ubuntu+mono+PetaPoco+Oracle+.net 程序部署

    前言:将windows 下开发的 .net 控制台程序(连接Oracle数据库)部署到 ubuntu 下步骤记录  2017-09-19 实验所用机器为虚拟机Ubuntu16.04  amd64 安装 ...

  7. Facebook发布React 16 专利条款改为MIT开源协议

    9 月 26 日,用于构建 UI 的 JavaScript 库 React 16 的最新版本上线. Facebook 最终在现有的两种 React 版本中选择了出现 bug 概率最少的一款.这次版本更 ...

  8. 生成模型(generative model)与判别模型(discriminative model)的区别

    监督学习可以分为生成方法与判别方法,所学到的模型可以分为生成模型与判别模型. 生成模型 生成模型由数据学习联合概率分布\(P(X,Y)\),然后求出条件概率分布\(P(Y|X)\)作为预测的模型,即生 ...

  9. Maven中避开测试环节

    两种方法 修改pom文件 添加<skipTests>true</skipTests>标签 <plugin> <groupId>org.apache.ma ...

  10. [SCOI2009][bzoj1025]游戏

    [SCOI2009][bzoj1025]游戏 标签: DP 置换 题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=1025 题解 很套路的题目 ...