Android MVP设计模式学习笔记

前一阵子在翻译Android最佳开发实践的时候查了很多文档,也是在那个时候才了解Model-View-Presenter(MVP)设计模式,一种正在被更广泛接受和使用的Android架构,你可以在这个issue里找到一些讨论。

不过这种架构具体的优势或者思想我不打算在这里赘述,你可以在wiki这个链接里找到其详细的解释。

如果你看了前面两篇文档或者查过一些资料的话,你应该会了解到,目前为止,没有一个标准的MVP模式,我在学习这种模式的时候也看到了很多种不同的架构,比如:1 2 3。所以下面我将介绍我的实现方式。

需要说明的是,我的实现主要依据最后一个链接中Codelab的实现方式,可能并不是最好的选择。

需要的话,可以在我的github上找到这个Demo的源码

实现原理

在说明原理之前,上一张MVP的架构图:
android_mvp

可以看到,Model和View之间的交互是通过Presenter完成的,而Presenter与Model和View之间的交流则是通过接口调用来实现的。

在这里你需要注意以下几点(参考极客学院的wiki):

  • view通常会持有presenter的引用;
  • presenter持有view和model的引用;
  • model应该包括数据和对数据的获取或者修改操作;

一个简单的例子

正如同几乎每个人写的第一行代码都是从简单的打印一句”Hello World!”开始,我给出的例子也是在Android设备上打印一句”Hello World!”。可能我比较笨,每次学习新的结构或者编程语言的时候都想找一个尽可能简单的例子入手学习。所以,我给出的例子也尽可能简单。

我的项目结构看起来类似这样:

me.santong.mvp
    ├── model
    │   ├── ImpMessageData.java
    │   ├── Message.java
    │   └── MessageRepository.java
    ├── presenter
    │   ├── Contact.java
    │   └── Present.java
    └── view
        ├── MessageActivity.java
        └── MessageFragment.java

这个结构有点像MVC的项目分层,其实我觉得,项目结构的样子只要合理便无关痛痒,重要的是自己的习惯(//或者老板的要求…)。因为我只是展示一个简单的例子,所以我并没有把结构搞得很复杂。

首先先说一下核心:

Contact.java:

public interface Contact {
    interface View{
        void showMessage(Message message);
    }

    interface UserListener{
        void setMessage(Message message);
    }
}

这个接口相当于View和Presenter之间的桥梁即上图中View和Presenter中的两根线。在有些MVP架构的实现中,有时会把这个联系关系写成两个接口,而不是像我这样写在一个嵌套接口当中。

这个接口的作用有两点:

  • 使得View层中展示需要展示的内容;
  • 监听用户的操作并交给Presenter处理。

Tip: 因为我比较懒…setMessage(Message message)这个方法我并没有去实现,只是打印了一句”Hello world”。

MessageRepository:

public interface MessageRepository {
    Map<Integer, Message> getMessages();

    Message getMessage(int id);

    void saveMessage(@NonNull Message message);
}

这是连接Presenter和Model的线,然后使用ImpMessageData来存取数据。当然这是一种偷懒的写法,甚至可以说,我实现的挺烂的,没有在意耦合或者复杂的存储,也没有过多的去考虑命名等等一系列问题。

这里我只是模拟简单的数据,在生产环境中,你可能需要操作数据库,解析后台返回的JSON串等等,代码复杂度可不止这一点。

不过殊途同归,无论怎么复杂,最终都需要和Presenter结合在一起,毕竟这个才是心脏。

Presenter:

public class Presenter implements Contact.UserListener {

    private Contact.View mView;

    private MessageRepository mdata;


    public Presenter(Contact.View view, MessageRepository messageRepository) {
        mView = view;
        mdata = messageRepository;
        onBindData();
    }

    private void onBindData() {
        Message message = mdata.getMessage(0);
        setMessage(message);
    }

    @Override
    public void setMessage(Message message) {
        mView.showMessage(message);
    }
}    

你可以看到,我在构造函数中将实现Contact.ViewMessageRepository两个接口的对象即MessageFragmentImpMessageData传了进去,前者是负责展示UI的Fragment对象,后者刚才介绍过的,负责数据的处理,这样,我们就可以很方便的用这两个对象来完成业务逻辑。

另一方面,我在MessageFragment实例化了一个userListener的对象,通过调用userListener中的方法来处理业务逻辑,同时我们可以在Presenter中实现Contact.UserListener这个接口对用户的响应进行操作。

当然,我在这个例子中没有实现用户响应的部分,所以可能看不到在Presenter中实现这个接口的意义。

总体来说,这就是一个简单的MVP架构的Demo,并没有特别复杂,我觉得也比较好理解。如果有什么问题可以留言给我。

再见,Presenter?

等等,这还不是结束。

我在查资料学习MVP架构的时候也看到了一些关于MVVM架构的信息,当时我并没有在意。当我好不容易对MVP有一些理解的时候我看到了这篇文章:ANDROID DATABINDING: GOODBYE PRESENTER, HELLO VIEWMODEL!,大意是Google在2015年的I/O大会上展示了预览版的Android M中的一个库,Data Binding,可以很轻松的替代Presenter的功能,使得代码更加简单和强大,我那个泪奔啊…

那是否意味着在Android开发中,MVP已经不是好的选择了?

我觉得并不是,MVP架构其实已经发展了很久了,只是最近才火了起来,相对而言更加稳定,也是目前比较好的选择。另一方面,个人认为,至少在市场占有率上,Android 5.0(Lollipop)以上的设备不足10%(根据Android studio的提示,不靠谱找谷歌…),所以目前应该是不用着急去掌握MVVM;再者说,MVVM思想其实和MVP也有异曲同工的地方,虽然以后可能早晚要学习这个架构,但是现在掌握了MVP架构,我想可以为之后的学习带来更大的帮助。

补充阅读: MVC,MVP和MVVM的区别