标准化MVP模式
不同的人对MVP有不同的层级划分,虽然都做到了数据和业务分离,但没有统一的标准,不利于后续代码的维护和扩展。这里简单对MVP模式在Android中的使用进行一些约定。
MVP模式的基本概述
既然我们要约定一套标准的MVP模式架构,那么首先我们需要对MVP进行简单的说明。
MVP模式由来
MVP从MVC演变而来,通过表示器将视图与模型巧妙地分开。MVP的全称为Model-View-Presenter,Model
提供数据,View
负责显示,Controller/Presenter
负责逻辑的处理(以下使用Presenter)。MVP与MVC有着一个重大的区别:在MVP中View并不直接使用Model,它们之间的通信是通过Presenter
(MVC中的Controller)来进行的,所有的交互都发生在Presenter
内部,而在MVC中View会直接从Model中读取数据而不是通过Controller。
MVP各个模块说明
MVP模式中各个模块,独立负责不同的业务逻辑。
View
,用来表述Activity或Fragment等暴露给用户使用的视图,中需要和用户交互的事件变化。Model
,用来处理获取服务器数据或本地数据库数据以及一些缓存数据等业务,其中这些数据的操作可以进行更一步的封装,但是调用不能暴露给外部,只能在Model
层使用。Presenter
,用来获取Model
层级的数据,并通过View
层级回调给视图窗口使用。
MVP的基本模块约定
通过上述对MVP模式的概述,我们能大致在心中形成一个简单的划分。那么我们现在直接将这个划分进行限定,让在一个项目团队中的每个人都能直接使用这套规则来进行开发。
视图交互View层
我们定义一个IBaseView
用来表述基本的视图变化,所有后续使用的VIew
层级都需要继承这个基类。
interface IBaseView {
//TODO: 实现基础的视图交互需求,例如获取Context
fun getContext(): Context
}
数据获取Model层
我们定义一个IBaseModel
用来确认数据获取的地方,所有后续构建的Model
层级都需要继承这个基类。
class IBaseModel {
//TODO: 2020年04月10日15:16:02 实现获取对应的数据
}
业务逻辑处理Presenter层
我们定义一个IBasePresenter
用来确认业务逻辑处理的地方,所有后续构建的Presenter
层级都需要继承这个基类。
class IBasePresenter(mView: IBaseView) {
//TODO: 2020年04月10日15:17:24 实现对应视图层逻辑处理
}
视图展示层(Activity或Fragment等)
我们定义一个IBaseMVPActivity
用来实现IBaseView
,且定义获取Presenter
的方法。
abstract class IBaseMVPActivity<out P : IBasePresenter>: AppCompatActivity(), IBaseView {
override fun getContext(): Context {
return this
}
/**
* 让presenter只会创建一个
* */
val presenter: P by lazy {
createPresenter()
}
/**
* 生成presenter的方法
* */
abstract val createPresenter: () -> P
}
扩展
由于Presenter
持有了View
,而视图层级实现了View
。可能会导致当Activity
被销毁时,由于Presenter
调用Model
层的耗时操作,导致内存泄漏,可以结合rxlifecycle2
来处理这个。
且我们可以考虑对Presenter
和Model
之间的交互,增加一个IBaseContact
接口来处理。考虑到Activity或Fragment
和Presenter
,可能存在一对多的情况,并在Presenter
和Model
中指定引用的IBaseView
和IBaseContact
类型,来防止团队协作时传递参数和使用方法的错误的问题。
abstract class BaseModel<out C>(private val contact: C) {//考虑是否在这里限制contact
/**
* 用来处理所有的请求
* */
private val cmSub by lazy {
CompositeDisposable()
}
/**
* 销毁网络请求和提示的对话框
*/
open fun destroy() {
if (!cmSub.isDisposed) {
cmSub.dispose()
}
}
/**
* 增加统一订阅方法,来统一处理请求
* */
fun <T> Observable<T>.subc(s: DisposableObserver<T>) {
if (UserSettingManager.fetchUseNetType() == UserSettingConst.USER_NET_TYPE_NONE) {//仅使用wifi
QNToastUtils.showShort("设置无法使用网络数据!")
return
}
if (UserSettingManager.fetchUseNetType() == UserSettingConst.USER_NET_TYPE_WIFI) {//仅使用wifi
//第一次检测网络使用情况
val netManager = QNUtils.getInstance().app.
getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
if (NetChangeManager.checkNetType(netManager, false) != ConnectivityManager.TYPE_WIFI) {
QNToastUtils.showShort("设置仅使用WIFI网络数据,当前无WIFI连接!")
return
}
}
if (UserSettingManager.fetchUseNetType() == UserSettingConst.USER_NET_TYPE_3G) {//仅使用3g
//第一次检测网络使用情况
val netManager = QNUtils.getInstance().app.
getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
if (NetChangeManager.checkNetType(netManager, false) != ConnectivityManager.TYPE_MOBILE) {
QNToastUtils.showShort("设置仅使用移动网络数据,当前无移动网络数据!")
return
}
}
this.subscribe(s)
cmSub.add(s)
}
}
参考:
https://baike.baidu.com/item/MVP%E6%A8%A1%E5%BC%8F/10961746?fr=aladdin
https://blog.csdn.net/hpp_1225/article/details/80674451
https://www.jianshu.com/p/f3e7deae7281