前言
接着上一篇的博客,在上一篇中已经把网络框架Retrofit
进行简单的封装,接下来说说MVP
模式
MVC&MVP&MVVM区别
先来说说MVC
,如图
图是最好的记忆方式,MVC
呈现闭环的形式。其中:
-
View
使用xml
文件做为视图样式 -
Controller
Activity/Fragment
控制业务逻辑,比如发起网络请求,控制视图里面的输入输出信息,更新本地数据库信息等等 -
Model
网络请求数据模型,本地数据库数据模型,以及一些耗时处理操作并更新View
的展示信息等等
MVC具有两种设计方式
- 从
View
获取用户操作信息,然后把信息传递给Controller
进行一些逻辑处理 - 直接把操作信息给
Controller
,比如Controller
获取EditText
的输入信息等等
MVC优缺点
优点
-
MVC
已经在framework
层搭建好,上手比较容易,模块化比较清晰 - 实现了视图层
View
,业务逻辑层Controller
以及数据模型层Model
的分离,降低了代码的耦合性
缺点
-
Controller
任务重,容易导致代码臃肿 -
View
依赖Model
,layout
无法实现数据绑定,从而导致各种自定义View
,提高了代码的重复性 - 由于
View
依赖Model
,导致不好写代码的测试用例,只能编译调试。
MVP
为了解决MVC
的View
依赖Model
,以及Controller
代码臃肿,增加了Presenter
来处理业务逻辑以及View
和Model
的分离,如下图
通过Presenter
成功的把View
和Model
进行分离,其中:
-
View
指Activity/Fragment
,主要是实现MVPView
的抽象方法供Presenter
调用,以及调用Presenter
方法进行网络请求或者业务处理,也就是图上的双向通信 -
Model
同MVC
一样,主要是网络请求数据模型或者本地数据库数据模型以及一些耗时的操作。 -
Presenter
业务处理,调用Model
的方法网络请求获取数据并且调用MVPView
的方法更新View
的数据
设计MVP
的时候,会遇到一个问题,就是在手机屏幕切换的时候,如果保存Presenter
当前的状态。这就涉及到Presenter
生命周期问题。这个问题在网上能够搜到很多资料,主要解决办法有:
- 把
Activity/Fragment
当做Presenter
来使用,然后Presenter
当做View
来使用,参考一种在android中实现MVP模式的新思路这篇文章 - 使用
Loader
的生命周期来管理Presenter
的生命周期 -
Presenter
继承Fragment
来管理生命周期
主要是以Presenter
生命周期要比Activity/Fragment
的生命周期更长的原理来解决,这里使用的Loader
类来解决。
MVP优缺点
优点
- 实现了
View
和Model
的解耦 - 便于写代码的测试用例
缺点
- 上下文
context
容易丢失 - 具有
presenter
生命周期问题以及内存泄漏问题 - 双向通信回调,导致项目复杂化
MVVM
在MVP
中,当我们在Presenter
中获取到Model
需要调用MVPView
的方法绑定View
并更新数据,而MVVM
结合databinding
可以直接响应Model
数据变化自动化更新View
,使Activity/Fragment
代码变得更加简洁。如下图
-
Model
同上,网络数据模型或者本地数据模型 -
View
用xml
格式来表示视图格式,结合databinding
可以直接绑定Model
数据和视图点击事件 -
ViewModel
处理业务逻辑,发送网络请求,更新Model
数据等操作
主要步骤就是View
获取响应信息后通知ViewModel
从Model
更新数据,数据更新后,Model
通知ViewModel
更新View
展示的数据
MVVM优缺点
优点
-
View
和Model
低耦合 -
Activity/Fragment
代码变得更加简洁,减少了更新View
数据以及点击事件的处理 - 解决了
MVP
中View(Activity/Fragment)
和Presenter
相互持有的问题 - 不在需要考虑主线程更新
UI
的问题
缺点
-
View
层变得更加复杂 - 数据绑定使得
BUG
不好调试以及更大的性能消耗
MVP实现
实现的几个步骤:
-
MVPView
,定义一些回调的方法,并让Activity/Fragment
实现它 -
Presenter
获取View
实例,并提供几个加载数据的加载框处理的回调方法 - 使用
Loader
管理Presenter
生命周期(一个PresenterFactory
和一个PresenterLoader
) -
Activity/Fragment
通过Loader
的LoaderManager.LoaderCallbacks
回掉获取Presenter
实例
先定义MVPView
object Mvp {
interface View {
val sub: CompositeDisposable
}
}
其中CompositeDisposable
在BaseActivity
实现创建CompositeDisposable
对象,统一管理接口请求的Obserable
的绑定和解绑
定义Presenter
interface Presenter{
fun attachView(attach: Any)
fun detachView()
}
attachView()
绑定View
,也就是Activity/Fragment
detachView()
释放View
通过BasePresenter
实现如下
@Suppress("UNCHECKED_CAST")
abstract class BasePresenter<V : Mvp.View> : Presenter,IProgressDialog{
private var attachView:V? = null
private var dialog:IProgressDialog ?= null
lateinit var mvpView:V
override fun attachView(attach: Any) {
this.attachView = attach as V
this.dialog = attach as IProgressDialog
mvpView = mvpView()
initHandler()
}
override fun detachView() {
this.attachView = null
}
private fun mvpView(): V {
checkAttachView()
return attachView!!
}
fun checkAttachView(){
if(this.attachView==null) throw RuntimeException("Call the attachView method before using the Mvp.View")
}
open fun initHandler() {
}
override fun showLoading() {
dialog?.showLoading()
}
override fun dismissLoading() {
dialog?.dismissLoading()
}
override fun updateNextPage(haveNext: Boolean) {
dialog?.updateNextPage(haveNext)
}
}
attachView
对应View
层的引用,attach
传Activity/Fragment
dialog
对应BaseActivity
实现的IProgressDialog
接口,实现showLoading(),dismissLoading(),updateNextPage()
方法管理网络请求弹出框显示和消失的操作以及RecyclerView
分页加载的一些操作。
mvpView
供继承BasePresenter
的Presenter
网络请求处理以及一些Activity/Fragment
方法的调用或者MVPView
的一些方法
Presenter生命周期管理
Loader
类生命周期有:
onStartLoading()
Activity
的onStart()
调用之后,会回调这个方法创建一个Loader
实例
onForceLoad()
当onStartLoading
调用forceLoad
方法后,会回调这个方法,可在这里创建Presenter
。
deliverResult()
调用这个方法可以把Presenter
分发给Activity/Fragment
onReset()
Loader
销毁前回调
定义一个创建Presenter
的接口PresenterFactory
interface PresenterFactory<out P:BasePresenter<*>> {
fun create() :P
}
这样就可以在Activity/Fragment
实现这个接口创建对应Presenter
。从而得到相应Presenter
的实例方法的引用。
定义PresenterLoader
实现Loader
类并传入PresenterFactory
来管理生命周期
class PresenterLoader<P :BasePresenter<*>>(context: Context, val factory:PresenterFactory<P>): Loader<P>(context) {
private var presenter:P? = null
override fun onStartLoading() {
if(presenter != null){
deliverResult(presenter)
return
}
forceLoad()
}
override fun onForceLoad() {
presenter = factory.create()
deliverResult(presenter)
}
override fun onReset() {
presenter = null
}
}
结合上面描述的Loader
生命周期就可以很好的理解上面的代码了。
LoaderManager.LoaderCallbacks
最后一步在BaseLoaderActivity
实现LoaderManager.LoaderCallbacks
的回调方法
abstract class BaseLoaderActivity<P:BasePresenter<*>>: AppCompatActivity(),Mvp.View,LoaderManager.LoaderCallbacks<P>{
protected var presenter:P? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
supportLoaderManager.initLoader(Consts.BASE_ACTIVITY_LOADER_ID,null,this)
}
override fun onLoadFinished(loader: Loader<P>?, data: P) {
presenter = data
presenter?.attachView(this)
}
override fun onCreateLoader(id: Int, args: Bundle?): Loader<P>? {
return createLoader()
}
override fun onLoaderReset(loader: Loader<P>?) {
presenter = null
}
override fun onDestroy() {
presenter?.detachView()
super.onDestroy()
}
abstract fun createLoader():Loader<P>
}
Loader
会先调用onCreateLoader
创建一个Loader
实例,然后调用onLoadFinished
,我们可以在这里获取到Presenter
实例,然后当Loader
销毁前调用onLoaderReset()
,这里我们可以对Presenter
进行释放。其中
supportLoaderManager.initLoader(Consts.BASE_ACTIVITY_LOADER_ID,null,this)
是进行Loader
初始化的一个操作
createLoader()
供继承BaseLoaderActivity
的Activity
结合PresenterLoader
和PresenterFactory
创建Loader<P>
对象。
同理,BaseLoaderFragment
也如上创建即可。