基于Kotlin的MVP基础封装

>>强大,10k+点赞的 SpringBoot 后台管理系统竟然出了详细教程!

基于Kotlin的MVP基础封装


这段时间在写基于gank API客户端Demo的时候,尝试着封装了一把MVP,下面就来谈谈这整个过程中的一些感想。


MVP

说起MVP,大家都是熟悉的不能再熟悉的了,但是要封装一套好的MVP还是很有必要的,可以很快捷的开发项目。接着简单提一下我对MVP的个人理解吧(白话文^-^)。

基于Kotlin的MVP基础封装
mvp.png

View层:取数据和显示界面,问P层索要数据,在界面上显示数据。

Presenter层:把View需要的操作传递给Model层,然后Model层处理完复杂操作之后通过P层来把结果传递给View层。

Model层:P层让我干什么我就干什么,有什么用和怎么用不需要管,只管处理,然后把处理后的结果回调给P层。

了解了三者的基本关系之后,接着来看看具体如何封装属于自己的MVP结构。我这里是按照自己的需求,大家仅供参考!

Demo整体结构如下:

基于Kotlin的MVP基础封装
demo.png

整个项目按照上图结构设计。

下面介绍两个比较重要的地方:IBaseViewBasePresenter

IBaseView:

其中IBaseView里面写了两个通用方法:在请求网络的时候用到的通用方法,显示和隐藏进度条。

1interface IBaseView{
2    fun showLoading()
3
4    fun hideLoading()
5
6}

当我们在实现具体I***View时,只需继承它就行了,不必每次都把showLoadinghideLoading写一遍,如:

1interface IMainView : IBaseView {
2    fun showAndroidData(bean: AndroidBean)
3
4    fun showErrorMsg(msg: String = "亲,网络出现问题了哦~")
5}

这是demo中的一个,另外定义了两个方法,一个是展示获取的Android数据,还有一个就是获取数据失败的方法。显示和隐藏进度条就交给IBaseView来实现。

BasePresenter:

BasePresenter里面实现了P层和V层的绑定和解绑,这里需要知道,在MVP结构中,P和V是双向绑定的,如果我们只绑定不解绑的话,在activity已经销毁的情况下,Presenter如果还在执行操作,那么就会造成activity无法被释放的问题,产生内存泄漏。所以这里一定要注意P和V的解绑,具体实现是在BaseActivity中统一处理。具体代码如下:


1package com.taonce.kotlindemo.base
2
3open class BasePresenter<V{
4
5    private var view: V? = null
6
7    // 绑定View
8    fun attachView(view: V) {
9        this.view = view
10    }
11
12    // 解绑
13    fun detachView() {
14        this.view = null
15    }
16
17    fun isAttach()Boolean {
18        return view != null
19    }
20
21}

IBaseView一样,在实现具体的***Presenter的时候,也只需要继承BasePresenter就ok了。只需要另外加上自己的逻辑,不考虑每次的V和P的解绑。如:


1package com.taonce.kotlindemo.presenter
2
3import com.taonce.kotlindemo.base.BasePresenter
4import com.taonce.kotlindemo.bean.AndroidBean
5import com.taonce.kotlindemo.model.MainModel
6import com.taonce.kotlindemo.contract.IMainModel
7import com.taonce.kotlindemo.contract.IMainView
8
9class MainPresenter(mView: IMainView) : BasePresenter<IMainView>(), IMainModel.OnGetAndroidDataListener {
10
11    private var mView: IMainView? = mView
12    private var mModel: IMainModel? = null
13
14    init {
15        mModel = MainModel()
16    }
17
18    fun getAndroidData(category: String, page: Int) {
19        this.mView?.showLoading()
20        this.mModel?.getAndroidData(category, page, this)
21    }
22
23    override fun onGetAndroidDataFinished(bean: AndroidBean?) {
24        this.mView?.hideLoading()
25        if (bean != null) {
26            mView?.showAndroidData(bean)
27            if (bean.error == "true") {
28                mView?.showErrorMsg()
29            }
30        } else {
31            mView?.showErrorMsg()
32        }
33    }
34
35}

BaseActivity

BaseActivity除了日常的getLayoutId()initView()initData()initEvent()四个抽象方法之外,主要还是封装了通用的进度条的显示和隐藏,P层和V层的绑定和解绑。

基于Kotlin的MVP基础封装
MVP-BaseActivity.png
  1. 通过实现IBaseView接口,把里面的方法进行重写,调用showLoadingView()hideLoadingView()方法。

  2. 通过泛型来实现P层的引用,然后通过abstract fun getPresenter(): T来得到具体的Presenter,这样就可以在onCreate()方法里面对P和V进行绑定,在onDestory()方法里对P层引用的View进行释放。

具体代码如下:


1
package com.taonce.kotlindemo.base
2
3import android.support.v7.app.AppCompatActivity
4import android.os.Bundle
5import com.taonce.kotlindemo.R
6import com.taonce.kotlindemo.ui.inter.IBaseView
7
8abstract class BaseActivity<V, T : BasePresenter<V>> : AppCompatActivity(), IBaseView {
9
10    private var baseLoadingView: BaseLoadingView? = null
11    private var basePresenter: T? = null
12
13    override fun onCreate(savedInstanceState: Bundle?) {
14        super.onCreate(savedInstanceState)
15        setContentView(getLayoutId())
16        basePresenter = getPresenter()
17        basePresenter?.attachView(this as V)
18        initLoadingView()
19        initView()
20        initData()
21        initEvent()
22    }
23
24    abstract fun getLayoutId()Int
25
26    abstract fun initData()
27
28    abstract fun initView()
29
30    abstract fun initEvent()
31
32    abstract fun getPresenter(): T
33
34
35    override fun onResume() {
36        super.onResume()
37    }
38
39    override fun onDestroy() {
40        super.onDestroy()
41
42        // 销毁dialog
43        if (null != baseLoadingView && baseLoadingView!!.isShowing) {
44            baseLoadingView?.dismiss()
45        }
46        baseLoadingView = null
47
48        // 在activity销毁时,解绑activity和presenter
49        if (basePresenter != null) {
50            basePresenter?.detachView()
51            basePresenter = null
52        }
53    }
54
55    override fun onStop() {
56        super.onStop()
57    }
58
59    override fun onPause() {
60        super.onPause()
61    }
62
63    private fun initLoadingView() {
64        baseLoadingView = BaseLoadingView(this, R.style.transparent_dialog)
65    }
66
67    private fun showLoadingView() {
68        if (null != baseLoadingView) {
69            baseLoadingView?.show()
70        } else {
71            initLoadingView()
72            baseLoadingView?.show()
73        }
74    }
75
76    private fun hideLoadingView() {
77        if (null != baseLoadingView && baseLoadingView!!.isShowing) {
78            baseLoadingView?.cancel()
79        }
80    }
81
82    /**
83     * 将显示dialog和取消dialog放在了基础类中
84     */

85    override fun showLoading() {
86        showLoadingView()
87    }
88
89    override fun hideLoading() {
90        hideLoadingView()
91    }
92}

网络

网络部分主要采用的是OkHttp3+Retrofit2的方式,通过OKHttp3设置公共头参、Log输出、超时连接等,Retrofit2是用来进行网络请求,最终的线程转换是通过RxJava来实现的,由于网络这块还没深入去探究,暂时只简单封装了一下,后期会在此基础上完善。具体的代码会在文末贴上链接。


整个封装就介绍到这里啦,如果大家觉得有什么不足的地方,欢迎随时交流沟通,期待你们的批评。项目已上传GitHub,地址为:https://github.com/Taonce/Kotlin-RxJava-Retrofit,也可以直接点击下方阅读原文进行查看。


写在最后

每个人不是天生就强大,你若不努力,如何证明自己,加油!

Thank You!

--Taonce

如果你觉得这篇文章对你有所帮助,那么就动动小手指,长按下方的二维码,关注一波吧~~非常期待大家的加入

基于Kotlin的MVP基础封装
专注Kotlin知识的公众号


原文始发于微信公众号(Taonce):基于Kotlin的MVP基础封装