曾露
摘要:傳統(tǒng)的MVC模式在Android的應(yīng)用開發(fā)中存在諸多不足,主要表現(xiàn)在Android應(yīng)用開發(fā)的關(guān)鍵類Activity會(huì)充當(dāng)Controller和View的合體,既要負(fù)責(zé)業(yè)務(wù)邏輯,又要負(fù)責(zé)顯示,造成Activity的職責(zé)過多,耦合度高。MVP模式是MVC模式演進(jìn)而來,引入了Presenter徹底分離Model和View層,在解決Activity臃腫的問題同時(shí),還有助于后期的測試與維護(hù)。本文分析MVC對于Android開發(fā)的不足,并探索MVP模式在Android開發(fā)中的可行性,以及優(yōu)劣勢,最后實(shí)現(xiàn)MVP模式在Android開發(fā)中的應(yīng)用。
關(guān)鍵詞:Android;MVP;模式
引言
GUI(Graphical User Interface)應(yīng)用程序出現(xiàn)之后,應(yīng)用程序也變得更加復(fù)雜,為了管理這種復(fù)雜性,基于職責(zé)分離的思想而孕育而出了MVC模式。在Android開發(fā)過程中,同樣會(huì)采用MVC模式的思想,將訪問和數(shù)據(jù)的表現(xiàn)分離。一般的處理是將進(jìn)行界面描述的XML文件作為視圖層(View),使用的時(shí)候可以非常方便的引入,同時(shí)便于后期界面的修改。將Activity等類作為控制層(Controller),來控制View層和Model層的通信,以此來達(dá)到分離視圖顯示和業(yè)務(wù)邏輯層,其中與業(yè)務(wù)相關(guān)的數(shù)據(jù)結(jié)構(gòu)類作為模型層(Model),用來處理數(shù)據(jù)庫的操作、網(wǎng)絡(luò)請求等操作。但其實(shí)Activity并不是一個(gè)標(biāo)準(zhǔn)的MVC模式中的Controller,它的首要職責(zé)是加載應(yīng)用的布局和初始界面,以及接受并處理來自用戶的操作請求,并做出響應(yīng)。隨著界面及其邏輯的復(fù)雜度不斷提升,Activity類的職責(zé)不斷增加,以致變得龐大臃腫。不僅如此,在Android中,允許View和其它線程共存于Activity內(nèi),造成的問題是Activity中同時(shí)存在業(yè)務(wù)邏輯和UI邏輯,成為包羅萬象的“上帝類”,這大大增加了應(yīng)用后期的測試和維護(hù)成本。為了使Android應(yīng)用開發(fā)簡單,各層次職責(zé)清晰,增加可讀性和復(fù)用性,減少后期的測試、維護(hù)成本,本文在Android開發(fā)應(yīng)用中引人MVP模式。
1 MVP模式
MVP從MVC演變而來,通過表示器將視圖與模型巧妙地分開。在該模式中,視圖通常由表示器初始化,它呈現(xiàn)用戶界面(UI)并接受用戶所發(fā)出命令,但不對用戶的輸入作任何邏輯處理,而僅僅是將用戶輸入轉(zhuǎn)發(fā)給表示器。通常每一個(gè)視圖對應(yīng)一個(gè)表示器,但是也可能一個(gè)擁有較復(fù)雜業(yè)務(wù)邏輯的視圖會(huì)對應(yīng)多個(gè)表示器,每個(gè)表示器完成該視圖的一部分業(yè)務(wù)處理工作,降低了單個(gè)表示器的復(fù)雜程度,一個(gè)表示器也能被多個(gè)有著相同業(yè)務(wù)需求的視圖復(fù)用,增加單個(gè)表示器的復(fù)用度。表示器包含大多數(shù)表示邏輯,用以處理視圖,與模型交互以獲取或更新數(shù)據(jù)等。模型描述了系統(tǒng)的處理邏輯,模型對于表示器和視圖一無所知。
1.1MVP模式的引入
在Android開發(fā)應(yīng)用中,MVP的結(jié)構(gòu)劃分:視圖(View)負(fù)責(zé)繪制uI元素、與用戶交互,在Android開發(fā)中對應(yīng)于Activity相關(guān)的類;模型(Model)類似于數(shù)據(jù)加工處理廠,負(fù)責(zé)對數(shù)據(jù)的獲取,數(shù)據(jù)的解析,數(shù)據(jù)的存儲(chǔ),數(shù)據(jù)的分發(fā),數(shù)據(jù)的增刪改查等操作;表示器(Presenter)作為View與Model交互的中間紐帶,處于MVP的中間層,表示器會(huì)把視圖遞交的命令進(jìn)行一定的校驗(yàn)等操作,然后交給模型層處理,模型層處理完數(shù)據(jù)之后,會(huì)通知表示器,表示器主動(dòng)去獲取數(shù)據(jù)處理的結(jié)果遞交給視圖層顯示。因此表示器有封裝業(yè)務(wù),更新UI界面和持有線程等功能。各模塊數(shù)據(jù)的交互見圖1。
從上圖可以看出,MVP的分層結(jié)構(gòu)特別類似于網(wǎng)絡(luò)的七層協(xié)議,每層只知道自己依賴層的細(xì)節(jié)。層與層之間的耦合性低,模塊的復(fù)用性高,可維護(hù)性高,降低了測試的復(fù)雜度。
按照View和Presenter的交互方式和View本身的職責(zé),可以將MVP劃分為PV(PassiveView)和SoC(Superviding Controller)。其中PV中的View是被動(dòng)的,由Presenter來推送和獲取數(shù)據(jù),這也是普遍的用法,本文研究的MVP模式也屬此種模式。MVP模式的變種Passive View中各模塊的依賴關(guān)系如圖2所示。
在被動(dòng)視圖(passive View)模式中,表示器通過接口與視圖交互。采用這種方案可以使表示器自身成為一個(gè)可重用性和可測試性均很高的類。首先,表示邏輯獨(dú)立于所使用的UI技術(shù),其次,針對某一接口為表示器編碼,該表示器可以與實(shí)現(xiàn)該接口的任何對象交互,而實(shí)現(xiàn)該接口的可能是Activity對象、Fragment對象等,這意味著只要視圖接口不變,視圖的任何更新都不會(huì)影響到表示器。這就能使單個(gè)表示器只專注于它自己的職責(zé),使得表示器層結(jié)構(gòu)簡單,邏輯清晰,符合面向?qū)ο蟮膯我宦氊?zé)原則,當(dāng)程序需要修改時(shí),大大降低了修改的成本。再者,同一表示器可以處理同一應(yīng)用程序的不同視圖。最后,如果將應(yīng)用邏輯混合于UI代碼中,由于應(yīng)用程序中的UI代碼非常難以自動(dòng)測試,從而導(dǎo)致整個(gè)應(yīng)用的難以測試。因此,從UI分離出視圖接口,將UI中的邏輯從視圖中移除,通過模仿視圖對象,可以方便地測試表示器。因此,表示器層是作為MVP體系的控制中心,而視圖僅僅是用戶交互請求的匯報(bào)者,不維護(hù)數(shù)據(jù)的狀態(tài)。表示器直接依賴View的接口。
1.2MVP模式的優(yōu)缺點(diǎn)
MVP與MVC的主要區(qū)別是View與Model不直接交互,而是通過與Presenter來完成交互,這樣可以修改視圖而不影響模型,達(dá)到解耦的目的,實(shí)現(xiàn)了Model和View真正的完全分離。視圖的變化總是比較頻繁,將業(yè)務(wù)邏輯抽取出來,放在表示器中實(shí)現(xiàn),使模塊職責(zé)劃分明顯,層次清晰,一個(gè)表示器能復(fù)用于多個(gè)視圖,而不需要更改表示器的邏輯(當(dāng)然是在該視圖的改動(dòng)不影響業(yè)務(wù)邏輯的前提下),這增加了程序的復(fù)用性。數(shù)據(jù)的處理由模型層完成,隱藏了數(shù)據(jù),在數(shù)據(jù)顯示時(shí),表示器可以對數(shù)據(jù)進(jìn)行訪問控制,提高數(shù)據(jù)的安全性。以前的Android開發(fā)是難以進(jìn)行單元測試的,但是隨著項(xiàng)目變得復(fù)雜,測試時(shí)保證應(yīng)用質(zhì)量的關(guān)鍵,MVP模式中,表示器對視圖是通過接口進(jìn)行的,可以利用測試驅(qū)動(dòng),模擬出視圖對象,實(shí)現(xiàn)視圖相對于表示器的接口,就可以對表示層進(jìn)行不依賴于UI環(huán)境的單元測試了,這大大降低了Android應(yīng)用開發(fā)中的業(yè)務(wù)邏輯測試難度和復(fù)雜度。MVP模式的引人,視圖層完全不依賴與模型層,相當(dāng)于將視圖從特定的業(yè)務(wù)場景中脫離出來,做到了對業(yè)務(wù)完全不可知的狀態(tài),因此可以將視圖層組件化,提供一系列接口供表示層操作,這樣就可以做出高度可復(fù)用的視圖組件了。
MVP的明顯缺點(diǎn)是增加了代碼的復(fù)雜度,特別是針對小型Android應(yīng)用的開發(fā),會(huì)使程序冗余。Presenter中除了應(yīng)用邏輯以外,還有大量的View->Model,Model->View的手動(dòng)同步邏輯,會(huì)導(dǎo)致Presenter臃腫,維護(hù)困難。視圖的渲染過程也會(huì)放在Presenter中,造成視圖與Presenter交互過于頻繁,如果某特定視圖的渲染很多,就會(huì)造成Presenter與該視圖聯(lián)系過于緊密,一旦該視圖需要變更,那么Presenter也需要變更了,不能如預(yù)期的那樣降低耦合度和增加復(fù)用性。
2MVP模式的應(yīng)用
2.1MVP模式中的模型
模型從黑盒的角度來說就是輸入/輸出數(shù)據(jù)。模型在Android應(yīng)用中,主要負(fù)責(zé)從網(wǎng)絡(luò),數(shù)據(jù)庫,文件,傳感器,第三方等數(shù)據(jù)源讀寫數(shù)據(jù),以及對外部的數(shù)據(jù)類型進(jìn)行解析,轉(zhuǎn)換為應(yīng)用程序內(nèi)部數(shù)據(jù),并交由上層處理,還對數(shù)據(jù)進(jìn)行臨時(shí)存儲(chǔ)和管理,協(xié)調(diào)上層數(shù)據(jù)請求。
對于不同的數(shù)據(jù)處理,一般的,建立一個(gè)單例,進(jìn)行數(shù)據(jù)的初始、設(shè)置、檢查以及處理。
public interface IManager{
void onAppCreate();//應(yīng)用創(chuàng)建時(shí)
void set();//提供數(shù)據(jù)
void handle();//處理數(shù)據(jù)
void check();//數(shù)據(jù)檢查
}
在模型層中,會(huì)存在大量的實(shí)體,用于提供數(shù)據(jù)的存儲(chǔ)方式,如下所示:
public abstract class Entity{
private String mid;
public String getld(){
return mid;
}
protected abstract void setld(String id);
}
2.2 MVP模式中的視圖
前文提到,視圖層主要負(fù)責(zé)UI交互,在表示器的控制下修改UI,將業(yè)務(wù)事件交由表示器處理,不存儲(chǔ)數(shù)據(jù),也不與模型層交互。視圖層與表示器的任何交互都必須通過視圖接口進(jìn)行,用戶的任何命令都必須轉(zhuǎn)發(fā)到表示器,并由其進(jìn)行處理,因此要為每個(gè)視圖定義接口。
IView接口是每個(gè)視圖需要實(shí)現(xiàn)的接口,表示器通過此接口控制View,代碼如下所示:
publicinterfaceIView{
void initViews();//初始視圖
}
在Android應(yīng)用中,用來顯示頁面的類一般是Activity、fragment等,這些類在使用時(shí)都需要繼承上述的接口,且需要依賴表示器,見BaseActivity所示:
public abstract class BaseActivity extends Frag-mentActivity{
private SetmAllPresenters;//一個(gè)activity有可能有多個(gè)IPresenter
protected abstract int getLayoutResld();//獲取layout的id
protected abstract void onlnitPresenters();//初始化presenters
Protected abstract void parseArgumentsFromln-tent(Intent argIntent);//從intent中解析數(shù)據(jù)
@Override
protected void
onCreate(Bundle savedln-stanceState){
super.onCreate(savedlnstanceState);
//周期onCreate
}
//…其他生命周期方法也是類似,調(diào)用IPresenter中相應(yīng)的生命周期方法…
}
2.3 MVP模式中的表示器
表示器起到連接視圖與模型的橋梁作用,視圖中的控件將捕獲任何用戶操作并觸發(fā)視圖中的事件,例如按鈕單擊或索引選擇更改事件,視圖會(huì)直接向表示器遞交獲捕獲的數(shù)據(jù),交由表示器層處理。
表示器通常通過其初始函數(shù)接收對視圖的引用。視圖保留對表示器的引用,表示器保留對視圖接口的引用,表示器不依賴于具體的視圖對象。
首先將IView和IPresenter組合在一塊,建立IContract接口。
public interface IContract{
mtertace lConcreteView extends lVlew{
//具體view的UI操作
}
interface IConcretePresenter extends IPre-senter
//Presenter所需要處理的業(yè)務(wù)邏輯
}
}
表示器的初始函數(shù)接收并保存對視圖的引用,使用約定所表示的公共接口初始化視圖。表示器類還包含大量方法,執(zhí)行這些方法可響應(yīng)來自UI的任何請求,任何單擊或用戶操作都與表示器類的方法綁定。表示器的接口還提供了對應(yīng)于Activity或Fragment的生命周期的方法,這是為了根據(jù)視圖生命周期的不同提供相應(yīng)的邏輯業(yè)務(wù)。如下所示:
public interface IPresenter
void onStop();
void onResume();
void onDestroy();
void onPause();
void onStart();
void init(V view);
}
3總結(jié)
在Android應(yīng)用開發(fā)過程中,MVC框架并不能很好的契合Android的開發(fā)架構(gòu),因此本文采用MVP的模式開發(fā)Android應(yīng)用,介紹了MVP模式應(yīng)用于Android開發(fā)的可行性,同時(shí)通過編程,實(shí)現(xiàn)了MVP應(yīng)用于Android開發(fā)的思想。具體在應(yīng)用的過程中,還有很多許多細(xì)節(jié)需要注意,例如模型層對于復(fù)雜的數(shù)據(jù)處理,還需要根據(jù)不同的數(shù)據(jù)源、不同的業(yè)務(wù)請求而進(jìn)行細(xì)分等。