关于Android MVP模式的思考

Posted _houzhi

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了关于Android MVP模式的思考相关的知识,希望对你有一定的参考价值。

最近经常看到各种介绍MVP模式的博客的,之前写过不少的android应用,在做那些应用的时候,都是要求快速完成,所以从开始设计到写代码就一直考虑着重用。以前写的项目基本都是不断重构项目,将项目代码变得更加精简,提高代码之间的复用性。但是代码并没有特别地注重按照MVC模式或者是MVP模式来,更多的是直接考虑模块化,重用,精简。所以看了MVP模式后,决定去总结一下自己代码中的问题并优化,算是对自己之前写的代码的回顾。

MVP框架

MVP框架是目前在Android流行起来的框架,它非常适合用于Android开发上面。我最早接触MVP模式是在一本敏捷开发的书上。MVP分别指代M(model),V(View),P(Presenter):

  • M(Model):表示数据模型,以及相关的数据结构。
  • V(View):表示视图,主要是指UI界面相关的那些东西。在Android里面比如说layout的xml文件,在MVP中,很多时候Activity/Fragment也是被看做View。
  • P(Presenter):可以直接理解为视图与模型的中间纽带。

在MVP模式中,Model和View不直接进行关联,而是通过Presenter来进行关联的。往往实现的方式是增加一个IModel接口和IView接口,用Model和View分别实现那两个接口,Presenter里面保存IModel和IView接口类型的成员变量。

代码示例

下面举一个关于Android用户信息的MVP模式例子。

public interface IUserView
void setName(String name);

用户的JavaBean—User:

class User
    private String name;
    private String id;
    public String getName()
        return name;
    
    public String getId()
        return id;
    
    
    public void setName(String name)
        this.name = name;
    
    public void setId(String id)
        this.id = id;
    

用户模型接口

public interface IUserModel
void saveUser(User user);
User load();

真正模型

public class UserModel implements IUserModel
    void saveUser(User user)
        // 保存用户信息,保存在本地数据库中,或者xml里面
    
    User loadUser()
        // 从网络中,或者从本地缓存中读取用户信息
        return null; //未实现
    

Presenter:

public class UserPresenter
    private IUserView view;
    private IUserModel userModel;
    public UserPresenter(IUserView view)
        this.view = view;
        userModel = new UserModel();
    
    public void loadUser()
        // 此处可能是异步load
        User user = userModel.loadUser();
        view.setName(user.getName());
    

把Activity作为View来看待

public class UserActivity extends Activity implements IUserView
    TextView tvName; //名称对应的TextView
    UserPresenter userPresenter ;
    public void onCreate(Bundle bundle)
        ...
        userPresenter = new UserPresenter(this);
        // userPresenter.loadUser(); 可以有先初始化
    
    
    void setName(String name)
        tvName.setText(name); //如果presenter的loadUser是异步线程,这里可以通过tvName.post来运行在UI线程。
    
    
    void reloadUserData() //该函数可以某个按钮的onClick事件里面调用
        userPresenter.loadUser(); // 可以是从网络中加载数据
    

上面代码中Activity不再与Model直接关联,而是通过Presenter来间接关联Model。并且当Model的数据变化了的时候,Presenter能够通知View。上面的例子是View需要变化了,请求Presenter获取数据。

分析

MVP与MVC最大的不同就是View和Model不再直接关联。很多Android的MVC模式都是直接将Activity看作Control,这会导致整个Activity非常臃肿,因为它既然进行UI交互,还需要加上Control这部分的功能。另外即使另外新建一个Control,而把Activity只当做View的功能,如果Activity还是直接跟Model直接关联的话,因为跟Model直接关联,还是会在Activity增加很多操作。而使用P作为Model和View的纽带,P可以先对模型数据进行一些处理,然后再显示到View。另外一方面对于View的一些请求,Presenter也可以进行一些处理再去请求Model。

上面是关于代码方面的优势,其实通过分隔开Model和View,也是将各个模块进行了解耦。另外一方面通过增加IUserView和IUserModel,这样每个部分进行单元测试也更加方便了,比如可以直接实现IUserView来模拟测试Presenter。

个人觉得MVP模式适合Android应用,一个很大的原因就是Activity这种组件的存在,UI交互完全放在了Activity里面,这导致很多时候Activity会在一不注意间就变得臃肿。View过于庞大。当然还有很多跟Android相关的优势,比如说能够更好地避免Activity的内存泄漏(Presenter直接引用View,而不是Activity的时候)。其实通过增加Presenter,一定程度上也增加了Presenter的复用,很多人说View和Presenter是一一对应的,但是我觉得如果不一一对应,比如说一个Activity里面包含多个Presenter,将Presenter细化,那样Presenter复用的可能性也就越高了,同时也避免了Presenter过于臃肿。

一个模式优化过程

平时自己写代码的时候,其实还真的是比较少那么明显地使用这种MVP模式,或者说是MVC模式。更多的是模块化,类层次化(面向对象),面向切面,并且坚持代码精简,复用的原则。下面介绍一个将平时的项目简化后的模式,并且通过考虑优化结构将模式转变成MVP的过程。先看看下面这种类型结构:

先模块化将程序分为Fragment/Activity部分,Adapter部分,模型网络操作部分,通过将相关类进行层次化来减少类的臃肿,另外通过AOP编程的方式将一些内容从子父类中提取出来,作为一个单独的切面。这种面向切面能够提高代码的复用性。

上面的类型图里面也有一个不合理的例子,正如上面的注释中所说的将网络操作作为模型的一部分,而不是再添加一个接口,会导致网络操作一旦修改,会影响到Model的子类。

下面看看如何对上面的结构进行转换。上面这种结构更多的是MVC的方式,而且是将V和C基本合在一起了,内聚在一起能够更方面UI交互,但是也会导致臃肿。上面的图中发现只有BaseFragment单向地去关联Model,这样势必会导致Fragment增加更多的代码来控制,因为在Android中进行网络连接是一定要在非UI线程操作的,如果Model没有关连Fragment,必然需要将一个异步操作放到Fragment,等待Model操作完成了后,Fragment来更新Fragment的内容。如果增加一个接口,然后Fragment实现,并且用Model引用它,那么将能够减少Fragment的操作,而且能够更好地去对Model进行单元测试。如果增加一个Presenter,由Presenter与Fragment相互关联,然后Presenter也与Model相互关联,那么Fragment将会大大简化,更加专注一些其他的UI交互。增加Presenter整个架构就变成了MVP模式了。重构后的类型图如下:

总结

模式总是坚持着复用,模块间低耦合,模块内高内聚等等原则来进行的,设计模式中就有六大原则: 单一职责原则,开闭原则,依赖倒转原则,迪米特法则,里氏替换原则,组合聚合原则。好的模式能够让人在阅读的时候能够很好地理解代码,在对程序进行修改的时候能够快速简洁,并且不对原有代码结构破坏。

以上是关于关于Android MVP模式的思考的主要内容,如果未能解决你的问题,请参考以下文章

Android开发架构模式MVP的简单思考

Android当中的MVP模式终篇---关于对MVP模式中代码臃肿

Android当中的MVP模式终篇---关于对MVP模式中代码臃肿

MVP模式

Android MVP模式的初识

浅谈Android MVP 设计模式