MVP模式实战(音乐APP-Android-Kotlin)

1. What is that?

MVP是一种设计模式(框架),因为其出色的解耦功能广泛地用于Android工程中,它将应用程序分为Model-View-Presenter,各司其职,简称MVP

  • Model(模型) 负责对数据的处理和存储,将数据回调给Presenter
  • Presenter(主持者) 负责将View层的请求(如点击,更新视图数据)进行转发给对应的Model,接受回调后再通知View层更新视图
  • View(视图) 仅负责将显示数据
  • Contract(契约类) 仅仅用于定义View和Model的接口,便于管理和查看

一次简单的更新视图的基本流程
MVP模式实战(音乐APP-Android-Kotlin)

顺序就是按照①②③④⑤来进行
1️⃣在View中,我们向Presenter发送一次更新TextView的请求
2️⃣Presenter收到请求后再向对应的Model发送获取String的请求(中间可能有耗时操作,所以可能需要回调接口)
3️⃣成功拿到数据后再通过回调接口给Presenter
4️⃣Presenter拿到数据后再触发View的回调
5️⃣最后完成View的视图更新。
自始至终,View做的事情只有处理用户的请求(更新TextView)并发送给Presenter,然后提供一个用来更新视图的回调;Presenter做的事情只有转发,自己本身不处理逻辑;model负责提供信息,同时包括数据的处理。

有的版本的MVP可能选择将数据处理放入Presenter中,然后model只有一个setter/getter的类似JavaBean的作用,但是我觉得这样处理使得Presenter变得很臃肿,所以我选择将逻辑处理放入Model。两种方式都可以√

2. MVP通用框架

2.1 Contract层
Contract并没有什么很通用个框架,因为每个视图和每一个model的工作各不相同,这里给出的是上图中的的范例

class DetailContract{
    interface DetailView{
        fun onChangeText(String)
    }

    interface DetailModel {
        fun getNowText(callBack: GetTextCallBack)
    }
    interface GetTextCallBack{
        fun onSuccess(str:String)
        fun onFail(info:String)
    }
}

2.2 Model层
Model也没有什么很通用的框架,这里给出的是上图中的范例

class SampleModel: DetailContract.DetailModel{
    override getNowText(callBack: GetTextCallBack){
        val str = ...
        //以上是获取String的操作
        if(str!=""){
            callBack.onSuccess(str)   
        }else{
            callBake.onFail("获取失败")
        }
    }
}

这里的具体Model类实现了Contract契约类中的接口,方便我们Presenter进行调用
2.3 View层
View在Android中一般包括两种,一种是Activity,一种是Fragment,这里只给出Activity的封装,Fragment类似,需要处理一些生命周期的问题。

Activity:

abstract class BaseActivity<V,T:BasePresenter<V>>:Activity(){

    val TAG:String = javaClass.simpleName

    protected lateinit var mPresenter: T

    lateinit var mContext: Context

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        mContext = this
        //初始化Presenter
        mPresenter = createPresenter()
        //将Presenter和View绑定
        mPresenter.attachView(this as V)
        //初始化布局
        initView(savedInstanceState)
    }

    /**
     * 应该由子类进行实现的初始化view的方法
     */
    abstract fun initView(savedInstanceState: Bundle?)

    /**
     * 创建对应的Presenter
     */
    abstract fun createPresenter():T

    //解除绑定
    override fun onDestroy() {
        super.onDestroy()
        mPresenter.detachView()
    }
}

BaseActivity是一个抽象类,所有加入MVP模式的Activity都应该继承这个抽象类。 泛型V代表的是视图(即自己),T则是对应的Presenter。View层持有对应Presenter的引用,用来发送消息。
2.4 Presenter层

abstract class BasePresenter<T> {
    //View接口类型的弱引用,防止所持有的view已经被销毁,但是该presenter仍然持有,导致内存的泄露
    protected lateinit var mViewRef:Reference<T>

    //绑定View引用
    fun attachView(view:T){
        mViewRef = SoftReference<T>(view)
    }

    //获取当前绑定的View引用
    protected fun getView(): T? {
        return mViewRef.get()
    }

    //是否已绑定View
    fun isViewAttached(): Boolean {
        return mViewRef != null&&mViewRef.get()!=null
    }

    //解除引用
    fun detachView(){
        if (mViewRef != null){
            mViewRef.clear()
        }
    }
}

BasePresenter是一个抽象类,所有加入MVP模式的Presenter都应该继承该抽象类。
Presenter持有View层的一个弱引用,同时包括4个和弱引用有关的方法,分别是绑定View的引用,获取当前View的引用,判定是否已绑定了View,解除View的引用。
在具体的Presenter中还拥有一个对应Model对象。也就是Presenter同时持有View和Model,这样才可以做到信息的转发功能

传入的是Contract中的View接口类型是因为可以使得Presenter只通过接口向view传输传输信息。而不是一个具体的类型。

扫描二维码关注公众号,回复: 6301750 查看本文章

以上就是一些常用的框架,下面我们用实战来继续加深理解:

3. 实战

该范例选自红岩移动开发部的中期考核,内容为一个音乐App。仅仅分析播放页面(因为我就做了两个页面

猜你喜欢

转载自blog.51cto.com/14295695/2402179