Android端的MVP架构已经出来有很长时间了。而对于Android的MVP实现模式,也并无个标准的实现方式。java
如今市面上最流行的是google开源出来的一套MVP模型,此模型可到此google家MVP开源地址进行查看。android
而此篇博客将要介绍的并非google的MVP模型。而是根据我自身理解所建立的一种MVP模型。与google的MVP模型相比,此种MVP模型具备如下一些优点:git
仅仅靠上面的文字来进行分层说明略显空洞,因此这里咱们来经过一个简单的sample代码
来作MVP分层概念说明, 以下方是个简单的登陆页面的MVP实现:github
interface LoginView:MVPView {
fun onLoginSuccess()
fun onLoginFailed()
}
class LoginPresenter(view:DemoView):MVPPresenter<DemoView>(view) {
fun login(username:String, password:String) {
LoginApis.login(username, password, object Callback {
override fun onSuccess() {
view.onLoginSuccess()
}
override fun onFailed() {
view.onLoginFailed()
}
})
}
}
class LoginActivity:BaseMVPActivity(),LoginView {
// 建立与绑定Presenter。
val presenter = LoginPresenter(this)
override fun createPresenters() = arrayOf(presenter)
override fun onLoginSuccess() {
// 接收数据请求任务的返回数据并展现
EasyToast.DEFAULT.show("登陆成功")
}
override fun onLoginFailed() {
// 接收数据请求任务的返回数据并展现
EasyToast.DEFAULT.show("登陆成功")
}
...
// 点击登陆
fun onLoginClick() {
val username = ...
val password = ...
presenter.login(username, password)// 发起login任务请求
}
}
复制代码
1. LoginViewapi
interface LoginView:MVPView {
fun onLoginSuccess()
fun onLoginFailed()
}
复制代码
继承并扩展MVPView接口。不少人喜欢直接将此类做为MVP中的V层
,可是实际上,我更愿意称此为通讯协议接口
,做用是由V层
提供给P层
进行P-V绑定
,用于在P层
中通知V层
进行界面更新,相似于提供了一个Callback给P层进行使用bash
2. LoginActivity网络
class LoginActivity:BaseMVPActivity(),LoginView {
override fun onLoginSuccess() {...}
override fun onLoginFailed() {...}
// 发起login任务请求
fun onLoginClick() {presenter.login(username, password)}
}
复制代码
真正的View
层。能够是Activity
, Fragment
等。是真正进行界面更新的地方。架构
View
层须要持有Presenter
的对象,用于在须要的时候使用presenter
发起具体的数据请求处理任务
,好比上例中点击进行登陆时。经过presenter
发起了登陆任务, 并经过LoginView
协议接口,接收任务处理回调
进行界面更新app
3. LoginApis框架
LoginApis.login(username, password, object Callback {
override fun onSuccess() { view.onLoginSuccess() }
override fun onFailed() { view.onLoginFailed() }
})
复制代码
Model
层,也叫数据提供层。
与其余的MVP
不一样,这里并无要求Model
层须要定义一个特殊的接口去进行实现。全部的功能性api
。都可被视做为Model
层。好比这里LoginApis
,即是用于提供登陆模块的网络任务入口
。
Model
层与Presenter
层的通讯方式主要分为两种:一种直接从Model层同步获取
到指定数据,另外一种是经过异步回调
的方式获取到指定数据,即此处LoginApis
的通讯方式。
请注意避免直接向Model
层传递Presenter
去进行数据获取。保证Model
的独立性
4. LoginPresenter
Presenter
层,链接V-M的中间枢纽层。复杂的数据业务逻辑都在这里进行处理。
结合上方示例:一个完整的M-P-V通讯流程,可分为如下几步:
V层向P层
发起具体的处理任务P层
接收到V层
发起的任务。调用M层
的api,获取到原始数据
P层
对从M层
获取到的原始数据
进行预处理(本示例由于较简单,故没有这一步)。处理完毕后
的数据。经过V层
提供的协议接口,通知到V层
去进行界面更新。经过上面的实例与讲解。相信可使你们对MVP模型有必定的了解了,下面咱们将一步步的介绍整个MVP模型框架的搭建
interface MVPView {
fun getHostActivity():Activity
fun showLoadingDialog()
fun hideLoadingDialog()
fun toastMessage(message:String)
fun toastMessage(resId:Int)
}
复制代码
MVPView
中定义了一些基础的协议方法。这些方法是全部V层
都须要的功能。好比Toast展现
、进行异步任务时的加载中Dialog展现
等。
open class MVPPresenter<T:MVPView>(private var view:T?){
fun attach(t:T) {
this.view = t
}
fun detach() {
this.view = null
}
fun isViewAttached() = view != null
fun getActivity() = view?.getHostActivity()?:throw RuntimeException("Could not call getActivity if the View is not attached")
// Lifecycle delegate
open fun onCreate(bundle: Bundle?) {}
...
open fun onDestroy(){}
}
复制代码
咱们来一条条的捋一下:
首先。咱们在上面的MVP说明中说过,MVPView
为协议接口,提供出来用于进行P-V绑定
,因此相应的就会有P-V的绑定与解绑功能
(为了方便使用,这里也让默认构造器自动进行了P-V绑定)
fun attach(t:T) { this.view = t }
fun detach() { this.view = null }
复制代码
而后,咱们会常常须要在P层中使用绑定的Activity去进行各类操做。而p层
是不建议去持有Context实例
的,因此在此提供一个getActivity
方法,从绑定的view
中去获取正确的Activity实例
提供使用:
fun getActivity() = view?.getActivity()?:throw RuntimeException("Could not call getActivity if the View is not attached")
复制代码
而isViewAttached
方法,则是专门为异步回调任务
所设计的api。由于若是是使用异步回调的方式
去从model层获取的数据。那么极可能,接收到回调消息的以前,这个时候view已被解绑置空
。致使通知失败
因此。通常来讲。对于任务中有异步回调操做
的,应该在回调处。先行判断是否已解绑
。若已解绑则跳过当前操做:
if (!isViewAttached()) return
view?.hideLoadingDialog()
复制代码
最后,则是提供的一堆onXXX
生命周期方法了。用于与activity/fragment 中的生命周期进行绑定。
与其余的MVP
相比不一样,这里提供MVPDispatcher
做为V-P链接器
:
class MVPDispatcher{
private val presenters:MutableList<MVPPresenter<*>> = mutableListOf()
// ==== 添加与移除Presenter ========
fun <V:MVPView> addPresenter(presenter:MVPPresenter<V>) {...}
internal fun <V:MVPView> removePresenter(presenter:MVPPresenter<V>) {...}
// ==== 绑定生命周期 ==========
fun dispatchOnCreate(bundle:Bundle?) {...}
...
fun dispatchOnRestoreInstanceState(savedInstanceState: Bundle?) {...}
}
复制代码
能够看到此链接器干了如下几件事:
addPresenter
与removePresenter
:向容器presenters
中添加或移除presenter实例
。 作到对单页面绑定多个presenter的效果。dispatchOnXXX
:经过已添加的presenter
进行生命周期通知
. 作到V-P生命周期绑定的效果destroy
销毁通知时,自动移除解绑全部的presenter实例
。fun dispatchOnDestroy() {
presenters.forEach {
if (it.isViewAttached()) { it.onDestroy() }
// 生命方法派发完毕后。自动解绑
removePresenter(it)
}
}
复制代码
最后就是真正的V层
的建立了:Activity/Fragment
的MVP基类搭建!
这里使用BaseMVPActivity
做为举例说明。fragment
的基类搭建与此大同小异。
首先,咱们须要肯定BaseMVPActivity
所须要尽到的职责:
1. 一个具体的V层,须要持有一个惟一的MVPDispatcher进行操做
abstract class BaseMVPActivity:Activity() {
val mvpDispatcher = MVPDispatcher()
}
复制代码
2. 统一实现默认协议方法:MVPView
abstract class BaseMVPActivity:Activity(), MVPView {
...
override fun getHostActivity():Activity {...}
override fun showLoadingDialog() {...}
override fun hideLoadingDialog() {...}
override fun toastMessage(message:String) {...}
override fun toastMessage(resId:Int) {...}
}
复制代码
3. 借助MVPDispatcher实现V-P,一对多的绑定
abstract class BaseMVPActivity:Activity(), MVPView {
...
// 由子类提供当前页面全部须要绑定的Presenter。
open fun createPresenters():Array<out MVPPresenter<*>>? = null
override fun onCreate(savedInstanceState: Bundle?) {
...
// 建立全部的presenter实例,并经过mvpDispatcher进行绑定
createPresenters()?.forEach { mvpDispatcher.addPresenter(it) }
}
}
复制代码
好比在最上面咱们所举例的LoginActivity。假设如今咱们须要对登陆页再添加一个验证码校验逻辑
. 此逻辑被放在了CaptchaPresenter
中:
class LoginActivity:BaseMVPActivity(),LoginView, CaptchaView {
// 登陆的Presenter实现
val loginPresenter = LoginPresenter(this)
// 验证码的Presenter实现
val captchaPresenter = CaptchaPresenter(this)
// 绑定多个Presenter
override fun createPresenters() = arrayOf(loginPresenter, captchaPresenter)
...
}
复制代码
这就作到了Presenter的复用。在须要共用一些基础业务逻辑
的时候。此一对多的绑定
是个很好的特性!
4. 借助MVPDispatcher实现V-P生命周期关联管理
abstract class BaseMVPActivity:Activity(), MVPView {
...// other codes
override fun onCreate(savedInstanceState: Bundle?) {
...
mvpDispatcher.dispatchOnCreate(intent?.extras)
}
...
override fun onDestroy() {
...
// 销毁时mvpDispatcher会自动进行全部的Presenter的解绑。
// 因此具体的V层并不须要再本身去手动进行解绑操做了
mvpDispatcher.dispatchOnDestroy()
}
}
复制代码
这就是一个基本的V层基类实现类须要作到的事。到这里。整个MVP基础框架的搭建就算完成了!
因为此MVP架构实际上是个挺简单的架构。因此我将此架构源码存放在了EasyAndroid组件库中了。
EasyAndroid做为一款集成组件库,此库中所集成的组件,均包含如下特色,你能够放心使用~~
1. 设计独立
组件间独立存在,不相互依赖,且若只须要集成库中的部分组件。也能够很方便的
只copy对应的组件文件
进行使用
2. 设计轻巧
由于是组件集成库,因此要求每一个组件的设计尽可能精练、轻巧。避免由于一个小功能而引入大量无用代码.
每一个组件的方法数均
不超过100
. 大部分组件甚至不超过50
。
因为V层基类实现
不一样项目都会有必定的差别性。好比Activity基类选择
(AppCompatActivity/v4Activity/Activity)、或者MVPView的展现样式设计
等。因此BaseMVPActivity
这类真正的V层基类实现
并无被放入lib中。而是在示例工程中
单独进行了提供.
在须要使用的时候,经过copy此部分的源码直接到工程中使用便可
EasyAndroid库中的mvp模块。仅仅提供了MVPView
、MVPPresenter
、MVPDispatcher
这三个基础支持类。避免引入无用代码。
https://github.com/yjfnypeu/EasyAndroid
MVPView
、MVPPresenter
、MVPDispatcher
源码地址https://github.com/yjfnypeu/EasyAndroid/tree/master/utils/src/main/java/com/haoge/easyandroid/mvp
V层基类实现
及简单sample示例代码
地址https://github.com/yjfnypeu/EasyAndroid/tree/master/app/src/main/java/com/haoge/sample/easyandroid/activities/mvp