preface

When the MVP mode first came out, I also read a lot about it. To tell you the truth, after reading only have a general understanding, let me write a really do not come out. Because the project is flexible and complex, if you want to skillfully use the MVP mode, you have to practice, gradually improve and optimize.

start

What follows is a summary of my own project. Because the level is limited, if there is any misunderstanding, please correct, so as not to mislead others.

① View why I will say View first, because View is visible, can interact with the user, will give us a kind of most intuitive feeling. MvpView: This is my simple encapsulation of View, which includes loading of the page, errors or prompts that may occur in the current page, and operations for keyboard visibility. Here you modify and add according to your business needs.

public interface MvpView {

    void showLoading();

    void hideLoading();

    void onError(@StringRes int resId);

    void onError(String message);

    void showMessage(@StringRes int resId);

    void showMessage(String message);

    void hideKeyboard();

}
Copy the code

My Presenter is associated with an Activity/Fragment important lifecycle method. There is also a unified management of errors in the page.

public interface MvpPresenter<V extends MvpView> {

    void onAttach(V mvpView);

    void onDetach();

    boolean handleApiError(String error);

    void handleException(Throwable throwable);

    void setUserLoggedOut();

}
Copy the code

Let’s implement this Presenter.

public class BasePresenter<V extends MvpView> implements MvpPresenter<V> { private Reference<V> mViewRef; private final SchedulerProvider mSchedulerProvider; private CompositeDisposable mCompositeDisposable; Public BasePresenter () {/ / the thread scheduler instance mSchedulerProvider = AppSchedulerProvider. GetInstance (); } // instantiate CompositeDisposable, Protected void addDisposable(Disposable) {if (mCompositeDisposable == null) {mCompositeDisposable = new CompositeDisposable(); } mCompositeDisposable.add(disposable); } /** * Dispose (){if (mCompositeDisposable! = null) { mCompositeDisposable.dispose(); } } @Override public void onAttach(V mvpView) { mViewRef = new WeakReference(mvpView); Override public void onDetach() {dispose(); ReferenceClear(); Private void ReferenceClear(){if (mViewRef! = null) { mViewRef.clear(); mViewRef = null; } } public boolean isViewAttached() { return mViewRef ! = null; } public V getMvpView() { return mViewRef.get(); } public SchedulerProvider getSchedulerProvider(){ return mSchedulerProvider; } public CompositeDisposable getCompositeDisposable(){ return mCompositeDisposable; } public void checkViewAttached() { if (! isViewAttached()) throw new MvpViewNotAttachedException(); @override public Boolean handleApiError(String Content) {Boolean error = ApiEmptyError.isError(content); boolean isDialogShow = ApiEmptyError.getIsDialogShow(); boolean needAgainLog = ApiEmptyError.getIsNeedAgainLog(); String msg = JsonParse.getSuccessStatusMsg(content, "msg"); If (error && isDialogShow) {// Return true; }else if(error && needAgainLog){// Need to log in setUserAsLoggedOut(); return true; }else if(error){// toast getMvpView().onerror (MSG); return true; } return false; } /** * Handle Throwable types, such as network exceptions, Param throwable */ @override public void handleException(throwable throwable) {String throwstr = ApiException.setThrowable(throwable); LogUtil.debug("handleException----->"+throwstr); } public void setUserLoggedOut() {//TODO Override public void setUserLoggedOut() {//TODO Override public static class MvpViewNotAttachedException extends RuntimeException {public MvpViewNotAttachedException () {super (" the Presenter before the request data, Call Presby. onAttach(MvpView)"); }}}Copy the code

Next, it’s time to implement the methods in the interface.

public abstract class MvpBaseFragment<V extends MvpView, P extends MvpPresenter> extends Fragment implements MvpView { protected P mPresenter; protected List<P> mListPresenter; protected ProgressDialog mProgressDialog; Public void onViewCreated(View View, Bundle savedInstanceState) {super.onViewCreated(View, Bundle savedInstanceState) savedInstanceState); mListPresenter = new ArrayList<>(); if (mPresenter == null) { mPresenter = createPresenter(); } if (mListPresenter == null) { mListPresenter = createListPresenter(); } // Override public void onDestroyView() {super.onDestroyView(); if (mPresenter ! = null) { mPresenter.onDetach(); } if (mListPresenter ! = null && mListPresenter.size() > 0) { for (P p : mListPresenter) { p.onDetach(); } mListPresenter.clear(); Public void showLoading() {if (mProgressDialog == null) {mProgressDialog = new ProgressDialog(getActivity()); } mProgressDialog.show(); } // hideLoading @override public void hideLoading() {if (mProgressDialog! = null) { mProgressDialog.cancel(); @override public void onError(int resId) {} @override public void onError(string message) { showShortToast(message); @override public void showMessage(int resId) {} public void showMessage(string  message) { showMessage(message); Override public void hideKeyboard() {return createListPresenter(){return createListPresenter() mListPresenter; } // A single Presenter protected P createPresenter(){return mPresenter; }}Copy the code

Above I used an ArrayLIst to store multiple presenters. Because when I actually use it, if there’s a lot of content on the page, if I use a Presenter, all the stuff is added to that Presenter, and it still looks bloated. So I decided to split it up into multiple presenters to share the workload.

Ok, the general encapsulation we have completed, the following is the specific use.

public class HomeFragment extends MvpBaseFragment implements HomeMvpView { private HomePresenter<HomeMvpView> mPresenter; @Override public void beforeViewData() { } @Override public View initLayout(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { return LayoutInflater.from(getActivity()).inflate(R.layout.fragment_home_layout, container,false); } @Override public void initView(View view, Bundle savedInstanceState) { initPresenter(); } // Instantiate Presenter private void initPresenter(){mPresenter = new HomePresenter<>(); mPresenter.onAttach(this); Public void showBanner(List<BannerImageInfo> adInfos) {} public void showBanner(List<BannerImageInfo> adInfos) requestNetData() { mPresenter.downloadBanner(); } @override public void onClick(View View) { @override protected MvpPresenter createPresenter() {return mPresenter; }}Copy the code

HomeMvpView.java

Public Interface Home Max extends MvpView{void showBanner(List<BannerImageInfo> adInfos); public Interface Home Max extends MvpView{void showBanner(List<BannerImageInfo> adInfos); }Copy the code

HomeMvpPresenter.java

Public interface Home VpPresenter <V extends Home vpView & MvpView> extends MvpPresenter<V> {/*** * download Banner */  void downloadBanner(); }Copy the code

HomePresenter.java

public class HomePresenter<V extends HomeMvpView & MvpView> extends BasePresenter<V> implements HomeMvpPresenter<V> { @Override public void downloadBanner() { addDisposable(HttpMethods.getInstance().getApiHepler() .downloadBanner(HttpMethods.BASE_URL + "/v1/default/slider") .subscribeOn(getSchedulerProvider().io()) .observeOn(getSchedulerProvider().ui()) .subscribe(new DefaultConsumerAccept(){ @Override public void onSuccess(String response) { super.onSuccess(response); BannerImageModel model = JsonParse.parseJson(response, BannerImageModel.class); ArrayList<BannerImageInfo> list = model.getData().getList(); getMvpView().showBanner(list); } @Override public void showErrorDialog() { super.showErrorDialog(); } @Override public void setUserLoggedOut() { super.setUserLoggedOut(); } @Override public void showErrorMsg(String msg) { super.showErrorMsg(msg); }})); }Copy the code

In the MvpPresenter section I wrapped exception handling in it, but later I found a better way to handle exceptions and errors (just do it as you like). To encapsulate Consumer. Here is my simple encapsulation.

public class DefaultConsumerAccept<T> implements Consumer<T> { @Override public void accept(T t) throws Exception { if(handleApiError((String) t)){ return; } onSuccess((String) t); } public Boolean handleApiError(String Content) {//ApiEmptyError is an error classification based on project requirements Boolean error = ApiEmptyError.isError(content); boolean isDialogShow = ApiEmptyError.getIsDialogShow(); boolean needAgainLog = ApiEmptyError.getIsNeedAgainLog(); String msg = JsonParse.getSuccessStatusMsg(content, "msg"); If (error && isDialogShow) {// Show a dialog box to prompt showErrorDialog(); return true; }else if(error && needAgainLog){// Need to log in setUserLoggedOut(); return true; }else if(error){// toast showErrorMsg(MSG); return true; } return false; } public void onSuccess(String response){ } public void showErrorDialog(){ } public void setUserLoggedOut(){ } public void showErrorMsg(String msg){ } }Copy the code

That’s about it. We can also wrap the Consumer so that we can better handle exceptions and errors in requests. Such as:

public class DefaultConsumerThrowable<T> implements Consumer<Throwable>{ @Override public void accept(Throwable throwable) throws Exception { handleException(throwable); } /** * Handle Throwable types, such as network exceptions, @param throwable */ public void handleException(throwable throwable) {//ApiException encapsulates the exception handling class String throwstr = ApiException.setThrowable(throwable); showErrorMsg(throwstr); } private void showErrorMsg(String error){ } }Copy the code

So much for MVP usage.

Related video

Andorid Advanced learning project architecture /MVC/MVP/MVVM