MVP通信方案的思考
一、简述MVC、MVP、MVVM区别
市面上关于MVC、MVP、MVVM各种实现方案都不一样,下面简要说下MVC、MVP、MVVM之间的区别。
1、MVC模式
就是把软件分为三个部分: Model(数据模型层)、View(视图层)、Controller(控制器层),它们之间关系是: View传送指令到Controller, Controller完成业务后,model发生改变,Model将新的数据更新View.
2、MVP模式
MVP 模式将 Controller 改名为 Presenter,同时改变了通信方向。View和Model不直接交互,而是通过中间的Presenter中转,这样一来就隔离了视图层和数据层。
各部分之间的通信,都是双向的。
View 与 Model 不发生联系,都通过 Presenter 传递。
View 非常薄,不部署任何业务逻辑,称为”被动视图”(Passive View),即没有任何主动性,而 Presenter非常厚,所有逻辑都部署在那里。
3、MVVM模式
MVVM 模式将 Presenter 改名为 ViewModel,基本上与 MVP 模式完全一致。唯一的区别是,它采用双向绑定(data-binding):View的变动,自动反映在 ViewModel,反之亦然。
二、MVP方面实现几种方案
市面上关于MVP的实现有很多种,但是主要分类就那么几种,比如使用Activity|Fragment作为View视图层,或把它们作为Presenter层等,还有一种就是目前在使用的Activity|Fragment是独立的,不作为MVP中的一员,而是MVP整个作为一个组件系统装载到Activity|Fragment甚至是一个View中,你只需要在页面销毁、View销毁的时候卸载MVP即可。那么这样的MVP就更具灵活性、可插拔性。
1、MVP方案一(使用Activity|Fragment作为View视图层)
2、MVP方案二(使用Activity|Fragment作为Presenter控制层)
3、MVP方案三(独立装载、卸载一个MVP模块)
相比之下,第三种方案会更灵活,很容易能够自由卸载和安装MVP;而且这样MVP不限于装载于Activity, Fragment甚至可用于一些逻辑复杂的View中。但是相比前两种方案也有不足的地方,比如有时候我们需要通过P层来通知Activity或Fragment做一些事,对于前两种方案很容易就实现,但是对于第三种独立装载的方案则需要通过其他手段来解决。那么就有了下面一套MVP通信方案。
三、MVP通信桥接树的实现
该方案实现了多个MVP嵌套时,任意MVP中的P层都与不同层级的P进行通信,Activity|Fragment装载点就是整棵桥接树的根结点。对于每个节点都是一个回调事件集合的挂载点。在这个挂载点可以注册无数种你需要通知回调的事件。
四、如何使用
假设现在一个场景CommunityRecPresenterImpl中需要使用图片预览功能,然后我们图片预览功能是在HomePresenterImpl中的View层实现,此外CommunityRecPresenterImpl是HomePresenterImpl下层的P,所以需要使用桥接树的方式反向通知上层P,这里是HomePresenterImpl
1、先定义一个IHook回调钩子
interface ImagePreviewHook : IHook3<ImageView, List<ImageView>, List<String>, Unit>//因为涉及到三个回调参数,选择继承IHook3接口
2、然后,在HomePresenterImpl中注册挂载需要触发钩子事件
mBridgeNode.registerHook(object : ImagePreviewHook {
override fun invoke(targetIv: ImageView, imageIvList: List<ImageView>, imageUrls: List<String>) {
mView.previewImage(targetIv, imageIvList, imageUrls)
}
})
3、最后,在下层CommunityRecPresenterImpl中调用注册钩子,并把参数回调出来
override fun onAttached() {
mView.registerEventListener {
onImagePreview { targetIv, ivList, imageUrls ->
mBridgeNode.getHook(ImagePreviewHook::class, false)?.invoke(targetIv, ivList, imageUrls)
}
}
}