一、前言
在日常的Android開發中,如果不有意地進行架構設計,往往代碼都會比較凌亂,其中最常見的一個問題就是Activity的代碼太過冗雜,一些複雜的類可能會到達幾千行代碼。要解決這個問題,可以藉助MVP思想對代碼進行簡單的分層。
二、MVP的演變過程
階段一:野蠻生長
在剛接觸Android的時候,我們按照官方指引文檔還有示例代碼,最簡單直接地把佈局在xml文件裏面實現,而View的綁定和其他邏輯都在Activity中實現,任由其野蠻生長,一個Activity走天下。那麼隨着功能的增加,代碼也會變得越來越多,那麼就會導致Activity裏面的代碼非常繁雜,對功能迭代和維護都十分不友好。
階段二:MVC引入
衆所周知,MVC架構是源於Web開發演變出來的架構,所以在一開始的時候,Android Develpers很自然地會把這一套架構搬到Android上面來,但是好景不長,開發者們發現使用了這個架構,Activity層的代碼還是會變得非常繁雜,原因很簡單,“橘生淮南則爲橘,橘生淮北則爲枳”,沒有什麼架構是一套走天下的,MVC適用於Web開發,但是在Android開發中就不奏效了,那麼是爲什麼?
如上圖爲MVC的結構,模型(model)-視圖(view)-控制器(controller)。在Android中,MVC的對應關係如下:
- 視圖層(View):一般採用XML文件進行界面描述
- 控制層(Controller):對應Activity或Fragment
- 模型層(Model):數據操作和管理的類
但是在Android中,Activity和Fragment並不是標準MVC模式中的Controller,它的首要職責是加載佈局和初始化界面,伴隨着控件綁定和觸摸事件的分發和處理。所以隨着界面和邏輯的不斷增加,Activity和Fragment就會變得異常臃腫。
階段三:MVP架構誕生
由於MVC架構並不適合於Android開發,所以開發者們將MVC進行了演進,MVP架構呼之欲出,從此走上了歷史的舞臺。那麼MVP和MVC有什麼不一樣呢?
- View層:對應XML和Activity、Fragment,主要負責顯示界面和觸摸時間分發處理,和Presenter進行交互
- Model層:主要是負責業務邏輯,包括存儲、網絡等
- Presenter層:屬於V、M的中間橋樑,完成它們之間的交互,初始化和釋放等工作。
這樣,在Activity和Fragment中就可以專一展示View的指責,把和界面不相關的邏輯放到Model層,通過Presenter進行傳遞和響應,實現了界面和邏輯的分層。
三、代碼設計
網絡上已經有很多關於MVP的代碼介紹,但是在項目中使用MVP就需要把MVP抽取成通用的代碼,方便其他人進行復用,這也是從架構的思想來設計MVP。
根據依賴倒置原則
知道,我們需要面向接口編程,不依賴具體實現,所以把MVP的每一層都分離出接口,如下圖所示的IView、IPresenter、IModel。
在抽象出來接口之後,那麼就需要實現M、V、P層的實現類(或者抽象),其實就是根據二中的MVP結構圖把三者連接起來。
IView的實現類
先看IView的實現類BaseActivity(BaseFragment也是同理),它是直接跟IPresenter交互的,所有它應該持有一個IPresenter的實現類的對象,爲了把IPresenter更加抽象,我們用到泛型P來定義這個對象,同時在onDestory的時候對presenter進行釋放,避免內存泄漏。
這裏的getLifeCycle並不是複寫AppCompatActivity的方法,而是在IView中定義了這個接口,具體作用後面再說。
所以整體代碼也是非常簡單,就是持有一個泛型P的對象,具體創建需要在子類裏面進行,從而View的基類就實現好了。
public class BaseActivity<P extends IPresenter> extends AppCompatActivity implements IView {
@Nullable
protected P mPresenter;
@Override
public Lifecycle getLifeCycle() {
return super.getLifecycle();
}
@Override
protected void onDestroy() {
super.onDestroy();
if (mPresenter != null) {
mPresenter = null;
}
}
}
IPresenter的實現類
再看IPresenter的實現類BasePresenter,它裏面也是嚴格按照MVP的結構圖所示,它能跟V層和M層打交道,所以它持有了泛型V和泛型M的對象。由於Presenter在View層創建,所以它持有的View對象就在構造函數中傳入,而持有Model對象則由子類來進行初始化。在onDestroy中對這兩個對象進行釋放。
public abstract class BasePresenter<V extends IView, M extends IModel> extends LifeCycleComponent implements IPresenter {
@Nullable
protected V mView;
@Nullable
protected M mModel;
public BasePresenter(@NonNull V view) {
super(view.getLifeCycle());
this.mView = view;
}
@Override
public void onDestroy() {
super.onDestroy();
if (mView != null) {
mView = null;
}
if (mModel != null) {
mModel = null;
}
}
}
IModel的實現類
最後看IModel的實現類BaseModel,同理,按照MVP結構圖,Model層只持有Presenter的對象,而Model是由Presenter進行示例化,所以它持有的Presenter對象也是在構造函數中傳入。在onDestroy中進行釋放Presenter對象。
public class BaseModel<P extends IPresenter> extends LifeCycleComponent implements IModel{
@Nullable
protected P mPresenter;
public BaseModel(@Nullable Lifecycle mLifeCycle, @Nullable P presenter) {
super(mLifeCycle);
this.mPresenter = presenter;
}
@Override
public void onStop() {
super.onStop();
if (mPresenter != null) {
mPresenter = null;
}
}
}
LifeCycle輔助類
通過看上面的代碼,大家可能還有疑問,如IView定義的getLifeCycle方法作用是什麼?爲什麼BasePresenter和BaseModel都繼承了LifeCycleComponent?BaseModel的構造函數爲什麼要傳入Lifecycle對象?
不用急,爲您一一解答。
首先了解一下什麼是LifeCycle,簡單來說就是在Activity(Fragment)以外的組件用來監聽Activity(Fragment)生命週期的一個架構組件,從而讓該組件擁有和Activity(Fragment)一樣的生命週期,它的原理也是比較簡單,最新包的Activity(Fragment)都實現了一個LifecycleOwner的接口,只要我們在需要的組件裏面實現LifecycleObserver接口,然後在Activity(Fragment)調用lifecycle.addObserver(LifecycleObserver)即可,其實就是一個監聽者模式。
瞭解了LifeCycle之後,那麼我們爲什麼要用它呢?因爲Presenter和Model其實就是一個外部組件,爲了避免內存泄漏,我們必須讓它們保持和Activity(Fragment)一樣對生命週期,在Activity(Fragment)被銷燬時候,這兩個組件都能釋放資源。所以LifeCycleComponent就是一個實現了LifecycleObserver接口的組件,然後弱引用持有傳入的IView(因爲它提供了getLifeCycle方法),通過IView拿到lifecycle,然後把自己和Activity(Fragment)關聯起來,所以BasePresenter和BaseModel就可以在內部管理生命週期。
public class LifeCycleComponent implements LifecycleObserver {
@Nullable
private WeakReference<Lifecycle> mLifeCycle;
public LifeCycleComponent(@Nullable Lifecycle mLifeCycle) {
this.mLifeCycle = new WeakReference<>(mLifeCycle);
addLifeCycle();
}
private void addLifeCycle() {
Lifecycle lifecycle = null;
if (mLifeCycle != null) {
lifecycle = mLifeCycle.get();
}
if (lifecycle != null) {
lifecycle.addObserver(this);
}
}
@OnLifecycleEvent(Lifecycle.Event.ON_CREATE)
public void onCreate() {}
@OnLifecycleEvent(Lifecycle.Event.ON_START)
public void onStart(){}
@OnLifecycleEvent(Lifecycle.Event.ON_RESUME)
public void onResume(){}
@OnLifecycleEvent(Lifecycle.Event.ON_PAUSE)
public void onPause() {}
@OnLifecycleEvent(Lifecycle.Event.ON_STOP)
public void onStop() {}
@OnLifecycleEvent(Lifecycle.Event.ON_DESTROY)
public void onDestroy() {}
@OnLifecycleEvent(Lifecycle.Event.ON_ANY)
public void onAny() {}
}
四、總結
MVP只是一個對Android代碼比較友好的一個架構,它能夠比較對代碼進行比較清晰的分層,避免Activity變得過於臃腫,但是使用它當然也不能完全保證Activity不會變得臃腫,尤其當我們在同一個Activity(Fragment)進行多功能開發時,即便只在V層進行UI操作,代碼也會變得複雜,這時候就需要進行二次重構,對V層再進行模塊分離,再次對V層瘦身。
其次由於是面向接口編程和結構分層,所以不可避免的是會造成生成過多的類和接口,所以這也是MVP的另一個缺點之一。但是總體來說,MVP也不失爲一個合格的框架,畢竟MVP只是重構過程中的萬里長征的第一步。
Github代碼:MvpDemo