對於Android MVP的一些思考(二)

2021-08-08 05:58:39 字數 3557 閱讀 6780

上次對mvp的表面概念作出了一些思考【對於mvp、響應式程式設計以及事件匯流排的一些思考】。而隨著對自己的mvp框架深入優化、擴充套件,也發現了一些疑惑的地方。

相信接觸過mvp框架的都清楚,針對model-view-presenter這三者,都會為其單獨建立乙個inte***ce,規範其各自的行為。舉個例子,乙個登入用的activity,在這裡將其命名為loginactivity,其對應的presenter和model為loginpresenterloginmodel,而其各自的介面則為iloginviewiloginpresenteriloginmodel

看,乙個登入頁面,就產生了3個介面檔案。而隨著應用複雜度提高,介面檔案的數量將隨之劇增——我將其稱為「介面膨脹」。

因此,後來有人通過建立contract類來規範介面,比如:

public

inte***ce

logincontract

public

inte***ce

iloginpresenter

public

inte***ce

iloginmodel

}

這樣,乙個頁面對應乙個contract,減少了介面的生成數量。我覺得相對之前的情況,contract的引入使得mvp專案相對簡潔不少。

但是,我們是否真的需要這麼多介面?

對此,我覺得應該再次審視mvp的本質——就是解耦。而介面是最充分發揮解耦功能的方式。而如何和應用的實際情況相結合,這是乙個動態平衡的問題。也許有的專案針對model層的改動很大,呼叫的地方很多,這時候model完全拋棄介面不一定是件好事;而有的專案p層的使用極為有限,建立過多的inte***ce確實是浪費時間和增加method數。

所以對我而言,我的取捨是:model去掉介面,但是每個v針對乙個m,即確保v:p:m是1:1:1的關係。這樣即使要改動乙個m,也僅是改動乙個p即可。雖然這樣也是有缺點:當m層內所呼叫的多個操作有所變動,可能需要改動特別多的地方,但這保證了只影響m層,其他層不受影響。

而p層的inte***ce,我還是選擇保留,與view共同寫在contract中——除非對method數有要求。

其實這是乙個很小的點。比如說,有的人喜歡分類將所有activity放到同乙個包中,按型別建包;有的喜歡按照需求功能,比如login部分都放到同乙個包,按功能建包。

按照google的demo,結合contract,demo選的是按功能建包,同一功能的都放到同乙個包中。

但是會有這樣一種情況——假設我現在寫乙個應用內的文章模組,它包含有:

列表頁詳情頁

投稿頁etc.

這樣,如果按照上述分包策略,這部分的所有m、v、p都放進乙個article的包內,是否又顯得過於臃腫?

又或者,再按照功能點細分,就會有如下分包

這樣,保證了每個包內僅有一組 m、v、p和contract,結構上是非常清晰。不過,我們是否真的需要如此多的包呢?

其實只要不是按照上述第一種方法分包,恐怕任何方式的分包都會導致包的數量增加。我看到有的專案會將contract抽離出單獨乙個包,所有contract都寫在裡面;而m、v、p都各自乙個包,雖然這樣也夠直觀,但是各自內部不會再分包,這樣又是否夠清晰呢?

事實上,分包也只是個人喜好,到底如何分,隨君喜好吧!

有一種情況:當應用回到後台,再次回到前台時,可能v層已經被記憶體**,這時候如何讓p層與v層重新建立聯絡,並且盡可能恢復資料?

p層與v層共存亡

資料不應儲存在p層

是的,乙個應用所產生的臨時資料不應該記錄在p層,但一些臨時變數可以。比如乙個列表頁的資料,從伺服器獲取下來後,應該在m層保持住;而使用者滑動到列表頁的第幾層,則可以記錄在p層。

那麼,如何恢復資料呢?

首先明確乙個觀點,即上述第一點,p與v共存亡,既然v被**了,p也不會存在,所以v重新被建立了,p也隨著v的建立而建立。

所以第一種方法,就是最常用的,將資料儲存到v的bundle中,隨著v被重新建立,取出bundle的資料給回p層,再從p層回到m層。

但是上述文章有提到一點,即把資料保持在m層。

m層其實並不是必須跟隨v的生命週期,畢竟它不關心p、v,它只負責運算元據。所以m層可以通過靜態變數等手段保持資料到記憶體,當p、v重新建立時,再從m處取得資料。

實際上這種方式更符合mvp的思想,甚至由此可以輔助處理不常變動的網路資料,將資料快取到記憶體中,無需多次請求網路,畢竟相比之下請求網路的操作和記憶體相比代價還是略高。

在這裡,我只給出這種思考點,至於如何使用,或者有更好的方式,都要看實際需求決定。

依然舉乙個例子:當乙個activity內用viewpager之類的包裹4個fragment,如何合理地處理其邏輯和資料互動?

起初我的想法是,fragment也只是乙個控制項view,因此我認為」fragment和activity共用乙個presenter和model「,這樣就能減少管理複雜度,也無需考慮資料的傳遞——畢竟資料都在同乙個presenter和model裡打轉。

後來我意識到這個想法是錯誤的,一是這樣違背了使用mvp的初衷,二是fragment也有其自身的生命週期,以及它自身的特性注定了它可以承擔複雜的頁面邏輯,這些在mvp架構下離不開p的加持。

建立fragment時通過setargument()設定引數:activity ---> fragment(create)activity和fragment之間互相互動:activity <===> fragmentfragment之間互相互動:fragment <===> fragment

排除第一種流向,最麻煩的就是在第2、3種情況下,彼此互動的資料型別十分多(比如activity和fragment、fragment之間的資料互動型別例項分別有5~10種),怎麼辦呢?

我認為的解決方法是,在不使用bus類的方法上,針對每種資料型別,都建立對應的repository,在需要互動的v層所對應的model上呼叫其對應的repository,並根據repository提供訂閱的observable,供p層呼叫,畢竟決定互動資料的邏輯是由p決定的;然後,當其中乙個v產生資料,將通過p層傳遞到m層,m層內部將資料傳送到repository,而訂閱了該repository的p層將收到資料從而處理v層。

是的,上述的方法稍微有點傻,但是考慮到解耦和日後修改時的難易度,個人感覺可以接受。

什麼?你說如果資料型別在10種、20種、甚至上百種呢?

那就重構吧!

架構往往是提供一種思考正規化,而不是硬性規定,任何架構或者思想總有無法涉及或者無法處理的問題,這時候就考驗到使用者如何靈活地變通運用。mvp是個很好的框架,但基於android自身的設計,始終無法做到徹底地將各層次分離開來;而引入響應式程式設計,我覺得是乙個很好的靈活處理方式,雖然mvp不是必須依賴響應式,但是通過事件響應、資料響應,可以更好地處理mvp裡同層級間的聯絡(如m與m間的資料流動),這一點是很多文章沒有提及到的。

這些思考僅一己之見,還需實戰實驗,還望能拋磚引玉!

對於工作的一些思考

感覺自從領導讓我管專案以來,一直沒有讓領導很滿意的地方是自己在專案上花的心思太少.很簡單的一些例子就證明了,比如自己雖然是中途接手的專案,然後並沒有仔細檢視招標檔案,沒有針對招標檔案的要求 去核對乙方的一些功能是否完成.其次,對於乙方,我還在心裡上和行動上 做到完成把控住,我不僅要去分析我領導的想法...

對於切片的一些理解

使用技巧 type struct 乙個切片是由資料指標加上長度和容量組成的,類似與c 中的vector。var a int 等價於nil b int 表示乙個空的切片,不等於nil c int len,cap都為3的切片 d c 2 cap為3,len為2。與c共享一片記憶體位址 e c 0 2 c...

對於爬蟲的一些思考

由於專案並不會投入太多的時間,所以穩定性能是最終的。穩定性的可以從以下的維度進行考慮 資料量不多的時候採用單執行緒。異常處理。重試。詳細的日誌。個人覺得資料量少就是在40小時內遍歷全部並且可以爬完的就是小資料量。異常處理主要就是放在請求 時 入庫。而重試主要是用traceback這個庫,它的作用是捕...