美文网首页架构Android技术知识Android开发
Android架构选型(MVP+DataBinding)

Android架构选型(MVP+DataBinding)

作者: free46000 | 来源:发表于2017-02-19 00:23 被阅读1446次

    通过代码对比,详细讲解MVC,MVP,MVVM之间应该如何选择,以及对Android单元测试的探索。本文的侧重点在于如何选择,并没有对每种架构模式概念展开详解(网络上这方面的文章有很多,大家可以自行搜索)。

    大纲

    • MVC or MVP or MVVM?
    • 确定选型:MVP + DataBinding
    • 单元测试(探索阶段)

    目的

    • 提高开发效率
    • 易于测试
    • 拥抱变化
    • 降低维护成本

    Android中的MVC

    示例:

    展示任务详情的功能,详情View层的通过xml来写的,请求数据相关的代码会在Model层提供接口,然后通过Activity对View和Model层进行连接。

    代码:

    M:
    public interface TaskModel {
        void loadTask(String taskId, OnTaskListener listener);
    }
    
    V:
    taskdetail.xml:界面布局文件,采用XML进行描述,属于V层的一部分。
    
    C & V:
    TaskDetailActivity:C层和V层
    public class TaskDetailActivity {
        private void initView() {
            taskModel.loadTask(taskId, new OnTaskListener() {
                public void onSuccess(Task task) {
                    //V层代码,但是目前耦合到了C层            
                    detailTitle.setText(task.getTitle);
                }
            });
        }  
    }
    

    总结:

    • 编写简单快速,适合含有简单逻辑的业务,或是demo程序。
    • Activity的臃肿:xml作为view层,控制能力太弱,无法动态的改变页面的内容,只能把代码写在activity中,造成了activity既是Controller层,又是View层的问题。
    • 耦合度较高,需求变化改动大,后续维护成本高。
    • Controller混杂着Android代码无法Junit。

    Android中的MVP

    示例:

    展示任务详情的功能,详情View层的通过xml和Activity来完成,请求数据相关的代码会在Model层提供接口,然后通过Presenter对View和Model层进行连接。

    代码:

    M:
    public interface TaskModel { 
        void loadTask(String taskId, OnTaskListener listener);
    }
    
    V:
    taskdetail.xml:界面布局文件,采用XML进行描述,属于V层的一部分。
    public class TaskDetailActivity implements TaskDetailView {
        public void showTask(Task task) {
            detailTitle.setText(task.getTitle);
        }  
    }
    
    P:
    public class TaskDetailPresenter implements Presenter {
        public void getTask() {
            taskModel.loadTask(taskId, new OnTaskListener() {
                public void onSuccess(Task task) {
                    //通过接口回调到V层更新UI
                    taskDetailView.showTask(task);
                }
            });
        }  
    }
    

    总结:

    • 减少各层之间耦合,易于后续的需求变化,降低维护成本。
    • Presenter层独立于Android代码之外,可以进行Junit测试。
    • 接口和类较多,互相做回调,代码臃肿。
    • Presenter层与View层是通过接口进行交互的,接口粒度不好控制。

    Android中的MVVM

    示例:

    展示任务详情的功能,详情View层的通过xml和Activity来完成,请求数据相关的代码会在Model层提供接口,然后通过ViewModel对View和Model层进行连接。

    代码:

    M:
    public interface TaskModel  ...
        void loadTask(String taskId, OnTaskListener listener);
    V:
    taskdetail.xml:界面布局文件,采用XML进行描述,绑定规则在xml中进行定义。
    TaskDetailActivity:Activity主要是初始化和补充的功能。
    VM:
    TaskDetailViewModel {
            public void getTask() {
                  taskModel.loadTask(taskId, new OnTaskListener() {
                        public void onSuccess(Task task) {
                            //通过绑定技术更新UI,做到数据独立于UI
                            taskDeatailViewBinding.setTask(task);
                }
                  });
            }  
    }
    

    总结:

    • 和MVP比较像,主要区别在于View和ViewModel / Presenter之间的通信
    • 相比MVP优势是通过DataBinding技术为VM和V层进行数据绑定,提高开发效率,由于目前绑定技术的局限,V层一些界面的处理还是需要Activity的辅助。
    • VM层掺杂Android代码无法进行Junit测试。

    确定选型

    通过以上对比,选择了MVP+DataBinding,此架构模式基于MVP,并使用DataBinding库来显示数据并绑定View。它并不遵循严格的MVVM或MVP模式,因为它同时使用了ViewModel和Presenter。

    DataBinding

    这是我上篇文章我们为什么要使用DataBinding,里面通过代码的对比,总结说明为什么要使用DataBinding的技术,有兴趣的同学可以阅读一下,在这里我把文章里的一小段总结贴出来:

    DataBinding为数据驱动:数据变化后自动更新UI;事件处理:直接找到目标实例处理用户操作的事件。这样我们就不需要和UI或者控件打交道,只需要在java代码中处理业务逻辑就好了,非常清晰,其余的统一交给binding库去完成。降低了代码耦合度,使得数据独立于UI,对以后程序的变化和维护都有积极的影响。

    MVP+DataBinding

    示例:

    展示任务详情的功能,数据和事件绑定与基础MVP代码的对比。

    代码:

    //普通MVP   任务详情代码示例:
    public void onCreateView(...) {
        detailTitle = (TextView) root.findViewById(R.id.task_detail_title);
        detailComplete = (CheckBox) root.findViewById(R.id.task_detail_complete);
        detailComplete.setOnCheckedChangeListener(
               (cb, isChecked) -> presenter.completeChanged(task, isChecked)
        );
    }
    @Override
    public void showDescription(String title) {
        detailTitle.setText(title);
    }
    //xml文件省略...
    
    //MVP+DataBinding   任务详情代码示例:
    @Override
    public void showTask(Task task) {
        viewDataBinding.setTask(task);
    }
    //可以通过布局文件直接绑定到数据模型的属性(xml文件)
    <TextView
        android:id="@+id/task_detail_title"
        android:text="@{task.title}" />
    //事件绑定同样可以直接在布局文件中实现(xml文件)
    <CheckBox
        android:id="@+id/task_detail_complete"
        android:checked="@{task.completed}"
        android:onCheckedChanged="@{(cb, isChecked) -> presenter.completeChanged(task, isChecked)}" />
    

    总结:

    • DataBinding库提高了开发效率,使得xml布局文件用于将数据绑定到UI元素,也可以绑定一个action handler(Presenter)处理用户操作的事件,可以观察和设置数据,以便在需要时自动更新(双向绑定)。
    • 需要对View和Presenter两层做测试,增加工作量。
    • 目前Android Studio对Databing的支持不是太好(报错和代码自动生成)

    单元测试(探索阶段)

    Presenter

    不需要Android环境,因此使用Junit测试即可

    • JUnit:Java语言的单元测试框架
    • Mockito:模拟对象的测试框架

    View

    使用Google建议的Espresso进行UI的测试(需要依赖Android环境)

    • AndroidJUnitRunner:Android 且与 JUnit 4 兼容的测试运行器
    • Espresso:功能性 UI 测试框架

    问题

    就目前实践过程中,会发现需要为测试写一些额外的方法,不是太舒服。并且写两层测试,工作量变大。还有覆盖率以及维护的问题,一直在探索最佳实践,会在以后的文章里面和大家分享。

    本片文章来自于自己的编程实战,写的不好的地方请大家帮忙指正,希望能帮助大家选到合适自己的架构模式。
    谢谢阅读。

    相关文章

      网友评论

      • WangGavin:嗯,activity,presenter,view利用泛型再封装一些基类,就很不错了
        free46000: @newtrek 主要是写写选型,封装基类在实际项目中肯定是需要的,不然mvp会接口泛滥的,哈哈,至于注解和绑定我另一篇文章中也有详细对比,还是更建议绑定的
        WangGavin:但如果View层用了databinding,butterknife就没必要了

      本文标题:Android架构选型(MVP+DataBinding)

      本文链接:https://www.haomeiwen.com/subject/wlurwttx.html