写点什么

Android 架构设计:手把手教你撸一个简洁而强大的 MVP 框架!

用户头像
Android架构
关注
发布于: 2 小时前

override fun onLoginFailed() {...}


// 发起 login 任务请求


fun onLoginClick() {presenter.login(username, password)}


}


真正的View层。可以是Activity,?Fragment等。是真正进行界面更新的地方。


View层需要持有Presenter的对象,用于在需要的时候使用presenter发起具体的数据请求处理任务,比如上例中点击进行登录时。通过presenter发起了登录任务, 并通过LoginView协议接口,接收任务处理回调进行界面更新


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 通信流程,可分为以下几步:


  1. V层向P层发起具体的处理任务

  2. P层接收到V层发起的任务。调用M层的 api,获取到原始数据

  3. P层对从M层获取到的原始数据进行预处理(本示例因为较简单,故没有这一步)。

  4. 处理完毕后的数据。通过V层提供的协议接口,通知到V层去进行界面更新。


MVP 实现




通过上面的实例与讲解。相信可以使大家对 MVP 模型有一定的了解了,下面我们将一步步的介绍整个MVP模型框架的搭建

1. 基础通信协议接口定义:MVPView

interface MVPView {


fun getHostActivity():Activity


fun showLoadingDialog()


fun hideLoadingDialog()


fun toastMessage(message:String)


fun toastMessage(resId:Int)


}


MVPView中定义了一些基础的协议方法。这些方法是所有V层都需要的功能。比如Toast展示、进行异步任务时的加载中Dialog展示等。

2. 基础 Presenter 创建

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 中的生命周期进行绑定。

3. V-P 连接器

其他的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?) {...}


}


可以看到此连接器干了以下几件事:


  1. addPresenterremovePresenter:向容器presenters中添加或移除presenter实例?。?做到对单页面绑定多个 presenter 的效果。

  2. dispatchOnXXX:通过已添加的presenter进行生命周期通知.?做到 V-P 生命周期绑定的效果

  3. 在接收到 V 层destroy销毁通知时,自动移除解绑所有的presenter实例


fun dispatchOnDestroy() {


presenters.forEach {


if (it.isViewAttached()) { it.onDestroy() }


// 生命方法派发完毕后。自动解绑


removePresenter(it)


}


}

4. BaseMVPActivity 的创建

最后就是真正的V层的创建了:Activity/Fragment的 MVP 基类搭建!


这里使用BaseMVPActivity作为举例说明。fragment的基类搭建与此大同小异。


首先,我们需要确定BaseMVPActivity所需要尽到的职责:


1. 一个具体的 V 层,需要持有一个唯一的 MVPDispatcher 进行操作


abstract class BaseMVPActivity:Activity() {


val mvpDispatcher = MVPDispatc


《Android学习笔记总结+最新移动架构视频+大厂安卓面试真题+项目实战源码讲义》
浏览器打开:qq.cn.hn/FTe 免费领取
复制代码


her()


}


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)


}


...

用户头像

Android架构

关注

还未添加个人签名 2021.10.31 加入

还未添加个人简介

评论

发布
暂无评论
Android架构设计:手把手教你撸一个简洁而强大的MVP框架!