從0開始搭建MVP+ViewModel框架的android應(yīng)用01---MVPVM誕生記

對比MVC/MVP/MVVM

  • MVC:經(jīng)典的模式,model,view,controller,比較好理解,但是有些缺點(diǎn),承擔(dān)View角色的模塊包含了過多的業(yè)務(wù)邏輯
  • MVP:衍生于MVC,雖然View和業(yè)務(wù)解耦了,但是Presenter承擔(dān)了太多任務(wù)
  • MVVM:采用DataBinding,數(shù)據(jù)的渲染自動反映在ViewModel上,同時也可以通過ViewModel獲取數(shù)據(jù),但是業(yè)務(wù)處理堆在一塊。

基于此,想讓處理不同事情的模塊獨(dú)立起來,通過接口解耦,Presenter只負(fù)責(zé)remote data/native data的獲取,然后由ViewModel把數(shù)據(jù)跟View綁定起來,汲取MVP和MVVM所長,于是有了MVPVM。

補(bǔ)充:對于架構(gòu)模式的搭建,沒法說哪種更好,只有哪種更合適,不要局限于架構(gòu),結(jié)合業(yè)務(wù)特性,現(xiàn)有的人力和任務(wù)時間(采用架構(gòu)代碼量一般會增加,但是結(jié)構(gòu)會清晰),選取適合的框架。

MVPVM

參照MVP模式,采取contract接口隔離的方式,分離出View,Presenter,ViewWapper;Activity/Fragment實現(xiàn)View接口,提供Context下的API調(diào)用等,Presenter實現(xiàn)當(dāng)前模塊的業(yè)務(wù)數(shù)據(jù)獲取,ViewWrapper則負(fù)責(zé)把數(shù)據(jù)傳遞給ViewModel實現(xiàn)數(shù)據(jù)綁定,以及View傳遞的Event處理。如下圖:

mvp_vm_structure.jpg

抽離出Base類。

  • BaseView ——— 抽象出來的需要Context環(huán)境的調(diào)用接口
  • Presenter ——— 為實現(xiàn)架構(gòu)搭建,由BasePresenter實現(xiàn)接口
  • ViewWrapper ——— 為實現(xiàn)架構(gòu)搭建,由BaseViewWrapper實現(xiàn)接口
  • BaseActivity ——— 抽象出來的Base,即可由MvpVmActivity繼承,也可由業(yè)務(wù)Activity繼承
  • BasePresenter ——— 抽象出來的MvpVm架構(gòu)的Presenter基類
  • BaseViewWrapper ——— 抽象出來的MvpVm架構(gòu)的ViewWrapper基類
  • MvpVmActivity ——— 抽象出來的MvpVm架構(gòu)的Activity基類
  • MvpVmFragment ——— 抽象出來的MvpVm架構(gòu)的Fragment基類
  • DemoActivity

BaseView

public interface BaseView {

    public void setTitle(int titleId);
    
    public void setTitle(String title);
    
    public void showToast(int resId);
    
    public void showToast(String msg);
    
    public void showWaitDialog(int resId);
    
    public void showWaitDialog(String message);

    ....
    
}

Presenter

public interface Presenter<V, VW> {
    void attachView(V view);
    
    void setViewWrapper(VW viewWrapper);
    
    void detachView();
}

ViewWrapper

public interface ViewWrapper<V, D> {
    void attachView(V view);
    
    void detachView();
    
    void setBinding(D dataBinding);
    
    void onBind();
}

BaseActivity

public class BaseActivity<D extends ViewDataBinding> extends AppCompatActivity implements BaseView {

    ...
    
    protected D dataBinding;
    protected BaseActivity activity;
    private BaseActivityDataBinding baseBinding;

    protected <D extends ViewDataBinding> D generateDataBinding(@LayoutRes int layoutResID) {
        D binding;
        if (hasToolBar()) {
            baseBinding = DataBindingUtil.setContentView(this, R.layout.activity_base);
            
            ...
            
            LayoutInflater inflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
            binding = DataBindingUtil.inflate(inflater, layoutResID, baseBinding.contentLayout, true);
        } else {
            binding = DataBindingUtil.setContentView(this, layoutResID);
        }
        activity = this;
        
        ...
        
        return binding;
    }
}

generateDataBinding替換一般情況下調(diào)用的setContentView(int layoutId),在業(yè)務(wù)Avtivity中第一步調(diào)用dataBinding = generateDataBinding(R.layout.xxx)即返回對應(yīng)layout的DataBinding,用法后面demo中將會介紹。

BasePresenter

public class BasePresenter<V, VW> implements Presenter<V, VW> {

    public V view;
    protected VW viewWrapper;
    ...
    
    @Override
    public void attachView(V view) {
        this.view = view;
    }
    
    @Override
    public void setViewWrapper(VW viewWrapper) {
        this.viewWrapper = viewWrapper;
    }
    
    @Override
    public void detachView() {
        view = null;
        viewWrapper = null;
        ...
    }
    
    ...
    
}

BaseViewWrapper

public class BaseViewWrapper<V, D extends ViewDataBinding> implements ViewWrapper<V, D> {
    protected V view;
    protected D dataBinding;
        
    @Override
    public void attachView(V view) {
        this.view = view;
    }
        
    @Override
    public void detachView() {
        view = null;
        if (dataBinding != null) {
            dataBinding.unbind();
            dataBinding = null;
        }
    }
        
    @Override
    public void setBinding(D dataBinding) {
        this.dataBinding = dataBinding;
        onBind();
    }

    @Override
    public void onBind() {
        
    }
    
}

onBind方法由業(yè)務(wù)ViewWrapper實現(xiàn),具體操作為DataBinding的數(shù)據(jù)綁定,以及l(fā)istener等事件的設(shè)置,會在后續(xù)博客中詳細(xì)介紹。

MvpVmActivity

public abstract class MvpVmActivity<P extends BasePresenter, VW extends BaseViewWrapper, D extends ViewDataBinding>
extends BaseActivity<D> {

    protected P presenter;
    protected VW viewWrapper;
    
    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        presenter = createPresenter();
        viewWrapper = createViewWrapper();
        if (presenter != null && viewWrapper != null) {
            presenter.setViewWrapper(viewWrapper);
        }
    }
    
    protected abstract P createPresenter();
    
    protected abstract VW createViewWrapper();
    
    @Override
    protected void onDestroy() {
        if (presenter != null) {
            presenter.detachView();
        }
        if (viewWrapper != null) {
            viewWrapper.detachView();
        }
        if (dataBinding != null) {
            dataBinding.unbind();
            dataBinding = null;
        }
        super.onDestroy();
    }
}

createPresenter和createViewWrapper由業(yè)務(wù)Activity繼承實現(xiàn),實例化對應(yīng)業(yè)務(wù)的Presenter和ViewWrapper,后續(xù)博客會詳細(xì)介紹。

MvpVmFragment

public abstract class MvpVmFragment<P extends BasePresenter, VW extends BaseViewWrapper, D extends ViewDataBinding>
    extends BaseFragment<D> {
    
    protected P presenter;
    protected VW viewWrapper;
    
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        presenter = createPresenter();
        viewWrapper = createWrapper();
        if (presenter != null && viewWrapper != null) {
            presenter.setViewWrapper(viewWrapper);
        }
    }
    
    protected abstract P createPresenter();
    
    protected abstract VW createWrapper();
    
    @Override
    public void onDestroyView() {
        if (presenter != null) {
            presenter.detachView();
        }
        if (viewWrapper != null) {
            viewWrapper.detachView();
        }
        if (dataBinding != null) {
            dataBinding.unbind();
            dataBinding = null;
        }
        super.onDestroyView();
    }
}

createPresenter和createViewWrapper由業(yè)務(wù)Activity繼承實現(xiàn),實例化對應(yīng)業(yè)務(wù)的Presenter和ViewWrapper,但是DataBinding實例的獲取與在Activity中略有不同,是在onCreateView中獲取的,后續(xù)博客會詳細(xì)介紹。

DemoActivity

public class MvpVmDemoActivity extends MvpVmActivity<MvpVmDemoPresenter, MvpVmDemoViewWrapper, MvpVmDemoDataBinding>
    implements MvpVmDemoContract.View {
    
    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        dataBinding = generateDataBinding(R.layout.activity_mvpvm_demo);
        if (viewWrapper != null) {
            viewWrapper.setBinding(dataBinding);
        }
        presenter.fetchData();
    }
    
    @Override
    protected MvpVmDemoPresenter createPresenter() {
        return new MvpVmDemoPresenter(this);
    }
    
    @Override
    protected MvpVmDemoViewWrapper createViewWrapper() {
        return new MvpVmDemoViewWrapper(this);
    }
    
    ...
    
}

從代碼中可以看到,在onCreate第一步就是生成對應(yīng)的DataBinding實例(關(guān)于DataBinding會在后續(xù)博客中專門講一次),然后設(shè)置給ViewWrapper,實現(xiàn)數(shù)據(jù)綁定關(guān)系,在createPresenter和createViewWrapper中實例化對應(yīng)業(yè)務(wù)的presenter和viewWrapper。

截至到此,MVPVM的Base框架就大體搭起來了,后續(xù)還會更新基于此框架的業(yè)務(wù)細(xì)節(jié)實現(xiàn)(Adapter、RecyclerView、DataBinding的高級用法以及網(wǎng)絡(luò)請求框架Retrofit二次封裝等)

才疏學(xué)淺,板磚輕拍

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

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

  • MVP這種架構(gòu)在Android界已經(jīng)基本成為標(biāo)配,MVP本身也有很多寫法和變種,當(dāng)然,沒有最好的架構(gòu),只有最合適的...
    藍(lán)灰_q閱讀 1,600評論 0 12
  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 179,113評論 25 709
  • 作者:李旺成 時間:2016年4月3日 “Android MVP 詳解(下)”已經(jīng)發(fā)布,歡迎大家提建議。 MVP ...
    diygreen閱讀 129,343評論 85 1,321
  • 將運(yùn)營工作拆分成以下四個核心環(huán)節(jié): 1、找到用戶在哪 用戶畫像,調(diào)查,需求分析等工作,沒錯,你需要理解你的產(chǎn)品,哪...
    獵人PENN閱讀 1,471評論 0 0
  • 我走過很多個地方 卻一直把你的書簽留在身旁 看著這些個細(xì)小的褶皺在書房里飄蕩 聽得清的是房間的流光 整夜整夜寂寥的...
    夙音閱讀 233評論 0 1

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