Android之通用MVP模式框架

Android之通用MVP模式框架

在最近的學習中,我寫代碼都一直在使用通用的MVP模式框架,在使用的過程中,最讓我感觸非常深的是,整個代碼的層次感非常清晰,耦合度非常低,擴展非常方便,以及能很好的處理Presenter和View直接內存溢出情況。如果你在寫代碼,我非常建議你使用這種框架下,下面請跟着我的思路走吧。

1、先看以下的構架:

這裏寫圖片描述

在這裏你將看到model層下的BaseModelInter、presenter層下的BasePresenter、view層下的BaseViewInter。下面我們來看看這兩個接口,以及一個抽象類的代碼。

BaseModelInter.java

public interface BaseModelInter {
}

BaseViewInter.java

public interface BaseViewInter {
}

BasePresenter.java

public abstract class BasePresenter<T extends BaseViewInter, M extends BaseModelInter> {
    private WeakReference<T> weakReference;
    protected M model;
    public void attach(T t) {
        weakReference = new WeakReference<>(t);
        model = getModel();
    }

    public void deAttach() {
        if (weakReference != null) {
            weakReference.clear();
            weakReference = null;
        }
    }

    public boolean isViewAttached() {
        return weakReference != null && weakReference.get() != null;
    }

    public T getView() {
        if (weakReference != null) {
            return weakReference.get();
        }
        return null;
    }
    protected abstract M getModel();
}

然後你會發現,我艹,怎麼那兩個接口中怎麼什麼都沒寫,你也把和這個代碼貼上來了,是不是找幹啊?沒錯,我就是要貼上來,就是不怕你幹我!好了,開個小玩笑,迴歸正題,其實這樣定義兩個接口主要是爲了擴展子接口,擴展子功能的,因爲我們的主題是爲了打造通用的框架,那它到底能擴展什麼呢?接着往下看你就知道了。然後再看這個抽象類BasePresenter,這個抽象類,最關鍵的就是解決Presenter和view直接在長時間請求網絡數據的情況下,爲了防止內存溢出而設計的,我們通過一個虛引用就能很好的解決這個問題了。然後attach方法主要是將需要與具體的presenter類做綁定的view關聯起來,並且將對應的model也綁定起來。而這個view類剛好是屬於BaseViewInter下的子類。deAttach方法主要是當view向presenter請求數據時,由於網絡請求時間過長,而view直接銷燬了,而presenter沒有即使返回數據,則deAttach就會把對應的view取消關聯。isViewAttached方法判斷view與presente是否關聯,getView是返回一個綁定好的view對象,getModel方法則是讓具體的presenter子類去創建具體的model對象。

2.下面看一個具體的實例:

FirstActiviy界面一需要向他對應的presenter層的FirstActivityPresenter請求數據AAAA,然後presenter去找與其具體對應的model層FirstActivityModelImp去拿數據。然後將數據返回給FirstActivity。

框架結構如下:

這裏寫圖片描述

首先先看看BaseActivity.java和FirstActivity.java的代碼:

BaseActivity.java

public abstract class BaseActivity<T extends BasePresenter,V extends BaseViewInter> extends AppCompatActivity {
    protected T presenter;//③
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);//④
        presenter = getPresenter();//⑤
        presenter.attach((V)this);//⑦
    }

    protected abstract T getPresenter();

    @Override
    protected void onDestroy() {
        super.onDestroy();
        presenter.deAttach();
    }
}

FirstActivity.java

public class FirstActivity extends BaseActivity<FirstActivityPresenter,FirstActivity> implements FirstActivityViewInter {

    private TextView mTv; //①
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);//②
        setContentView(R.layout.first_activity);//⑧
        mTv = (TextView)findViewById(R.id.mTv);//⑨
        presenter.load("我是第一個view,我要獲取數據,請presenter爲我拿回一個字符串AAAA");//10
    }

    @Override
    public void doSth(String data) {
        Log.i("IT_Real", "doSth: 我獲取了字符串" + data);
        mTv.setText("我拿到的數據是:" + data);
    }

    @Override
    protected FirstActivityPresenter getPresenter() {//⑥
        return new FirstActivityPresenter();
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
    }

從上面代碼看firstActivity繼承了BaseActivity類。大家看看上面的執行順序吧。從上面的10個順序中,大家應該能理解吧, FirstActivity類首先開始執行,然後第6步將一個具體的FirstActivityPresenter返回給了父類的presenter。然後第7步是將FirstActivity和presenter進行關聯。最後執行第10步向具體的FirstActivityPresenter請求數據AAAA。

FirstActivityPresenter.java

public class FirstActivityPresenter extends BasePresenter<FirstActivity,FirstActivityModelImp> {

    @Override
    protected FirstActivityModelImp getModel() {
        return new FirstActivityModelImp();
    }

    public void load(String request){
        model.dealSth(request,new OnSendStrListener() {
            @Override
            public void sendAAAA(String aaaa) {
                getView().doSth(aaaa);
            }
        });
    }
}

load方法主要是向model去拿具體的數據,然後將具體的數據返回給view層。這個類繼承了BasePresenter類,可以看到,我們可以通過getView很好的拿到關聯的FirstActivity類的具體實例,也能通過model拿到FirstActivityModelImp的具體實例。這樣FirstActivityPresenter不持有FirstActivity的引用,就避免了內存溢出的發生。

FirstActivityViewInter.java

public interface FirstActivityViewInter extends BaseViewInter{
    void doSth(String data);
}

上面這個接口中提供的就是所有FirstActivity中需要實現的功能,包括以後需要具體擴展FirstActivity中功能等,非常方便。

最後看看Model層中的類

FirstActivityModelInter.java

/**
* 所有FirstModelImp中需要實現的數據操作功能,以後需要操作上面功能,直接在這個接口中添加即可,
* 擴展性好。
*/
public interface FirstActivityModelInter extends BaseModelInter{
    void dealSth(String request,OnSendStrListener listener);
}

OnsendStrListener.java

/**
* 具體要處理數據的回調接口,因爲View需要一個字符串AAAA,所以就給他提供一個方法發回一個字符串
* 具體的功能自己定義即可,這裏不統一,根據實際需求
*/
public interface OnSendStrListener {
    void sendAAAA(String aaaa);
}

FIrstActiviyModelImp.java

public class FirstActivityModelImp implements FirstActivityModelInter {
    /**
    * 將具體的數據返回給FirstActivityPresenter,實現具體的數據操作功能。
    */
    @Override
    public void dealSth(String request, OnSendStrListener listener) {
        if (request.equals("我是第一個view,我要獲取數據,請presenter爲我拿回一個字符串AAAA")){
            Log.i("IT_Real", "dealSth: presenter需要一個AAAA數據,我要返回一個AAAA數據");
            //接口回調該方法,就是將AAAA發回給presenter
            listener.sendAAAA("AAAA");
        }
    }
}

通過上面的具體實現,在以後的項目中,我們可以擴展非常方便,這裏我只實例了一個界面需要處理的功能,以及請求上面數據等。如果說以後你需要擴展多個界面,就像我一樣,在view包下的activity下新建一個SecondActiviy類即可,然後該類繼承BaseActivity,創建一個新的SecondViewInter (需要繼承BaseViewInter),將所有功能寫入到其中,然後讓SecondActivity類去實現即可,next創建對應的SecondPresenter,去繼承BasePresenter。處理一些事情即可,最後同樣寫一個SecondModelImp類,去實現SecondModleInter接口(需要繼承BaseModelInter)中的具體功能即可。。。這樣一來,我們的層次會非常清晰,然後擴展功能也非常方便,耦合也非常低,源代碼上傳一下,希望大家也可以養成這樣的好習慣,建議使用這種模式寫代碼,對以後的工作會有很大的幫助哦。

源代碼

發佈了58 篇原創文章 · 獲贊 19 · 訪問量 9萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章