接觸Android MVP模式在好早之前,一直也沒有在項目中真正的實用。剛好有一個機會需要自己去做項目,然後就用上MVP。MVP用起來還是很方便,整個項目結構非常清晰,相比於傳統的MVC模式,MVP清晰分工,有太多有點了。這些其實是需要在實用以後才能體會到的,尤其是當項目很複雜的時候。
一、MVP介紹
在MVP模式裏通常包含4個要素:
- View:負責繪製UI元素、與用戶進行交互(在Android中體現爲Activity);
- View interface:需要View實現的接口,View通過View interface與Presenter進行交互,降低耦合,方便進行單元測試;
- Model:負責存儲、檢索、操縱數據(有時也實現一個Model interface用來降低耦合);
- Presenter:作爲View與Model交互的中間紐帶,處理與用戶交互的負責邏輯。
二、爲什麼使用MVP模式
在Android開發中,Activity並不是一個標準的MVC模式中的Controller,它 的首要職責是加載應用的佈局和初始化用戶界面,並接受並處理來自用戶的操作請求,進而作出響應。隨着界面及其邏輯的複雜度不斷提升,Activity類的 職責不斷增加,以致變得龐大臃腫。當我們將其中複雜的邏輯處理移至另外的一個類(Presneter)中時,Activity其實就是MVP模式中 View,它負責UI元素的初始化,建立UI元素與Presenter的關聯(Listener之類),同時自己也會處理一些簡單的邏輯(複雜的邏輯交由 Presenter處理).
另外,回想一下你在開發Android應用時是如何對代碼邏輯進行單元測試的?是否每次都要將應用部署到Android模擬器或真機上,然後通過模擬用 戶操作進行測試?然而由於Android平臺的特性,每次部署都耗費了大量的時間,這直接導致開發效率的降低。而在MVP模式中,處理複雜邏輯的 Presenter是通過interface與View(Activity)進行交互的,這說明了什麼?說明我們可以通過自定義類實現這個 interface來模擬Activity的行爲對Presenter進行單元測試,省去了大量的部署及測試的時間。
三、MVP與MVC的異同
MVC模式與MVP模式都作爲用來分離UI層與業務層的一種開發模式被應用了很多年。在我們選擇一種開發模式時,首先需要了解一下這種模式的利弊:
無論MVC或是MVP模式都不可避免地存在一個弊端:
- 額外的代碼複雜度及學習成本。(這就導致了這兩種開發模式也許並不是很小型應用。)
但比起他們的優點,這點弊端基本可以忽略了:
- 降低耦合度
- 模塊職責劃分明顯
- 利於測試驅動開發
- 代碼複用
- 隱藏數據
- 代碼靈活性
四、案例
這裏用一個案例來詳細介紹MVP的實用,當然這裏做一個基類封裝方便使用。
IPresenterView接口
/**
* @author ttarfall
* @date 2016-09-06 10:08
*/
public interface IPresenterView {
}
(當然這裏用了一個空的接口,其實是可以在裏邊加一些通用的方法)
BasePresenter基類
/**
* 基礎basePresenter,用於IView接口的傳入,attach,dettach用於綁定與解綁IView,當Activity被銷燬的時候,及時解綁IView防止內存溢出
* @author ttarfall
* @date 2016-09-06 10:02
*/
public abstract class BasePresenter<T extends IPresenterView> {
protected T paresenterView;
public void attach(T mView) {
this.paresenterView = mView;
}
public void dettach() {
paresenterView = null;
}
}
BaseMVPActivity基類
import android.os.Bundle;
/**
* @author ttarfall
* @date 2016-09-06 09:36
*/
public abstract class BaseMVPActivity<V extends IPresenterView, P extends BasePresenter<V>> extends BaseActivity {
protected P presenter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
presenter = initPresenter();
try {
presenter.attach((V) this);
} catch (Exception e){
new ClassCastException(this.toString() +"實現IPresenterView或者IPresenterView子類接口");
}
}
@Override
protected void onDestroy() {
presenter.dettach();
super.onDestroy();
}
//實例化Presenter
public abstract P initPresenter();
}
BaseMVPFragment基類
import android.os.Bundle;
/**
* @author ttarfall
* @date 2016-09-08 13:45
*/
public abstract class BaseMVPFragment<V extends IPresenterView, P extends BasePresenter<V>> extends BaseFragment {
protected P presenter;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
presenter = initPresenter();
try {
presenter.attach((V) this);
} catch (Exception e) {
new ClassCastException(this.toString() + "實現IPresenterView或者IPresenterView子類接口");
}
}
@Override
public void onDestroy() {
presenter.dettach();
super.onDestroy();
}
//實例化Presenter
public abstract P initPresenter();
}
上邊是MVP做了一個簡單的封裝,接下來就是使用了。如圖
IMainView源碼,當然這裏的ILoaddingView 接口也是繼承IPresenterView ,只不過增加了一個setLoading方法。
MainPresenter部分源碼截圖,可以看到我這裏其實有3個mode,當然每一個mode都有自己實現的方法。
mode存主要是獲取數據的和保存數據使用。這裏展示UserInfoMode的使用,IUserInfoMode展示提供的方法。
最後就是IMainView需要在Activity或者Fragment中實現。然後就是Presenter通過IPresenter與Activity或者Fragment互動。
至此一整套MVP的解釋到案例就結束了,如果還有不太懂得童鞋可以留言。