淺談Android上的MVP架構

一、前言

在日常的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有什麼不一樣呢?

image

  • View層:對應XML和Activity、Fragment,主要負責顯示界面和觸摸時間分發處理,和Presenter進行交互
  • Model層:主要是負責業務邏輯,包括存儲、網絡等
  • Presenter層:屬於V、M的中間橋樑,完成它們之間的交互,初始化和釋放等工作。

這樣,在Activity和Fragment中就可以專一展示View的指責,把和界面不相關的邏輯放到Model層,通過Presenter進行傳遞和響應,實現了界面和邏輯的分層。

三、代碼設計

網絡上已經有很多關於MVP的代碼介紹,但是在項目中使用MVP就需要把MVP抽取成通用的代碼,方便其他人進行復用,這也是從架構的思想來設計MVP。

根據依賴倒置原則知道,我們需要面向接口編程,不依賴具體實現,所以把MVP的每一層都分離出接口,如下圖所示的IView、IPresenter、IModel。

image

在抽象出來接口之後,那麼就需要實現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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章