Android实践 — ikan项目(四)

/ 0评 / 0

  前几篇博文介绍了项目的net层、data层、domain层,简述了它们是如何维系M层的,本文开始讲解项目的View层和Presenter层。至于为什么会采用MVP模式而不是MVC模式,本文针对MVP模式稍作讲解,首先要了解MVP是什么,用它能给项目带来什么收益。MVP(model-view-presener)是从经典的模式MVC(model-view-controller)衍变而来,它们的基本思想有相通的地方:Controller/Presenter负责逻辑的处理,Model负责提供数据,View负责显示。作为一种新的衍生模式,MVP与MVC有着一个重大的区别:在MVP中View并不直接与Model交互,它们之间的通信是通过Presenter来进行的,所有的交互都发生在Presenter内部,而在MVC中View会从直接Model中读取数据而不是通过Controller。相对传统的CS应用而言,Android应用界面改动的频率比较高,如果采用MVP模式就避免了因频繁改动界面而导致模型层的修改。无论是MVC模式还是MVP模式,它们的设计理念都离不开关注点分离,且二者都有各自应用场景,基于业务需求慎重就好。下图描述MVC/MVP各自的依赖关系:

如你所见,MVP模式中View和Presenter相互引用,如何处理它们间的引用关系并不止一种实现方式,接着本文就项目中采用的方式稍作讲解。

通常情况下Presenter需要访问Context对象,所以需要在View层将Context对象暴露给Presenter使用,因此MvpView接口定义:

interface MvpView {

    val ctx: Context
}

Presenter需要持有View引用,MvpPresenter接口定义:

interface MvpPresenter<V : MvpView> {

    var view: V?
}

项目中MvpPresenter实现如下:在抽象类中留两个钩子以便在附加或者卸载View时做相关处理工作。

abstract class MvpBasePresenter<V : MvpView> : MvpPresenter<V> {

    private var viewRef: WeakReference<V>? = null

    override var view: V?
        set(value) {
            if (value != null) {
                viewRef = WeakReference(value)

                onViewAttached()
            } else {
                onViewDeAttached()

                viewRef?.clear()
                viewRef = null
            }
        }
        get() = viewRef?.get()

    abstract fun onViewAttached()

    abstract fun onViewDeAttached()
}

MvpView和MvpPresenter接口仅定义它们二者的依赖关系,并没有具体维护该关系,项目中我们将Activity作为View层,如果在Activity维护View和Presenter的关系势必导致其臃肿,因此,View和Presenter依赖的实施部分委托给MvpDelegateCallback处理以保持Activity作为View层的职责。看下MvpDelegateCallback的代码定义:

interface MvpDelegateCallback<V : MvpView, P : MvpPresenter<V>> {

    var presenter: P
}

我们让Activity实现MvpDelegateCallback,即让View层持有Prensenter的引用。其次我们既然将Activity作为View层看待,那么繁杂Activity的生命周期控制就不是View的职责了,因此我们将Activity的生命周期也交给代理处理,我们定义了委托协议如下。

interface ActivityMvpDelegate<V : MvpView, in P : MvpPresenter<V>> {

    fun onCreate(bundle: Bundle?)

    fun onStart()

    fun onResume()

    fun onPause()

    fun onSaveInstanceState(outState: Bundle?)

    fun onStop()

    fun onRestart()

    fun onDestroy()

    fun onContentChanged()

    fun onPostCreate(savedInstanceState: Bundle?)
}

接着在MvpActivity将生命周期回调交给ActivityMvpDelegate处理,具体实现代码如下:

abstract class MvpActivity<V : MvpView, P : MvpPresenter<V>> : AppCompatActivity()
        , MvpDelegateCallback<V, P>, MvpView {

    private lateinit var mvpDelegate: ActivityMvpDelegate<V, P>

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        mvpDelegate = ActivityMvpDelegateImpl(this, this)
        mvpDelegate.onCreate(savedInstanceState)
    }

    override fun onStart() {
        super.onStart()
        mvpDelegate.onStart()
    }

    override fun onResume() {
        super.onResume()
        mvpDelegate.onResume()
    }

    override fun onPause() {
        super.onPause()
        mvpDelegate.onPause()
    }

    override fun onStop() {
        super.onStop()
        mvpDelegate.onStop()
    }

    override fun onRestart() {
        super.onRestart()
        mvpDelegate.onRestart()
    }

    override fun onDestroy() {
        mvpDelegate.onDestroy()
        super.onDestroy()
    }

    override fun onSaveInstanceState(outState: Bundle) {
        super.onSaveInstanceState(outState)
        mvpDelegate.onSaveInstanceState(outState)
    }

    override fun onContentChanged() {
        super.onContentChanged()
        mvpDelegate.onContentChanged()
    }

    override fun onPostCreate(savedInstanceState: Bundle?) {
        super.onPostCreate(savedInstanceState)
        mvpDelegate.onPostCreate(savedInstanceState)
    }

    final override val ctx: Context
        get() = this
}

MvpActivity中需要实现MvpView接口将具体context对象返回:

 final override val ctx: Context
        get() = this

在ActivityMvpDelegateImpl中处理Presenter附加View的过程,其实现代码如下:

class ActivityMvpDelegateImpl<V : MvpView, in P : MvpPresenter<V>>
(private val activity: MvpActivity<V, P>, private val delegateCallback: MvpDelegateCallback<V, P>) :
        ActivityMvpDelegate<V, P> {

    @Suppress("UNCHECKED_CAST")
    override fun onCreate(bundle: Bundle?) {
        delegateCallback.presenter.view = activity as V
    }

    override fun onStart() {}

    override fun onResume() {}

    override fun onPause() {}

    override fun onSaveInstanceState(outState: Bundle?) {}

    override fun onStop() {
    }

    override fun onRestart() {
    }

    override fun onDestroy() {
        delegateCallback.presenter.view = null
    }

    override fun onContentChanged() {}

    override fun onPostCreate(savedInstanceState: Bundle?) {}
}

MvpDelegateCallback在具体实现类(View实现)中获得Presenter引用,然后在onCreate中将view附加到presenter,在onDestroy中将view从presenter移除。以上一直简述View和Presenter关系搭建过程,而在前几篇文章简述的M层会提供RepositoryManager供Presenter使用,至此项目采用MVP模式的实施简述告一段落,下一篇简述下presentation层。

笔者再絮叨一遍,针对文章如有不理解之处请留言告知,笔者会在看到后第一时间回复。

发表评论

电子邮件地址不会被公开。 必填项已用*标注