傳統MVP用在專案中是真的方便還是累贅?

JessYan發表於2017-02-26

原文地址: https://gold.xitu.io/post/58b25e588d6d810057ed3659

前言(最後奉上福利)

自從Google在去年放出MVP官方Sample後,越來越多的人開始加入MVP大軍,MVP可謂在16年大放異彩,我也乘勢推出了我的MVP框架狂刷了一波存在感

問題

但在使用當中我也發現了諸多弊端,導致很多初學者,在寫過Sample後,就再也沒在自己的專案中使用過MVP

MVP需要建立太多的類和介面,並且每次通訊都需要繁瑣的通過介面傳遞資訊

這是大多數使用過MVP的朋友,最能感受到的,最近在幫公司技術面,我也時常問應聘者,能否嘗試著解決這些問題?

解決方案

其實我之前已經有一套解決方案,其實也不能叫解決,只能說是緩解?

硬解決

所謂硬解決,便是使用比較暴力的方式?,通過Template自動生成需要的類和介面,這樣少去了頻繁的複製貼上

軟解決

所謂軟解決,那就要動動腦子,稍微優雅的解決了?

  1. 對於邏輯簡單的頁面可以不使用Presenter,直接在ActivityFragment中處理邏輯,在Presenter中如果不需要處理資料,也可以不實用Model

  2. PresenterModel都可以無限制的重用,所以MVP的劃分不需要太細粒度,稍微粗粒度一點,即不需要每個ActivityFragment都給他劃分一套MVP,可以幾個ActivityFragment使用同一個Presenter(使用同一個類不是同一個物件,這個Presenter含有可以共用的邏輯),也可一個ActivityFragment根據不同的需求持有多個不同型別的Presenter物件,Model層同理,這樣靈活使用,可以在一定程度上緩解MVP類和介面較多的缺點

並沒有完全解決問題

通過上面的解決方案,是可以一定的緩解MVP的缺點,但是並不能完全解決上述缺點

比如想重用Presenter,Presenter就必須只含有公用的邏輯,而實際專案中公用的邏輯並不是那麼多,所以能減少的類和介面也是很有限的,如果強制將不同頁面的邏輯放在同一個Prsenter中,來達到重用的目的,那麼每個Activity會被迫實現許多並不需要的方法,得不償失

尋求解決方法

因此我看了大多數MVP框架,尋求如何徹底改善這個問題,像支付寶團隊使用的T-MVP框架,是通過將ActivityFragment作為Presenter,將UI操作抽到Delegate中,作為View

TheMVP優點

這樣做的好處是,不僅可以少寫很多類,而且Presenter直接就可以和ActivityFragment的生命週期做繫結(但使用 Google 最新發布的 Android 架構元件當中的 Lifecycles 就已經可以非常簡單的讓任何一個類與 ActivityFragment 的生命週期做繫結, 包括 Presenter, 並且 Support Library v26.1.0 已經內嵌這個元件, 不用額外的引入這個元件),且可以隨便重用View(但大多數場景都是重用Presenter,因為View層變化總是比其它層頻繁)

TheMVP缺點

缺點就是不能重用Presenter,並且對於Presenter的實現有限制,必須是ActivityFragment,如果要在其他地方實現Presenter,如Adapter,Dialog就必須根據它的特性重新寫對應的Presenter基類

因為Presenter基類繼承了ActivityFragment,如果我們需要通過繼承使用其他ActivityFragment,那就又需要修改Presenter基類,一旦某個Activity需要繼承其他不同的Activity,那又需要重新建立一個基於此ActivityPresenter基類,導致一個ActivityFragment有多個不同的Presenter基類

分析問題,解決問題

總結一下MVP的缺點

1.粒度不好控制,控制不好就需要寫過多的類和介面
2.如要重用presenter可能會實現過多不需要的介面
3.Presenter和View通過介面通訊太繁瑣,一旦View層需要的資料變化,那麼對應的介面就需要更改

複製程式碼

想要在根本上解決以上問題,我想必須換個思路,能不能通過改變傳統MVP架構來解決這些問題?

實現MVP現階段有兩種方式,各有優缺點:

一個是將ActivityFragment作為Presenter,抽象一個View層出來

一個是將ActivityFragment作為View,抽象一個Presenter層出來

我想達到重用Presenter的目的,自然選擇了後者

在某一天我突然想到了Handler,他只通過一個handleMessage方法,根據Messagewhat欄位處理不同的操作,這樣向上層提供一個統一的入口,下層不管如何改變並不會影響上層,並且同樣可以實現多種的操作

於是根據這個思想,我重新改造了MVP架構,讓Presenter通過MessageView層通訊

如何實現

先上張圖

傳統MVP用在專案中是真的方便還是累贅?

具體做法是,VIEW層持有Presenter物件,當使用者請求一個事件,則呼叫Presenter中的方法,並把持有View引用Message傳給此方法,此方法處理完請求邏輯後將資料封裝到Message中,並通過Message持有的View引用回撥ViewhandleMessage方法,讓View做不同的操作,最後釋放掉Message的所有引用,放入訊息池

Presenter並不直接持有View,方法執行完即表示和View的關係解除

Handler的原理很像,Handler是將訊息放入MessageQueue,Looper去輪循處理訊息,我這裡是將訊息放入,Presenter的方法,並立即處理訊息

總結

這樣就能解決上述的缺點:

  1. 少寫了很多類和介面

  2. 並且Presenter只需要通過handleMessage一個方法與View通訊,也就不用繁瑣的一直新增介面方法,只需要一個Message引數,通過Message封裝資料,即使View需要的資料型別發生改變,也不需要更改任何方法,所以也不會影響上層呼叫

  3. 隨便重用Presenter,即使你一個Activity,重用10個不同的Presenter,那也只用實現一個handleMessage方法,不需要實現View中其他用不到的方法,通過一個方法同樣能做到不同的操作(傳統MVP一個頁面對應一個Presenter,其實大多數Presenter只有一兩個方法,這樣導致存在大量程式碼寥寥無幾的Presenter,你有想過將相近的邏輯都寫到一個Presenter中,一直重用Presenter有多爽嗎?)

  4. Presenter中的方法需要Activity傳遞一些資料時,也可以將資料封裝到Message中傳給Presenter,這樣即使需要的資料型別發生改變,也不需要更改方法,所以也不會影響上層呼叫

只有能不斷的靈活重用,才能感受到MVP的強大之處

當然很多不同的邏輯都寫在一個Presenter中,雖然可以少寫很多類,但是後面的擴充套件性肯定不好,所以這個粒度需要自己控制,但是對於外包專案簡直是福音

說了這麼多還是要看看Demo,具體該怎麼做吧?

Go!覺得好一定要右上角Star哦!

公眾號

掃碼關注我的公眾號 JessYan,一起學習進步,如果框架有更新,我也會在公眾號上第一時間通知大家

傳統MVP用在專案中是真的方便還是累贅?


Hello 我叫 JessYan,如果您喜歡我的文章,可以在以下平臺關注我

-- The end

相關文章