Android MVP 从入门到放弃

网上有很多关于Android MVP开发模式的讲解了,这里就不详细说了。这篇文章主要说一下怎么搭建一个MVP框架,以及在搭建的过程中的一些注意事项等。因为该框架是结合RxJava2+Retrofit2+MVP模式,所以需要注意的点还是挺多的,尤其是内存泄漏方面。废话不多说,现在开始。

首先说一下怎么搭建。首先我们肯定需要一个view的接口,让我们项目中所有的Activity来实现该接口,这就是MVP中的V层。

interface IBaseView {

    fun showLoading()

    fun dissLoading()
}

例如,在上面的代码中,我们定义了一个接口,里面有基本的两个操作方法,显示加载和隐藏加载,这是每个View层都会涉及到的,所以放在基类中。然后我们再定义一个View接口,用于继承该base接口,然后再定义该View接口中自己的逻辑。例如:

interface View : IBaseView {
        fun showData(newsBean: NewsBean)
        fun showError(msg: String)
    }

在这个View接口中,继承了上面定义的IBaseView接口,然后定义了自己的方法,显示数据和显示错误信息,最后我们的Activity只需要去实现这个View就好了,这个时候,我们的V层就算基本写完了。

然后P层也是同样的封装逻辑。首先定义一个IBasePresenter接口,然后再定义一个Presenter继承该接口。但P层的封装又和V层的封装有点不同,因为它需要考虑到MVP模式下的内存泄漏的问题。因为P层持有V层的引用,有业务逻辑操作,以及调用M层去请求网络,如果这些事情没有做完,这个时候Activity进行销毁操作或者由于被系统自动回收,Activity的内存就释放不了和无法回收,这就造成内存泄漏了,这里有两个机制来防止它内存泄漏的方式。首先是在初始化Activity的时候,让V层和P层绑定,销毁之后,它们解绑;第二就是在P层持有V层的弱引用对象。具体代码如下:

interface IBasePresenter {

    fun attachView(view: T)

    fun detachView()

    fun isViewAttached() : Boolean
}

open class BasePresenter : IBasePresenter {

    private var mRootView: T? = null

    lateinit var mWeakReference: WeakReference

    override fun attachView(view: T) {
        mWeakReference = WeakReference(view)
    }

    override fun detachView() {
        mRootView = null
        mWeakReference.clear()
    }

    override fun isViewAttached(): Boolean {
        mRootView = mWeakReference.get()
        return mRootView != null
    }
}

在这里,定义了一个IBasePresenter接口,里面有三个方法,分别是和V层绑定,解绑和判断是否已经绑定了,这在每个Activity中都需要用到,所以定义在基类中;然后再定义一个BasePresenter类实现该接口,在这个类里面就用到了弱引用来包裹View;通过这两种机制一般就能防止内存泄漏了。

最后我们定义和业务有关的Presenter来继承BasePresenter,然后在调用业务逻辑方法之前判断P层和V层是否绑定了,绑定了才走业务逻辑方法。相关代码如下:

interface Presenter : IBasePresenter {
        fun loadData(params: ArrayMap)
    }

class NewsPresenter : BasePresenter(), NewsContract.Presenter {

    private val newsModel: NewsModel by lazy { NewsModel() }

    override fun loadData(params: ArrayMap) {
        if (!isViewAttached()) {
            return
        }
        newsModel.getNews(params, object : Callback {
            override fun onSuccess(successData: NewsBean) {
                mWeakReference.get().let {
                    it?.showData(successData)
                }
            }

            override fun onFail(failData: String) {
                mWeakReference.get().let {
                    it?.showError(failData)
                }
            }

        })
    }
}

这里的业务逻辑方法就是loadData这个方法,在loadData方法里面,先去判断了该P层有没有和V层绑定,绑定了才去调用M层的方法,最后当M层返回数据的时候,通过弱引用对象的get方法获取到View,最后就能调用View中的方法了。

Model层就很简单了,通过RxJava2+Retrofit2来进行网络请求就好了。代码如下:

class NewsModel {

    fun getNews(params: ArrayMap, callback: Callback) {
        RetrofitFactory.instance.service.getNews(params)
                .subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe({
                    newsBean -> callback.onSuccess(newsBean)
                },{
                    t ->
                    t.message?.let { callback.onFail(it) }
                })
    }
}

在这里,有一个CallBack对象,这个是和P层之间通信的桥梁。当Model层返回数据的时候,使用CallBack对象返回数据给P层。当然,CallBack对象是在P层就实例化了。

interface Callback {

    fun onSuccess(successData: K)

    fun onFail(failData: V)
}

CallBack有使用到泛型的原因是不知道返回的数据是什么类型的,所以使用了泛型。

最后,我们定义一个BaseActivity,让所有的Activity继承它。

abstract class BaseActivity : AppCompatActivity(), IBaseView {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(layoutId())
        attachView()
    }

    abstract fun layoutId() : Int

    abstract fun attachView()

    abstract fun detachView()

    override fun onDestroy() {
        super.onDestroy()
        detachView()
    }
}

在BaseActivity中,定义了两个关键的方法,attachView和detachView,在这两个方法里面,调用P层定义的attachView和detachView方法,就实现了P层和V层的绑定了,最后在Activity的生命周期中调用即可。

如果嫌接口文件比较多,可以把View的接口和Presenter的接口放在一个契约类里面。比如:

interface NewsContract {

    interface View : IBaseView {
        fun showData(newsBean: NewsBean)
        fun showError(msg: String)
    }

    interface Presenter : IBasePresenter {
        fun loadData(params: ArrayMap)
    }
}

这样就减少了项目中的接口文件数量。至此,一个用Kotlin+RxJava2+Retrofit2+MVP模式基本搭建完毕。每个人理解的MVP模式可能不一样,所以写法也可能有出入,不过大体思想就是这样,所以不一定非要按照这种模式来写。现在来说一下MVP模式的优缺点吧。

优点:每层职责清晰单一;Activity只关心自己的生命周期,无须再有业务逻辑相关的处理;代码复用率提高(P层的逻辑可以被多个Activity使用);功能性测试脱于界面,便于测试

缺点:

当项目越来越大的时候,逻辑越来越多的时候,Presenter中除了逻辑以外,还有大量的View->Model,Model->View的逻辑操作,造成Presenter臃肿,维护困难。

UI和Presenter的交互会过于频繁。一旦UI变动,Presenter也需要变

接口暴增,可以说代码量成倍增长,交互都需要通过接口传递信息,让人无法忍受

所以,为了解决MVP模式的缺点,MVVM模式就诞生了。MVVM模式的开发,敬请参见下文:放弃了MVP,我选择了MVVM。

以上是个人对该MVP的理解,有不对的地方,或者代码有写的不对的地方,麻烦指正,谢谢。

项目地址:https://github.com/AnyWayGobin/MVP_MVVM      如果有帮助,记得star哦,谢谢。 

 

你可能感兴趣的:(Android相关开发,Android,RxJava2,Retrofit2,MVP,架构)