關(guān)于MVP分層架構(gòu)在項(xiàng)目中的實(shí)際運(yùn)用

關(guān)于MVP的基本知識(shí)網(wǎng)上已經(jīng)有很多了,但是很多都只是Demo,畢竟Demo跟實(shí)際運(yùn)用之間還有無數(shù)個(gè)Debug,其實(shí)一開始我也看了很多關(guān)于MVP的介紹,其中有谷歌官方的Demo,還有很多技術(shù)博客,那個(gè)時(shí)候就覺得自己知道什么是MVP了,后來真正在自己項(xiàng)目中運(yùn)用的時(shí)候,才發(fā)現(xiàn)并不是那么簡(jiǎn)單,不過經(jīng)過一番折騰,逐漸對(duì)MVP有了比較深層次的認(rèn)識(shí),所以今天記錄分享一下。

MVP結(jié)構(gòu)示意圖

我自己畫了一個(gè)關(guān)系圖,也就是最簡(jiǎn)單的MVP結(jié)構(gòu)示意圖,我在這里并不會(huì)再解釋什么是MVP,今天我想把所有的認(rèn)知轉(zhuǎn)化為代碼,也就是圖中的關(guān)系圖,他們之間的關(guān)系我全部都是用Callback來進(jìn)行聯(lián)系的,也就是之前說的引用。

M層

  • 這里的M層不是傳統(tǒng)意義上的Model,我更傾向于認(rèn)為他是一個(gè)ModelManager,就是一個(gè)數(shù)據(jù)處理中心,可以處理網(wǎng)絡(luò)數(shù)據(jù),數(shù)據(jù)庫,文件以及關(guān)于Android中的四大組件的交互包含BroadcastReceiver,Service中的,都可以集中在這里面處理,有很長一段時(shí)間對(duì)于M的認(rèn)知都是覺得就是個(gè)實(shí)體類,那個(gè)時(shí)候還以為自己掌握地很透徹,最后發(fā)現(xiàn)自己理解的其實(shí)是不對(duì)的,MddelManager持有Presenter的引用,M處理完數(shù)據(jù)之后通過Callback回調(diào)Presenter,Presenter由于持有View的引用,所以可以回調(diào)View

V層

  • V就是指View(界面),往大了說是Activity或者Fragemnt,往小了說可以是一個(gè)Dialog、Toast或者Snakbar,具體就是直接跟用戶進(jìn)行打交道的,View會(huì)實(shí)現(xiàn)Callback接口,然后傳遞給Presenter,然后Presenter會(huì)去ModelManager進(jìn)行交互,然后數(shù)據(jù)處理完成之后,會(huì)通過Callback回調(diào)回來,這樣就完成了一個(gè)閉環(huán)

P層

  • P就是Presenter,主持人其實(shí)挺形象的,就起一個(gè)客串的作用,相當(dāng)于一座橋,來連接Vie跟ModelManger,很多文章是把邏輯在Presenter中進(jìn)行處理的,我覺得不是很好,我認(rèn)為在Modelmanager里面處理比較好,這樣解耦的更徹底,畢竟Presenter只是個(gè)中間的信使而已,不應(yīng)該處理過多的邏輯。

關(guān)系搞清楚了,其實(shí)代碼實(shí)現(xiàn)就比較簡(jiǎn)單

M層代碼

public class MainManager {
    private ViewCallBack mViewCallBack;

    public MainManager(ViewCallBack viewCallBack) {
        this.mViewCallBack = viewCallBack;
    }

    public void getData() {
        mViewCallBack.refreshView(1, "數(shù)據(jù)");
    }
}

這里面只是寫了一個(gè)模板,可能一個(gè)界面需要多種數(shù)據(jù)處理方式,那么就根據(jù)需求在重新定義幾個(gè)方法即可

V層代碼

public interface ViewCallBack<V> {

    /**
     * @param code code:0:有數(shù)據(jù),1:數(shù)據(jù)為空,2:加載失敗
     * @param data 定義好的數(shù)據(jù)類型
     */

    void refreshView(int code, V data);
}

這里的V采取泛型的原因在于每個(gè)界面需要獲取的數(shù)據(jù)不一樣,所以用泛型加以區(qū)分,當(dāng)一個(gè)界面需要獲取的接口很多,或者得到的數(shù)據(jù)結(jié)果類型不太一致的時(shí)候,這里的泛型就需要用Object來指定,然后在refreshView中通過數(shù)據(jù)的類型來判斷需要刷新的數(shù)據(jù)

P層代碼

public class MainPresenter {
    private ViewCallBack mViewCallBack;
    private MainManager mMainManager;

    public MainPresenter(ViewCallBack viewCallBack) {
        this.mViewCallBack = viewCallBack;
        mMainManager = new MainManager(mViewCallBack);
    }

    public void getData() {
        mMainManager.getData();
    }
}

P層代碼的方法跟Manager對(duì)應(yīng),然后處理M層跟V層的Callback即可,但是注意Presenter是一個(gè)對(duì)象,需要在界面銷毀的時(shí)候置空,防止內(nèi)存泄露

我在demo中只是簡(jiǎn)單寫了一個(gè)改變Text的值,當(dāng)然在Manager里面可以進(jìn)行任何你想要的操作,因?yàn)槭遣捎媒涌诨卣{(diào),運(yùn)行一下看看效果

MVP效果圖

持續(xù)封裝

上面的只是一個(gè)Demo,下面進(jìn)行封裝抽取,方便集成到真正的項(xiàng)目中去

  1. M層封裝
public abstract class BaseBeanManager {

    protected ViewCallBack mViewCallBack;
    protected HashMap<String, String> paramMap;

    public BaseBeanManager(ViewCallBack modelCallBack) {
        mViewCallBack = modelCallBack;
    }
    public abstract void getData();
}
  1. V層封裝

 public abstract class BaseActivity<T extends BasePresenter, V> extends AppCompatActivity implements ViewCallBack<V> {
    public T presenter;//泛型定義Presenter
    @TargetApi(Build.VERSION_CODES.M)
    @Override
    protected void onCreate(Bundle bundle) {
        super.onCreate(bundle);
        setContentView(getLayoutId());
        presenter = initPresenter();
        initViews();
        initListener();
    }
    
    @Override
    protected void onResume() {
        super.onResume();
        //初始化Presenter
        if (presenter == null)
            presenter = initPresenter();
            //添加Callback
        presenter.add((ViewCallBack) this);

    }
    protected abstract int getLayoutId();

    protected abstract void initViews();

    protected abstract void initListener();//初始化監(jiān)聽事件

    protected abstract T initPresenter();//初始化Presenter

    @Override
    protected void onDestroy() {
        super.onDestroy();
        //生命周期結(jié)束時(shí)銷毀callback,并置空presenter
        if (presenter != null){
             presenter.remove();
             presenter = null;

        }
    }
}
  1. P層封裝
public abstract class BasePresenter {
    protected BaseBeanManager mBeanManager;//定義基類manager
    protected HashMap<String, String> paramMap = new HashMap<>();
    protected ViewCallBack mViewCallBack;

    public BasePresenter(ViewCallBack viewCallBack) {
        mViewCallBack = viewCallBack;
    }


    public void add(ViewCallBack viewCallBack) {
        this.mViewCallBack = viewCallBack;
    }

    public void remove() {
        this.mViewCallBack = null;
    }
    //默認(rèn)的獲取數(shù)據(jù)的方法
    protected abstract void getData();


}

使用

  1. M層
public class MainManager extends BaseBeanManager {

    public MainManager(ViewCallBack modelCallBack) {
        super(modelCallBack);
    }

    public void getData() {
        mViewCallBack.refreshView(1, "MVP返回的數(shù)據(jù)");
    }
}

2.V層

public class MainActivity extends BaseActivity<MainPresenter, String> implements ViewCallBack<String> {
    private TextView tvDemo;
    private Button btnGet;
    @Override
    protected int getLayoutId() {
        return R.layout.activity_main;
    }

    @Override
    protected void initViews() {
        tvDemo = (TextView) findViewById(R.id.tv_demo);
        btnGet = (Button) findViewById(R.id.btn_get);
    }

    public void initListener() {
        btnGet.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                presenter.getData();
            }
        });
    }

    @Override
    protected MainPresenter initPresenter() {
        return new MainPresenter(this);
    }

    @Override
    public void refreshView(int code, String data) {
        tvDemo.setText(data);
    }

}
  1. P層
public class MainPresenter extends BasePresenter {

    public MainPresenter(ViewCallBack viewCallBack) {
        super(viewCallBack);
    }


    public void getData() {
        mBeanManager = new MainManager(mViewCallBack);
        mBeanManager.getData();
    }
}

本身是不想貼這么多代碼的,但是只有對(duì)比才能發(fā)現(xiàn),MVP由于解耦地比較徹底,所以滿足單一職責(zé)原則,新增了很多類,封裝之后,即使新建的類變多了,每個(gè)類都需要一個(gè)相應(yīng)的Presenter,但是代碼量很少,所以看起來邏輯比較清楚

這就是我的項(xiàng)目中正在使用的的MVP,剛開始從MVC轉(zhuǎn)換過來的時(shí)候很不習(xí)慣,后來折騰了一陣子,發(fā)現(xiàn)其實(shí)挺好用的。

項(xiàng)目下載地址

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容