MVC、MVP、MVVM的选择

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

只是看起来很美好的MVC

android LiveEventBus使用 安卓live_数据

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逻辑可以复用。

android LiveEventBus使用 安卓live_数据_02

模块化

很自然地,我们就想到可以通过模块化、事件通知机制来解决以上的问题。关键的问题在于如何解决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倍。