MVP架構(gòu)
Model-View-Persenter 是IBM開(kāi)發(fā)的一套適用C++,Java的編程模型。2000年出現(xiàn)。
Persenter/Controller:負(fù)責(zé)處理業(yè)務(wù)邏輯交互。 View:負(fù)責(zé)顯示視圖。Model:負(fù)責(zé)提供數(shù)據(jù)。
架構(gòu)是對(duì)客觀不足的妥協(xié)。規(guī)范是對(duì)主觀不足的妥協(xié)。
MVP角色
View :負(fù)責(zé)繪制UI元素、與用戶(hù)進(jìn)行交互(在Android中體現(xiàn)為Activity)。
Activity interface: 需要View實(shí)現(xiàn)的接口,View通過(guò)View interface與Presenter進(jìn)行交互,降低耦合,方便進(jìn)行單元測(cè)試。
Model:負(fù)責(zé)存儲(chǔ)、檢索、操縱數(shù)據(jù)(有時(shí)也實(shí)現(xiàn)一個(gè)Model interface用來(lái)降低耦合)。
Presenter:作為View與Model交互的中間紐帶,處理與用戶(hù)交互的負(fù)責(zé)邏輯。
如何實(shí)現(xiàn)MVP模式
- View 層通過(guò)接口實(shí)現(xiàn)UI業(yè)務(wù)邏輯。比如加載進(jìn)度條,展示返回?cái)?shù)據(jù)列表。此時(shí)Activity 屬于視圖層。
-
Model層負(fù)責(zé)存儲(chǔ)、檢索、操縱數(shù)據(jù)(有時(shí)也實(shí)現(xiàn)一個(gè)Model interface用來(lái)降低耦合)。一般抽象出來(lái)。需要在Persenter層實(shí)現(xiàn)
Persenter層作為View與Model交互的中間紐帶,處理與用戶(hù)交互的負(fù)責(zé)邏輯。持有視圖層 UI 接口的引用。 同時(shí)持有Model的引用。所以此時(shí)需要調(diào)用視圖層的邏輯。
- 最終在MainActivity 中初始化Persenter,并調(diào)用相應(yīng)的方法。
-
因?yàn)轫?xiàng)目中有很多Persenter,那么最好抽象出父類(lèi)出來(lái)。為了避免內(nèi)存泄漏的問(wèn)題,對(duì)View使用弱引用的方式。
-
另外Persenter的注入,最好放在baseActivity 中實(shí)現(xiàn),避免重復(fù)代碼。
mvp相對(duì)于mvc優(yōu)點(diǎn)
減少了Activity的職責(zé),簡(jiǎn)化了Activity中的代碼,將復(fù)雜的邏輯代碼提取到了Presenter中進(jìn)行處理。與之對(duì)應(yīng)的好處就是,耦合度更低。
-
Activity 代碼變得更加簡(jiǎn)潔。
- 使用MVP之后,Activity就能瘦身許多了,基本上只有FindView、SetListener以及Init的代碼。其他的就是對(duì)Presenter的調(diào)用,還有對(duì)View接口的實(shí)現(xiàn)。這種情形下閱讀代碼就容易多了,而且你只要看Presenter的接口,就能明白這個(gè)模塊都有哪些業(yè)務(wù),很快就能定位到具體代碼。Activity變得容易看懂,容易維護(hù),以后要調(diào)整業(yè)務(wù)、刪減功能也就變得簡(jiǎn)單許多。
-
方便進(jìn)行單元測(cè)試。
一般單元測(cè)試都是用來(lái)測(cè)試某些新加的業(yè)務(wù)邏輯有沒(méi)有問(wèn)題,如果采用傳統(tǒng)的代碼風(fēng)格(習(xí)慣性上叫做MV模式,少了P),我們可能要先在Activity里寫(xiě)一段測(cè)試代碼,測(cè)試完了再把測(cè)試代碼刪掉換成正式代碼,這時(shí)如果發(fā)現(xiàn)業(yè)務(wù)有問(wèn)題又得換回測(cè)試代碼,咦,測(cè)試代碼已經(jīng)刪掉了!好吧重新寫(xiě)吧……
MVP中,由于業(yè)務(wù)邏輯都在Presenter里,我們完全可以寫(xiě)一個(gè)PresenterTest的實(shí)現(xiàn)類(lèi)繼承Presenter的接口,現(xiàn)在只要在Activity里把Presenter的創(chuàng)建換成PresenterTest,就能進(jìn)行單元測(cè)試了,測(cè)試完再換回來(lái)即可。萬(wàn)一發(fā)現(xiàn)還得進(jìn)行測(cè)試,那就再換成PresenterTest吧。
-
避免 Activity 的內(nèi)存泄露
- 發(fā)生OOM異常的原因
現(xiàn)內(nèi)存泄露造成APP的內(nèi)存不夠用,而造成內(nèi)存泄露的兩大原因之一就是Activity泄露(Activity Leak)(另一個(gè)原因是Bitmap泄露(Bitmap Leak))
Activity是有生命周期的,用戶(hù)隨時(shí)可能切換Activity,當(dāng)APP的內(nèi)存不夠用的時(shí)候,系統(tǒng)會(huì)回收處于后臺(tái)的Activity的資源以避免OOM。
Java一個(gè)強(qiáng)大的功能就是其虛擬機(jī)的內(nèi)存回收機(jī)制,這個(gè)功能使得Java用戶(hù)在設(shè)計(jì)代碼的時(shí)候,不用像C++用戶(hù)那樣考慮對(duì)象的回收問(wèn)題。然而,Java用戶(hù)總是喜歡隨便寫(xiě)一大堆對(duì)象,然后幻想著虛擬機(jī)能幫他們處理好內(nèi)存的回收工作。可是虛擬機(jī)在回收內(nèi)存的時(shí)候,只會(huì)回收那些沒(méi)有被引用的對(duì)象,被引用著的對(duì)象因?yàn)檫€可能會(huì)被調(diào)用,所以不能回收。
- 發(fā)生OOM異常的原因
-
MVC產(chǎn)生內(nèi)存泄漏異常分析
- 采用傳統(tǒng)的MVC模式,一大堆異步任務(wù)和對(duì)UI的操作都放在Activity里面,比如你可能從網(wǎng)絡(luò)下載一張圖片,在下載成功的回調(diào)里把圖片加載到 Activity 的 ImageView 里面,所以異步任務(wù)保留著對(duì)Activity的引用。這樣一來(lái),即使Activity已經(jīng)被切換到后臺(tái)(onDestroy已經(jīng)執(zhí)行),這些異步任務(wù)仍然保留著對(duì)Activity實(shí)例的引用,所以系統(tǒng)就無(wú)法回收這個(gè)Activity實(shí)例了,結(jié)果就是Activity Leak。Android的組件中,Activity對(duì)象往往是在堆(Java Heap)里占最多內(nèi)存的,所以系統(tǒng)會(huì)優(yōu)先回收Activity對(duì)象,如果有Activity Leak,APP很容易因?yàn)閮?nèi)存不夠而OOM。
-
MVC模式如何避免內(nèi)存泄漏
- 只要在當(dāng)前的Activity的onDestroy里,分離異步任務(wù)對(duì)Activity的引用,就能避免 Activity Leak。