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层。

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

    发表评论

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