Android框架设计之MVP

概述

  • 定义
    MVP 其实是 MVC 的一种演进版本,它更简单,将 MVC 中的 Controller 改为了 Presenter,View 通过接口与 Presenter 进行交互,降低耦合,方便进行单元测试。

    View:负责绘制 UI 元素、与用户进行交互(Activity、View、Fragment 都可以做为 View 层);
    Model:对数据的操作、对网络等的操作,和业务相关的逻辑处理;
    Presenter:作为 View 与 Model 交互的中间纽带,处理与用户交互的逻辑。可以把 Presenter理解为一个中间层的角色,它接受 Model 层的数据,并且处理之后传递给 View 层,还需要处理 View 层的用户交互等操作。

  • 作用
    1、将Model与View彻底分离。
    2、解决MVC中Activity职责过多,代码臃肿的问题

  • 三者关系

    image.png

MVP案例

此实例基于MVC的实例,改造为MVP模式。与MVC不同的是,一般Activty会当作View层来处理

  • Model层
    跟MVC不同的地方在于Model不会跟View发生交互,只会跟Presenter交互,实现了View和Model的完全分离。
data class UserModel(var userName:String){

    fun login(result: Int, listener: ModelCallBack){
        if (result == 1){
            listener.onSuccess("${userName}登录成功")
        }else{
            listener.onFailed("${userName}登录失败")
        }
    }

    //回调接口 根据是否成功返回数据
    interface ModelCallBack{
        fun onSuccess(msg:String)
        fun onFailed(msg:String)
    }
}
  • View层
    在MVP中Activity充当View层角色,并持有Presenter对象的引用。
    创建IView接口,由Activity(即View层)实现方法,并暴露给Presenter调用,用于更新View。
interface IView {
    fun updateUI(msg:String)
}

Activity类:

class MainActivity : AppCompatActivity(),IView{
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        val userPresenter = UserPresenter(this)
        //点击事件  模拟向服务器请求登录
        loginBtn.setOnClickListener{
            userPresenter.login()
        }
    }
    
    //实现更新界面的方法 暴露给Present调用
    override fun updateUI(msg:String) {
        textView.text = msg
    }
}
  • Presenter层
    Present作为中间层,负责业务逻辑处理。
    创建IPresenter接口,由Present层实现,暴露给View层调用
interface IPresenter{
    fun login()
}

Presenter类

class UserPresenter : UserModel.ModelCallBack,IPresenter{
    lateinit var userModel:UserModel
    lateinit var iView:IView
    constructor(iView: IView){
        this.iView = iView
        userModel = UserModel("用户${(0..9).random()}")
    }
    override fun onSuccess(msg: String) {
        iView.updateUI(msg)
    }

    override fun onFailed(msg: String) {
        iView.updateUI(msg)
    }

    override fun login() {
        userModel.login((0..1).random(),this)
    }
}

运行结果

MVP关键点

  • View 不再负责同步的逻辑,而是由 Presenter 负责。Presenter 中既有业务逻辑也有同步逻辑。

  • View 需要提供操作界面的接口给 Presenter 进行调用。(关键)

  • 与MVC的不同

    对比在 MVC 中,Controller 是不能操作 View 的,View 也没有提供相应的接口;而在 MVP
    当中,Presenter 可以操作 View,View 需要提供一组对界面操作的接口给 Presenter 进行调
    用;Model 仍然通过事件广播自己的变更,但由 Presenter 监听而不是 View。

MVP的优缺点

  • 优点

  • 便于测试。Presenter 对 View 是通过接口进行,在对 Presenter 进行不依赖 UI 环境的单元测试的时候。可以通过 Mock 一个 View 对象,这个对象只需要实现了View 的接口即可。然后依赖注入到 Presenter中,单元测试的时候就可以完整的测试 Presenter 业务逻辑的正确性。

  • View 可以进行组件化。在 MVP 当中,View 不依赖 Model。这样就可以让 View 从特定的业务场景中脱离出来,可以说 View 可以做到对业务逻辑完全无知。它只需要提供一系列接口提供给上层操作。这样就可以做高度可复用的 View 组件。

  • 缺点

  • 维护成本相对较高。Presenter 中除了业务逻辑以外,还有大量的 View->Model,Model->View 的手动同步逻辑,造成Presenter 比较笨重,维护起来会比较困难。

  • 系统内存不足时,系统会回收Activity。一般我们都是用OnSaveInstanceState()去保存状态,用OnRestoreInstanceState()去恢复状态。但是在我们的MVP中,View层是不应该去直接操作Model的,所以这样做不合理,同时也增大了M与V的耦合。解决办法是不要将Activity作为View层,可以把Activity当Presenter来处理。具体实现这里就不分析了,有兴趣的可以研究一下。

  • UI改变的话,比如TextView 替换 EditText,可能导致Presente的一些更新UI的接口也跟着需要更改,存在一定的耦合。

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。