Android:MVP架構(gòu)分析與封裝

Github地址:https://github.com/WangFion/mvp-mode

一褐隆、MVP 基本概念


??MVP 全稱:Model-View-Presenter 择同;MVP 是從經(jīng)典的模式MVC演變而來宋雏,它們的基本思想有相通的地方:Controller/Presenter負(fù)責(zé)邏輯的處理,Model提供數(shù)據(jù)冗酿,View負(fù)責(zé)顯示绪杏。
??談到這里,我們就不得不把它和MVC做一個(gè)對(duì)比了矫钓,首先看下圖:


MVC與MVP.png

??對(duì)于上圖,我們主要做以下幾點(diǎn)說明:
??1舍杜、MVP 模式下新娜, V 層和 P 層是分開定義的;而 MVC 模式下蝴簇,V 層和 C 層是混合定義的杯活,通常都在 Activity 或 Fragment 里面匆帚,故上圖把 V 和 P 圈在了一起熬词。
??2、MVP 模式下吸重,切斷了 V 層和 M 層的一個(gè)通訊互拾,他們之間的通訊必須經(jīng)過 P 層的控制,理論上 M 層是不允許持有 P 層的強(qiáng)引用嚎幸,故 M 層可以做到完全的獨(dú)立颜矿,因此 M 層的表現(xiàn)形式可以是本地 code、jar嫉晶、so骑疆、aar等等。而 MVC 模式下替废,M 層做不到完全獨(dú)立箍铭,M、V椎镣、C 三層之間耦合度較高诈火,很難應(yīng)對(duì)業(yè)務(wù)的擴(kuò)展。
??3状答、MVP 模式下冷守,理論上三層支持 N:N:N 的模式,但是鄙人建議三層之間的對(duì)應(yīng)關(guān)系是 1:1:N 的模式惊科,主要是從業(yè)務(wù)劃分和后期維護(hù)來看拍摇,至于具體的理由各位看官老爺就自行體會(huì)了。

??總的來看馆截,MVP 是在 MVC 的基礎(chǔ)上進(jìn)行了一個(gè)優(yōu)化充活,使得業(yè)務(wù)邏輯更加清晰,層次分明,降低了模塊層次耦合度堪唐。當(dāng)然了也不是沒有缺點(diǎn)巡语,像增加文件和接口個(gè)數(shù)等等,但鄙人認(rèn)為這點(diǎn)缺點(diǎn)相較于優(yōu)點(diǎn)來說可以忽略不記哈淮菠。


二男公、MVP 框架結(jié)構(gòu)


mvp框架.png

??首先,左側(cè)貫穿 M合陵、V枢赔、P 三層的包括 Application、工具類(Utils拥知、Tools)踏拜、實(shí)體類(Entitiy、java bean)低剔。Application就不說了整個(gè)項(xiàng)目的唯一對(duì)象速梗;工具類則是我們定義的一些工具,它和三層中的任何一層都不會(huì)有直接的聯(lián)系襟齿,故可以共同使用姻锁;而實(shí)體類則是數(shù)據(jù)的承載,用來在三層之間傳遞數(shù)據(jù)猜欺。
??其次位隶,最上層是我們的 View 層,主要用來顯示信息和做人機(jī)交互开皿,包括但不限于上圖所列項(xiàng)涧黄。這一層是直面用戶的、給人以真是感受的地方赋荆,故在 MVP 模式中此層主要專注于界面的顯示和事件的響應(yīng)而不會(huì)關(guān)心數(shù)據(jù)的具體信息以及業(yè)務(wù)的邏輯處理笋妥,所以在這層里面我們看到的是一系列類似 setXXX()、 showXXX()糠睡、hideXXX()挽鞠、onXXXListener() 的接口方法,它會(huì)持有一個(gè) Presenter 的引用狈孔,將一切的業(yè)務(wù)邏輯動(dòng)作都傳遞給 Presenter 處理信认。
??緊接著,View層之下的是我們的Presenter層均抽,此層主要是用來做業(yè)務(wù)邏輯處理和鏈接 M嫁赏、V兩層。在這層中我們看到的更多的是 switch-case油挥、if-else潦蝇、for款熬、while、toXXX等等一系列的邏輯處理和數(shù)據(jù)轉(zhuǎn)換等操作攘乒;另外贤牛,這層會(huì)持有 M、V兩個(gè)引用则酝,將邏輯和數(shù)據(jù)處理的結(jié)果通個(gè) V 層的引用傳遞到 View 來展示殉簸,通過 M 層的引用來獲取邏輯和數(shù)據(jù)處理過程中需要的數(shù)據(jù)服務(wù)支持。
??最后沽讹,最下層是我們的Modle層般卑,此層主要是提供數(shù)據(jù)服務(wù)支持的,這層包括但不限于我上圖所列的內(nèi)容爽雄。這層的設(shè)計(jì)我個(gè)人理解的有一個(gè)標(biāo)準(zhǔn):獨(dú)立于項(xiàng)目蝠检,怎么理解這個(gè)標(biāo)準(zhǔn)呢,套用毛主席的一句話:M 是項(xiàng)目的一塊磚挚瘟,哪里需要往哪搬叹谁,也就是說任何一個(gè)項(xiàng)目或者業(yè)務(wù)模塊需要,直接把這個(gè) Model 文件拷貝過去并且不需要做任何額外的工作就能直接使用刽沾,并且能正常工作本慕。因此在這層里面異步數(shù)據(jù)建議通過 callback、message等形式返回侧漓,對(duì)外部對(duì)象的持有一律采用 SoftReference 或者 WeakReference。


三监氢、MVP 架構(gòu)封裝


??上面的內(nèi)容布蔗,簡單的給大家介紹了一下關(guān)于 MVP 的基本信息,我相信仔細(xì)閱讀過上面內(nèi)容的童鞋心里已經(jīng)有了相關(guān)的概念浪腐。下面的內(nèi)容我會(huì)給大家分析一下我封裝的一個(gè) MVP 框架,從 code 層面讓大家對(duì) MVP 進(jìn)一步深入學(xué)習(xí),本框架分 Kotlin 和 Java 兩種編程語言摹察,雖然編程語言不一樣奶躯,但是基本思想和架構(gòu)是一樣的,我這里就不都分析了特漩,下面的內(nèi)容主要講解 Kotlin 版本的吧雹,Java 版本的大家可以去源碼自行查看。


項(xiàng)目結(jié)構(gòu)圖.png

??整個(gè)項(xiàng)目工程包含三個(gè) Module涂身。app Module 為項(xiàng)目業(yè)務(wù)模塊雄卷,在項(xiàng)目開發(fā)中用來編寫業(yè)務(wù)邏輯代碼,當(dāng)然了組件化開發(fā)模式下 app Module 一般會(huì)根據(jù)業(yè)務(wù)拆分出很多個(gè)子 Module蛤售,這里不是本文重點(diǎn)就不過多分析了丁鹉。mvp-java 和 mvp-kotlin 是本文分析的重點(diǎn)妒潭,也就是我封裝的 MVP 框架,所以接下來我就們開始詳細(xì)的分析 mvp-kotlin Module揣钦。

1雳灾、接口層

impl.png

  • 首先 Impl.kt 里面定義的是公共接口,內(nèi)容比較簡單大家一看就懂冯凹,這里就不詳細(xì)介紹了佑女。
  • 接下來是 Presenter.kt,詳細(xì)內(nèi)容如下:
package com.wf.mvp.kotlin.impl

import com.wf.mvp.kotlin.customize.UiHandler

/**
 * MvpMode -> com.wf.mvp.kotlin.impl -> IPresenter
 * @Author: wf-pc
 * @Date: 2020-05-10 15:24
 * <p>
 * Mvp's p-layer specification, used to limit the interfaces that the presenter must implement.
 */
interface Presenter : Impl {

    fun <U: Ui> attachView(view: U, handler: UiHandler?)

    fun detachView()

}

??此 Presenter 接口是所有 P 層都必須實(shí)現(xiàn)的頂層接口谈竿,它繼承至 Impl 接口团驱。這里定義了兩個(gè)最重要的接口方法 attachView 和 detachView,這兩個(gè)方法是用來供 V 層調(diào)空凸,使得 V 與 P 相互建立聯(lián)系嚎花,其中 attachView 綁定的 view 則是我們后面會(huì)講到的實(shí)現(xiàn)了 Ui 接口的 V 層的實(shí)例對(duì)象。

  • 最后是 Ui.kt呀洲,詳細(xì)內(nèi)容如下:
package com.wf.mvp.kotlin.impl

/**
 * MvpMode -> com.wf.mvp.kotlin.impl -> IView
 * @Author: wf-pc
 * @Date: 2020-05-10 15:26
 * <p>
 * Mvp's v-layer specification, used to limit the interfaces that the view must implement.
 */
interface Ui : Impl {

    fun attachPresenter()

    fun detachPresenter()

}

??此 Ui 接口則是所有 V 層都必須實(shí)現(xiàn)的頂層接口紊选,同 Presenter 接口一樣它亦繼承至 Impl 接口。這里定義了兩個(gè) attachPresenter 和 detachPresenter接口方法道逗,分別用來綁定和解綁 P 層的實(shí)例對(duì)象兵罢。

??總結(jié),以上便是接口協(xié)議層的所有內(nèi)容滓窍,這里規(guī)定了 V 層和 P 層的基礎(chǔ)協(xié)議規(guī)則卖词,使得 V 和 P 建立雙向聯(lián)系,后續(xù)具體的 View 和 Presenter 實(shí)例都是從這里派生出去吏夯。到這里你可能會(huì)問:為什么沒有 M 層的協(xié)議接口此蜈?如果有這樣的疑問那說明沒有認(rèn)真閱讀上兩節(jié)的內(nèi)容哦,前面我們講過 M 層是要做到獨(dú)立于項(xiàng)目噪生,那么它就不需要公共的協(xié)議裆赵,各自的數(shù)據(jù)服務(wù)實(shí)現(xiàn)各自的業(yè)務(wù)即可,另外 Presenter 下面還可能對(duì)應(yīng)于很多個(gè) M跺嗽,故 M 層沒有統(tǒng)一的接口協(xié)議战授,也不用必須于 P 層建立聯(lián)系。

2桨嫁、抽象層 Presenter

abs_presenter.png

??其中 DefaultIPresenter 是一個(gè)空實(shí)現(xiàn)的 Presenter植兰,沒有什么可講的內(nèi)容。我們主要給童鞋們分析 IPresenter 的實(shí)現(xiàn)瞧甩。

package com.wf.mvp.kotlin.presenter

import ......

/**
 * MvpMode -> com.wf.mvp.kotlin.presenter -> Presenter
 * @Author: wf-pc
 * @Date: 2020-05-10 16:13
 * <p>
 * Mvp's p-layer basic Presenter, used to attach activity and implement common functions.
 */
abstract class IPresenter<V : Ui> : Presenter {

    /**
     * The instance object of V layer.
     */
    protected var mView: V? = null

    /**
     * The instance object of main thread handler.
     */
    protected var mUiHandler: UiHandler? = null

    /**
     * Establish a reference relationship with the V layer.
     * 
     * @param view The instance object of V layer, must be a subclass of Ui.
     * @param handler The instance object of main thread handler.
     */
    @Suppress("UNCHECKED_CAST")
    override fun <U : Ui> attachView(view: U, handler: UiHandler?) {
        mView = view as V;
        mUiHandler = handler;
        mUiHandler?.attachRefs(this)
        init()
    }

    /**
     * Release references to layer V.
     */
    override fun detachView() {
        release()
        mUiHandler?.detachRefs()
        mUiHandler = null
        mView = null
    }

    /**
     * Only initialization code can be written here, no other operations can be performed.
     * For example, initialize the M layer instance object.
     */
    protected abstract fun init()

    /**
     * Used to release resources.
     */
    protected abstract fun release()

    ......
}

??上面的內(nèi)容注釋都寫的挺詳細(xì)的钉跷,IPresenter 抽象類里面持有了兩個(gè) V 層的實(shí)例對(duì)象 mView 和 mUiHandler。

??通過泛型方法 attachView 將 V 層的實(shí)例對(duì)象和 UI 線程的 Handler 對(duì)象傳遞到 P 層肚逸,使得 P 層持有了 V 層的引用爷辙,這樣 P 層就能通過 mView 對(duì)象來調(diào)用 V 層的接口方法了彬坏。而 detachView 則是用來與 V 層解除聯(lián)系和釋放相關(guān)的資源。

??在 attachView 和 detachView 里面分別預(yù)留了 init 和 release 抽象方法膝晾,子類通過實(shí)現(xiàn)這兩個(gè)接口來處理各自業(yè)務(wù)具體的初始化和釋放工作栓始。

??最后,省略掉的是 Impl 里面定義的公共接口血当,其中除了 onHandleMessage(msg: Message) 需要 Presenter 自己實(shí)現(xiàn)用來處理 Handler 消息以外幻赚,其余的全都是通過 mView 去調(diào)用了 V 層的實(shí)現(xiàn),其主要目的是方便 P 層使用臊旭。

3落恼、抽象層 View

abs_view.png

??此層定義了四個(gè)類,其中 N 開頭的是指的不需要 P 層的業(yè)務(wù)模塊离熏,例如應(yīng)用的啟動(dòng)頁面等佳谦,在 MVP 模式下理論上是不推薦使用的,哪怕是定義一個(gè)空的 P 層滋戳,故本文我們不做詳細(xì)介紹钻蔑。而 IActivity 和 IFragment 的實(shí)現(xiàn)邏輯是一樣的,只不過一個(gè)是針對(duì) Activity奸鸯,一個(gè)是針對(duì) Fragment 而已咪笑,所以我們選擇分析 IActivity 即可。

package com.wf.mvp.kotlin.view

import ......

/**
 * MvpMode -> com.wf.mvp.kotlin.view -> IActivity
 * @Author: wf-pc
 * @Date: 2020-05-10 16:42
 * <p>
 * Mvp's v-layer basic Activity, used to bind presenter and implement common functions.
 */
abstract class IActivity<P : Presenter> : Activity(), Ui {

    /**
     * The instance object of P layer.
     */
    protected var mPresenter: P? = null

    /**
     * The instance object of UI thread handler.
     */
    protected var mUiHandler: UiHandler? = null

    private var mToast: Toast? = null
    private var mLoading: ProgressDialog? = null

    override fun onCreate(savedInstanceState: Bundle?) {
        beforeCreate()
        super.onCreate(savedInstanceState)
        setContentView(bindLayoutId())
        initView(intent)
        attachPresenter()
        initListener()
        initData()
    }

    override fun onNewIntent(intent: Intent?) {
        super.onNewIntent(intent)
        setIntent(intent)
    }

    override fun onDestroy() {
        super.onDestroy()
        detachPresenter()
        release()
    }


    /**
     * Binding P layer instance object.
     * Obtain the generic class type through reflection, and then instantiate the Presenter object.
     */
    @Suppress("UNCHECKED_CAST")
    override fun attachPresenter() {
        mUiHandler = UiHandler()
        mUiHandler?.attachRefs(this)
        mPresenter = try {
            val type = this.javaClass.genericSuperclass as ParameterizedType
            val tClass: Class<P> = type.actualTypeArguments[0] as Class<P>
            tClass.newInstance()
        } catch (e: Exception) {
            DefaultIPresenter() as P
        }
        mPresenter?.attachView(this, mUiHandler)
    }

    /**
     * Unbind the P layer instance object.
     */
    override fun detachPresenter() {
        mUiHandler?.detachRefs()
        mPresenter?.detachView()
        mUiHandler = null
        mPresenter = null
    }

    /**
     * Used to do something before Create.
     */
    protected open fun beforeCreate() {}

    /**
     * Used to bind layout files.
     */
    protected abstract fun bindLayoutId(): Int

    /**
     * Used to initialize view.
     */
    protected abstract fun initView(intent: Intent?)

    /**
     * Used to initialize listener.
     */
    protected abstract fun initListener()

    /**
     * Used to initialize data.
     */
    protected abstract fun initData()

    /**
     * Used to release resources.
     */
    protected abstract fun release()

    /**
     * It is not defined as an abstract function here,
     * it is recommended to put the message to the Presenter layer for processing.
     */
    override fun onHandleMessage(msg: Message) {}

    ......
}

??抽象 IActivity 繼承至 Activity 和實(shí)現(xiàn)了 Ui 接口娄涩,代表著 IActivity 擁有了 V 層的控制能力窗怒。同樣的,IActivity 持有了一個(gè) Presenter 的實(shí)例對(duì)象和一個(gè) UiHandler 實(shí)例對(duì)象钝满,在 V 層就是通過這個(gè) mPresenter 來調(diào)用 P 層的相關(guān)接口處理業(yè)務(wù)邏輯兜粘。

??首先,我們?cè)?onCreate 方法里面進(jìn)行了功能代碼模塊的劃分弯蚜,分別預(yù)留出了相應(yīng)的接口來供其子類實(shí)現(xiàn),各個(gè)接口是用來做什么的上面也有詳細(xì)的注釋剃法,就不一一翻譯了碎捺。

??接下來,我們著重分析一下 attachPresenter 和 detachPresenter贷洲,不知道大家還記得不收厨?這兩個(gè)接口是定義在接口層的 Ui 接口里面的。

  • 在 attachPresenter 里面主要干了兩個(gè)事兒:
    (1)實(shí)例化了 UiHandler 對(duì)象并將當(dāng)前對(duì)象也就是 this (這里要說明一下:抽象類是不能實(shí)例化的优构,因此是沒有 this 對(duì)象的诵叁,而這里的 this 其實(shí)是會(huì)向下轉(zhuǎn)型為它的具體的子類對(duì)象)傳遞給它,而在 UiHandler 里面會(huì)回調(diào) this 的 onHandleMessage 方法钦椭。
    (2)通過反射獲取到泛型參數(shù)的 class 類型拧额,進(jìn)而通過 class 實(shí)例化了 mPresenter 對(duì)象碑诉,緊接著調(diào)用 mPresenter 的 attachView 將 this 和 mUiHandler 傳遞給 P 層,從而建立了 P 層和 V 層的綁定關(guān)系侥锦。其中进栽,當(dāng)反射出錯(cuò)的時(shí)候會(huì)默認(rèn)綁定一個(gè)空實(shí)現(xiàn)的 DefaultIPresenter。

  • 相應(yīng)的 detachPresenter 里面也干了兩個(gè)事兒:
    (1)釋放 UiHandler 資源恭垦。
    (2)斷開 V 層與 P 層的聯(lián)系快毛。

??最后,onHandleMessage(msg: Message) 有一段特殊的說明:建議消息處理放到 P 層去番挺,故此處采用了空實(shí)現(xiàn)唠帝。為什么這么建議呢?因?yàn)榇蠖鄶?shù)情況下消息也是用來處理業(yè)務(wù)邏輯的玄柏,只有極少數(shù)是用來作用于 UI的襟衰。其余省略掉的是 Impl 里面定義的公共接口,都很簡單禁荸,這里不做過多說明右蒲。

4、UiHandler

package com.wf.mvp.kotlin.customize

import android.os.Handler
import android.os.Message
import com.wf.mvp.kotlin.impl.Impl

/**
 * MvpMode -> com.wf.mvp.kotlin.customize -> UiHandler
 * @Author: wf-pc
 * @Date: 2020-05-10 15:11
 */
class UiHandler: Handler(){

    private var mRefsList = ArrayList<Impl>()

    fun attachRefs(refs: Impl){
        mRefsList.add(refs)
    }

    fun detachRefs(){
        removeCallbacksAndMessages(null)
        mRefsList.clear()
    }

    override fun handleMessage(msg: Message) {
        super.handleMessage(msg)
        for (refs in mRefsList){
            refs.onHandleMessage(msg)
        }
    }
}

??UiHandler 是我們實(shí)現(xiàn)的一個(gè)自定義 Handler赶熟,這里有一點(diǎn)需要注意:我們只是取名為 UiHandler瑰妄,并不是說它一定就是 UI 線程的 Handler。

??其中我們通過一個(gè) List<Impl> 來存儲(chǔ)它所持有的外部引用映砖,通過 attachRefs 來添加引用间坐,detachRefs 來釋放引用。

??在 handleMessage 方法里面將消息回調(diào)給 List<Impl> 里面的引用的 onHandleMessage 方法邑退,因此我們這里的引用都必須是實(shí)現(xiàn)了 Impl 接口的對(duì)象竹宋。


??到這里,我們這個(gè)框架的封裝就講完了地技,整個(gè)框架主要是搭建了 V 層和 P 層的聯(lián)系蜈七,由于我們講過 M 層理論上是要獨(dú)立于項(xiàng)目,故不對(duì)其進(jìn)行封裝莫矗。后續(xù)我們?cè)陧?xiàng)目開發(fā)中只需要將 Activity 繼承至 IActivity 飒硅、Fragment 繼承至 IFragment、Presenter 繼承至 IPresenter 就可以使用 mViewmPresenter 來進(jìn)行相互調(diào)用了作谚。


四三娩、使用


1、索引 contract

package com.wf.mvp.mode.kotlin.contract

/**
 * MvpMode -> com.wf.mvp.mode.kotlin.contract -> KotlinContract
 *
 * @Author: wf-pc
 * @Date: 2020-05-10 17:55
 */
interface KotlinContract {
    interface View {
        fun setText(text: String?)
        fun setTextColor(color: Int)
    }

    interface Presenter {
        fun initText(text: String?);
        fun getInfo()
    }
}

??contract 翻譯過來就是合約的意思妹懒,他的功能就類似于我們字典的索引雀监,在我們不熟悉這個(gè)模塊的時(shí)候,我們只需要看這個(gè)文件就能大概知道這個(gè)模塊里面有些什么內(nèi)容眨唬。雖然不是必須的会前,但是強(qiáng)烈建議加上好乐。

2、V 層 KotlinIActivity

package com.wf.mvp.mode.kotlin.view

import ......

class KotlinIActivity : IActivity<KotlinIPresenter>(), KotlinContract.View {

    override fun bindLayoutId(): Int {
        return R.layout.activity_kotlin
    }

    override fun initView(intent: Intent?) {

    }

    override fun initListener() {
        btn_kotlin.setOnClickListener {
            mPresenter?.getInfo()
        }
    }

    @SuppressLint("SetTextI18n")
    override fun initData() {
        // 獲取關(guān)聯(lián)的 P 層的具體 class 類型
        mPresenter?.initText("${mPresenter?.javaClass}")
    }

    override fun release() {
    }

    override fun setText(text: String?) {
        tv_kotlin.text = text ?: "null"
    }

    override fun setTextColor(color: Int) {
        tv_kotlin.setTextColor(color)
    }

}

??KotlinIActivity 為一個(gè)簡單的 V 層的實(shí)現(xiàn)回官,它實(shí)現(xiàn)了 IActivity 和 KotlinContract.View 索引曹宴,綁定了 KotlinIPresenter。我們可以看到歉提,除了我們封裝時(shí)預(yù)留的接口外笛坦,KotlinIActivity 只有兩個(gè) set 方法,這就是我們封裝的時(shí)候講到的 V 層只做 UI 的更新和響應(yīng)苔巨,具體的業(yè)務(wù)邏輯通過 mPresenter 交給 P 層去處理版扩。

3、P 層 KotlinIPresenter

package com.wf.mvp.mode.kotlin.presenter

import ......

/**
 * MvpMode -> com.wf.mvp.mode -> MainPresenter
 *
 * @Author: wf-pc
 * @Date: 2020-05-09 22:06
 */
class KotlinIPresenter : IPresenter<KotlinIActivity>(), KotlinContract.Presenter {

    private var mText: StringBuilder = StringBuilder()

    override fun init() {
    }

    override fun release() {

    }

    override fun onHandleMessage(msg: Message) {
        if (msg.what == 1002) {
            showLoading("1002")
        }
    }

    override fun initText(text: String?) {
        mText.clear()
        mText.append(mView?.javaClass).append("\n")
        mText.append(text).append("\n\n")
        mView?.setText(mText.toString())
    }

    override fun getInfo() {
        mText.append(getResources().toString()).append("\n")
        mText.append(getString(R.string.app_name)).append("\n")
        mText.append(getString(R.string.app_hello, "kotlin")).append("\n")
        mText.append("dimen_720p=${getDimension(R.dimen.dimen_720p)}").append("\n")
        mText.append(getDrawable(R.mipmap.ic_launcher).toString()).append("\n")

        mView?.setText(mText.toString())
        mView?.setTextColor(getColor(R.color.colorPrimary))

        Thread(Runnable {
            try {
                Thread.sleep(3000);
            } catch (e: InterruptedException) {
                e.printStackTrace();
            }

            runOnUiThread {
                showToast("Hello Kotlin !");
            }

            try {
                Thread.sleep(3000);
            } catch (e: InterruptedException) {
                e.printStackTrace();
            }

            mUiHandler?.sendEmptyMessage(1002);

            mUiHandler?.postDelayed({
                hideLoading();
                toggleKeyboard();
            }, 3000)

            mUiHandler?.postDelayed({
                toggleKeyboard();
            }, 6000)

        }).start()
    }
}

??KotlinIPresenter 為一個(gè)簡單的 P 層的實(shí)現(xiàn)侄泽,它實(shí)現(xiàn)了 IPresenter 和 KotlinContract.Presenter 索引礁芦,綁定了 KotlinIActivity。我們可以看到悼尾,除了我們封裝時(shí)預(yù)留的接口外柿扣,這里面做了很多的數(shù)據(jù)獲取和邏輯操作,最終通過 mView 將結(jié)果傳遞到 V 層顯示闺魏。

4未状、M 層實(shí)例
??我們說了 M 層是獨(dú)立于項(xiàng)目的,這里就不做演示實(shí)例了析桥,前面的內(nèi)容已經(jīng)講的很清楚了司草。


總結(jié)


??以上內(nèi)容就是我個(gè)人對(duì) MVP 模式的理解和簡單的封裝,模式或者架構(gòu)無非是一種規(guī)范或者約束泡仗,具體的實(shí)現(xiàn)仁者見仁智者見智埋虹,以上的內(nèi)容僅為本人的個(gè)人見解和思考,有不對(duì)的娩怎、可以優(yōu)化的或者更好的建議搔课,歡迎大家評(píng)論留言!

Github地址:https://github.com/WangFion/mvp-mode

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
禁止轉(zhuǎn)載截亦,如需轉(zhuǎn)載請(qǐng)通過簡信或評(píng)論聯(lián)系作者辣辫。
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市魁巩,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌姐浮,老刑警劉巖谷遂,帶你破解...
    沈念sama閱讀 222,252評(píng)論 6 516
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異卖鲤,居然都是意外死亡肾扰,警方通過查閱死者的電腦和手機(jī)畴嘶,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,886評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來集晚,“玉大人窗悯,你說我怎么就攤上這事⊥蛋危” “怎么了蒋院?”我有些...
    開封第一講書人閱讀 168,814評(píng)論 0 361
  • 文/不壞的土叔 我叫張陵,是天一觀的道長莲绰。 經(jīng)常有香客問我欺旧,道長,這世上最難降的妖魔是什么蛤签? 我笑而不...
    開封第一講書人閱讀 59,869評(píng)論 1 299
  • 正文 為了忘掉前任辞友,我火速辦了婚禮,結(jié)果婚禮上震肮,老公的妹妹穿的比我還像新娘称龙。我一直安慰自己,他們只是感情好戳晌,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,888評(píng)論 6 398
  • 文/花漫 我一把揭開白布鲫尊。 她就那樣靜靜地躺著,像睡著了一般躬厌。 火紅的嫁衣襯著肌膚如雪马昨。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,475評(píng)論 1 312
  • 那天扛施,我揣著相機(jī)與錄音鸿捧,去河邊找鬼。 笑死疙渣,一個(gè)胖子當(dāng)著我的面吹牛匙奴,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播妄荔,決...
    沈念sama閱讀 41,010評(píng)論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼泼菌,長吁一口氣:“原來是場噩夢(mèng)啊……” “哼!你這毒婦竟也來了啦租?” 一聲冷哼從身側(cè)響起哗伯,我...
    開封第一講書人閱讀 39,924評(píng)論 0 277
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎篷角,沒想到半個(gè)月后焊刹,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,469評(píng)論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,552評(píng)論 3 342
  • 正文 我和宋清朗相戀三年虐块,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了俩滥。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,680評(píng)論 1 353
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡贺奠,死狀恐怖霜旧,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情儡率,我是刑警寧澤挂据,帶...
    沈念sama閱讀 36,362評(píng)論 5 351
  • 正文 年R本政府宣布,位于F島的核電站喉悴,受9級(jí)特大地震影響棱貌,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜箕肃,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,037評(píng)論 3 335
  • 文/蒙蒙 一婚脱、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧勺像,春花似錦障贸、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,519評(píng)論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至殃姓,卻和暖如春袁波,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背蜗侈。 一陣腳步聲響...
    開封第一講書人閱讀 33,621評(píng)論 1 274
  • 我被黑心中介騙來泰國打工篷牌, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人踏幻。 一個(gè)月前我還...
    沈念sama閱讀 49,099評(píng)論 3 378
  • 正文 我出身青樓枷颊,卻偏偏與公主長得像,于是被迫代替她去往敵國和親该面。 傳聞我的和親對(duì)象是個(gè)殘疾皇子夭苗,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,691評(píng)論 2 361