原文地址: http://www.reibang.com/p/ac51c9b88af3
qq群:301733278
前言(最后奉上福利)
自從Google
在去年放出MVP的官方Sample后,越來越多的人開始加入MVP大軍,MVP可謂在16年大放異彩,我也乘勢推出了我的MVP框架狂刷了一波存在感
問題
但在使用當中我也發(fā)現(xiàn)了諸多弊端,導(dǎo)致很多初學(xué)者,在寫過Sample后,就再也沒在自己的項目中使用過MVP
MVP需要創(chuàng)建太多的類和接口,并且每次通信都需要繁瑣的通過接口傳遞信息
這是大多數(shù)使用過MVP的朋友,最能感受到的,最近在幫公司技術(shù)面,我也時常問應(yīng)聘者,能否嘗試著解決這些問題?
解決方案
其實我之前已經(jīng)有一套解決方案,其實也不能叫解決,只能說是緩解
硬解決
所謂硬解決,便是使用比較暴力的方式,通過Template自動生成需要的類和接口,這樣少去了頻繁的復(fù)制粘貼
軟解決
所謂軟解決,那就要動動腦子,稍微優(yōu)雅的解決了
對于邏輯簡單的頁面可以不使用Presenter,直接在Activity或Fragment中處理邏輯,在Presenter中如果不需要處理數(shù)據(jù),也可以不使用Model
Presenter和Model都可以無限制的重用,所以MVP的劃分不需要太細粒度,稍微粗粒度一點,即不需要每個Activity或Fragment都給他劃分一套MVP,可以幾個Activity或Fragment使用同一個Presenter(使用同一個類不是同一個對象,這個Presenter含有可以共用的邏輯),也可一個Activity或Fragment根據(jù)不同的需求持有多個不同類型的Presenter對象,Model層同理,這樣靈活使用,可以在一定程度上緩解MVP類和接口較多的缺點
并沒有完全解決問題
通過上面的解決方案,是可以一定的緩解MVP的缺點,但是并不能完全解決上述缺點
比如想重用Presenter,Presenter就必須只含有公用的邏輯,而實際項目中公用的邏輯并不是那么多,所以能減少的類和接口也是很有限的,如果強制將不同頁面的邏輯放在同一個Prsenter中,來達到重用的目的,那么每個Activity會被迫實現(xiàn)許多并不需要的方法,得不償失
尋求解決方法
因此我看了大多數(shù)MVP框架,尋求如何徹底改善這個問題,像支付寶團隊使用的TheMVP框架,是通過將Activity或Fragment作為Presenter,將UI操作抽到Delegate中,作為View層
TheMVP優(yōu)點
這樣做的好處是,不僅可以少寫很多類,而且Presenter直接就可以和Activity或Fragment的生命周期做綁定 (但使用 Google 最新發(fā)布的 Android 架構(gòu)組件當中的 Lifecycles 就已經(jīng)可以非常簡單的讓任何一個類與 Activity 或 Fragment 的生命周期做綁定, 包括 Presenter, 并且 Support Library v26.1.0 已經(jīng)內(nèi)嵌這個組件, 不用額外的引入這個組件), 且可以隨便重用View(但大多數(shù)場景都是重用Presenter,因為View層變化總是比其它層頻繁)
TheMVP缺點
缺點就是不能重用Presenter,并且對于Presenter的實現(xiàn)有限制,必須是Activity或Fragment,如果要在其他地方實現(xiàn)Presenter,如Adapter,Dialog就必須根據(jù)它的特性重新寫對應(yīng)的Presenter基類
因為Presenter基類繼承了Activity或Fragment,如果我們需要通過繼承使用其他Activity或Fragment,那就又需要修改Presenter基類,一旦某個Activity需要繼承其他不同的Activity,那又需要重新創(chuàng)建一個基于此Activity的Presenter基類,導(dǎo)致一個Activity或Fragment有多個不同的Presenter基類
分析問題,解決問題
總結(jié)一下MVP的缺點
1.粒度不好控制,控制不好就需要寫過多的類和接口
2.如要重用presenter可能會實現(xiàn)過多不需要的接口
3.Presenter和View通過接口通信太繁瑣,一旦View層需要的數(shù)據(jù)變化,那么對應(yīng)的接口就需要更改
想要在根本上解決以上問題,我想必須換個思路,能不能通過改變傳統(tǒng)MVP架構(gòu)來解決這些問題?
實現(xiàn)MVP現(xiàn)階段有兩種方式,各有優(yōu)缺點:
一個是將Activity或Fragment作為Presenter,抽象一個View層出來
一個是將Activity或Fragment作為View,抽象一個Presenter層出來
我想達到重用Presenter的目的,自然選擇了后者
在某一天我突然想到了Handler,他只通過一個handleMessage方法,根據(jù)Message的what字段處理不同的操作,這樣向上層提供一個統(tǒng)一的入口,下層不管如何改變并不會影響上層,并且同樣可以實現(xiàn)多種的操作
于是根據(jù)這個思想,我重新改造了MVP架構(gòu),讓Presenter通過Message和View層通信
如何實現(xiàn)
先上張圖
具體做法是,VIEW層持有Presenter對象,當用戶請求一個事件,則調(diào)用Presenter中的方法,并把持有View引用Message傳給此方法,此方法處理完請求邏輯后將數(shù)據(jù)封裝到Message中,并通過Message持有的View引用回調(diào)View的handleMessage方法,讓View做不同的操作,最后釋放掉Message的所有引用,放入消息池
Presenter并不直接持有View,方法執(zhí)行完即表示和View的關(guān)系解除
和Handler的原理很像,Handler是將消息放入MessageQueue,Looper去輪循處理消息,我這里是將消息放入,Presenter的方法,并立即處理消息
總結(jié)
這樣就能解決上述的缺點:
少寫了很多類和接口
并且Presenter只需要通過handleMessage一個方法與View通信,也就不用繁瑣的一直添加接口方法,只需要一個Message參數(shù),通過Message封裝數(shù)據(jù),即使View需要的數(shù)據(jù)類型發(fā)生改變,也不需要更改任何方法,所以也不會影響上層調(diào)用
隨便重用Presenter,即使你一個Activity,重用10個不同的Presenter,那也只用實現(xiàn)一個handleMessage方法,不需要實現(xiàn)View中其他用不到的方法,通過一個方法同樣能做到不同的操作(傳統(tǒng)MVP一個頁面對應(yīng)一個Presenter,其實大多數(shù)Presenter只有一兩個方法,這樣導(dǎo)致存在大量代碼寥寥無幾的Presenter,你有想過將相近的邏輯都寫到一個Presenter中,一直重用Presenter有多爽嗎)
當Presenter中的方法需要Activity傳遞一些數(shù)據(jù)時,也可以將數(shù)據(jù)封裝到Message中傳給Presenter,這樣即使需要的數(shù)據(jù)類型發(fā)生改變,也不需要更改方法,所以也不會影響上層調(diào)用
只有能不斷的靈活重用,才能感受到MVP的強大之處
當然很多不同的邏輯都寫在一個Presenter中,雖然可以少寫很多類,但是后面的擴展性肯定不好,所以這個粒度需要自己控制,但是對于外包項目簡直是福音
說了這么多還是要看看Demo,具體該怎么做吧蚓胸?
公眾號
掃碼關(guān)注我的公眾號 JessYan褥民,一起學(xué)習(xí)進步,如果框架有更新向拆,我也會在公眾號上第一時間通知大家
Hello 我叫 JessYan烤咧,如果您喜歡我的文章偏陪,可以在以下平臺關(guān)注我
- 個人主頁: http://jessyan.me
- GitHub: https://github.com/JessYanCoding
- 掘金: https://juejin.im/user/57a9dbd9165abd0061714613
- 簡書: http://www.reibang.com/u/1d0c0bc634db
- 微博: http://weibo.com/u/1786262517
-- The end