原文地址: https://gold.xitu.io/post/58b25e588d6d810057ed3659
前言(最後奉上福利)
自從Google
在去年放出MVP的官方Sample後,越來越多的人開始加入MVP大軍,MVP可謂在16年大放異彩,我也乘勢推出了我的MVP框架狂刷了一波存在感
問題
但在使用當中我也發現了諸多弊端,導致很多初學者,在寫過Sample後,就再也沒在自己的專案中使用過MVP
MVP需要建立太多的類和介面,並且每次通訊都需要繁瑣的通過介面傳遞資訊
這是大多數使用過MVP的朋友,最能感受到的,最近在幫公司技術面,我也時常問應聘者,能否嘗試著解決這些問題?
解決方案
其實我之前已經有一套解決方案,其實也不能叫解決,只能說是緩解?
硬解決
所謂硬解決,便是使用比較暴力的方式?,通過Template自動生成需要的類和介面,這樣少去了頻繁的複製貼上
軟解決
所謂軟解決,那就要動動腦子,稍微優雅的解決了?
-
對於邏輯簡單的頁面可以不使用Presenter,直接在Activity或Fragment中處理邏輯,在Presenter中如果不需要處理資料,也可以不實用Model
-
Presenter和Model都可以無限制的重用,所以MVP的劃分不需要太細粒度,稍微粗粒度一點,即不需要每個Activity或Fragment都給他劃分一套MVP,可以幾個Activity或Fragment使用同一個Presenter(使用同一個類不是同一個物件,這個Presenter含有可以共用的邏輯),也可一個Activity或Fragment根據不同的需求持有多個不同型別的Presenter物件,Model層同理,這樣靈活使用,可以在一定程度上緩解MVP類和介面較多的缺點
並沒有完全解決問題
通過上面的解決方案,是可以一定的緩解MVP的缺點,但是並不能完全解決上述缺點
比如想重用Presenter,Presenter就必須只含有公用的邏輯,而實際專案中公用的邏輯並不是那麼多,所以能減少的類和介面也是很有限的,如果強制將不同頁面的邏輯放在同一個Prsenter中,來達到重用的目的,那麼每個Activity會被迫實現許多並不需要的方法,得不償失
尋求解決方法
因此我看了大多數MVP框架,尋求如何徹底改善這個問題,像支付寶團隊使用的T-MVP框架,是通過將Activity或Fragment作為Presenter,將UI操作抽到Delegate中,作為View層
TheMVP優點
這樣做的好處是,不僅可以少寫很多類,而且Presenter直接就可以和Activity或Fragment的生命週期做繫結(但使用 Google 最新發布的 Android 架構元件當中的 Lifecycles 就已經可以非常簡單的讓任何一個類與 Activity 或 Fragment 的生命週期做繫結, 包括 Presenter, 並且 Support Library v26.1.0 已經內嵌這個元件, 不用額外的引入這個元件),且可以隨便重用View(但大多數場景都是重用Presenter,因為View層變化總是比其它層頻繁)
TheMVP缺點
缺點就是不能重用Presenter,並且對於Presenter的實現有限制,必須是Activity或Fragment,如果要在其他地方實現Presenter,如Adapter,Dialog就必須根據它的特性重新寫對應的Presenter基類
因為Presenter基類繼承了Activity或Fragment,如果我們需要通過繼承使用其他Activity或Fragment,那就又需要修改Presenter基類,一旦某個Activity需要繼承其他不同的Activity,那又需要重新建立一個基於此Activity的Presenter基類,導致一個Activity或Fragment有多個不同的Presenter基類
分析問題,解決問題
總結一下MVP的缺點
1.粒度不好控制,控制不好就需要寫過多的類和介面
2.如要重用presenter可能會實現過多不需要的介面
3.Presenter和View通過介面通訊太繁瑣,一旦View層需要的資料變化,那麼對應的介面就需要更改
複製程式碼
想要在根本上解決以上問題,我想必須換個思路,能不能通過改變傳統MVP架構來解決這些問題?
實現MVP現階段有兩種方式,各有優缺點:
一個是將Activity或Fragment作為Presenter,抽象一個View層出來
一個是將Activity或Fragment作為View,抽象一個Presenter層出來
我想達到重用Presenter的目的,自然選擇了後者
在某一天我突然想到了Handler,他只通過一個handleMessage方法,根據Message的what欄位處理不同的操作,這樣向上層提供一個統一的入口,下層不管如何改變並不會影響上層,並且同樣可以實現多種的操作
於是根據這個思想,我重新改造了MVP架構,讓Presenter通過Message和View層通訊
如何實現
先上張圖
具體做法是,VIEW層持有Presenter物件,當使用者請求一個事件,則呼叫Presenter中的方法,並把持有View引用Message傳給此方法,此方法處理完請求邏輯後將資料封裝到Message中,並通過Message持有的View引用回撥View的handleMessage方法,讓View做不同的操作,最後釋放掉Message的所有引用,放入訊息池
Presenter並不直接持有View,方法執行完即表示和View的關係解除
和Handler的原理很像,Handler是將訊息放入MessageQueue,Looper去輪循處理訊息,我這裡是將訊息放入,Presenter的方法,並立即處理訊息
總結
這樣就能解決上述的缺點:
-
少寫了很多類和介面
-
並且Presenter只需要通過handleMessage一個方法與View通訊,也就不用繁瑣的一直新增介面方法,只需要一個Message引數,通過Message封裝資料,即使View需要的資料型別發生改變,也不需要更改任何方法,所以也不會影響上層呼叫
-
隨便重用Presenter,即使你一個Activity,重用10個不同的Presenter,那也只用實現一個handleMessage方法,不需要實現View中其他用不到的方法,通過一個方法同樣能做到不同的操作(傳統MVP一個頁面對應一個Presenter,其實大多數Presenter只有一兩個方法,這樣導致存在大量程式碼寥寥無幾的Presenter,你有想過將相近的邏輯都寫到一個Presenter中,一直重用Presenter有多爽嗎?)
-
當Presenter中的方法需要Activity傳遞一些資料時,也可以將資料封裝到Message中傳給Presenter,這樣即使需要的資料型別發生改變,也不需要更改方法,所以也不會影響上層呼叫
只有能不斷的靈活重用,才能感受到MVP的強大之處
當然很多不同的邏輯都寫在一個Presenter中,雖然可以少寫很多類,但是後面的擴充套件性肯定不好,所以這個粒度需要自己控制,但是對於外包專案簡直是福音
說了這麼多還是要看看Demo,具體該怎麼做吧?
公眾號
掃碼關注我的公眾號 JessYan,一起學習進步,如果框架有更新,我也會在公眾號上第一時間通知大家
Hello 我叫 JessYan,如果您喜歡我的文章,可以在以下平臺關注我
- 個人主頁: jessyan.me
- GitHub: github.com/JessYanCodi…
- 掘金: juejin.im/user/57a9db…
- 簡書: www.jianshu.com/u/1d0c0bc63…
- 微博: weibo.com/u/178626251…
-- The end