Android MVP模式基类结构

相信MVP模式在Android程序中已经使用的非常广泛了,下面我来介绍一种MVP模式的基类结构。




整个结构以Fragment为核心,首先定义了BaseFragment继承于Fragment,主要是实现了把要加载的Fragment作为参数的launch方法,并在launch方法中实际加载绑定了目标Fragment的BaseActivity。除此之外,BaseFragment中还实例化并保存了一系列helper,比如viewHelper,dialoagHelper,broadCastHelper等等,从而可以在子类中方便的处理相关任务。

    public void launch(Class<? extends Fragment> fragment,
                       Bundle args4fragment, int reqCode) {
        launch(BaseActivity.class, fragment, args4fragment, reqCode);
    }

    public void launch(Class<? extends BaseActivity> activity,
                       Class<? extends Fragment> fragment, Bundle args4fragment, int reqCode) {
        if (getActivity() == null || isDetached()) {
            return;
        }
        Intent in = BaseActivityHelper.builder(this, activity).setFragment(fragment, args4fragment).build();
        if (reqCode != 0) {
            getHostFragment().startActivityForResult(in, reqCode);
        } else {
            getHostFragment().startActivity(in);
        }
    }


随后的子类BaseLinearFragment,则是在BaseFragment的基础上加载了一个包含两个ViewStub的layout,并依照head和body的区分又定义了一些方法。

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    android:id="@+id/content"
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <ViewStub
        android:id="@+id/head"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout="@layout/navbar"/>

    <ViewStub
        android:id="@+id/body"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>
</LinearLayout>

    @Override
    protected final void initInflateViewStub(View parent) {
        super.initInflateViewStub(parent);
        int headLayoutId = getHeadLayoutId();
        if (headLayoutId != EmptyConst.EMPTY_ID) {
            setupHead(viewHelper.inflateViewStub(R.id.head, headLayoutId));
        }
        setupBody(viewHelper.inflateViewStub(R.id.body, getBodyLayoutId()));
    }

    @LayoutRes
    protected int getHeadLayoutId() {
        return R.layout.navbar;
    }


到了BaseRequestFragment这,就开始处理网络请求相关的任务了。它实现了IRequestView接口,可以依照 成功获取数据/成功但数据为空/请求失败 三种情况来处理网络请求的结果。


public interface IRequestView {

    void showLoading();

    void showContent();

    void showEmpty();

    @DrawableRes
    int getEmptyImageResId();

    String getEmptyText();

    void showError();
}

同时相应的BaseRequestPresenter实现了IPresenter接口,可以对IRequestView进行绑定,并持有IRequestView。

public interface IPresenter<V extends IRequestView> {

    void attachView(V view);

    void detachView(V view);
}

SingleRequestFragment则在BaseRequestFragment的基础上终于建立起MVP模式,通过SingleRequestContract来和SingleRequestPresenter相互持有,用来处理加载Fragment时要发Api来获取一个数据结构进行渲染的情形。

public interface SingleRequestContract {

    interface View<T> extends IRequestView {

        Context getContext();

        void render(@NonNull T data);
    }

    interface Presenter<T> extends IPresenter<View<T>> {

        void onSaveInstanceState(Bundle outState);

        void restoreSavedInstance(Bundle savedInstanceState);
        
        void load(@Nullable RequestCallback<T> callback);
    }
}


ListRequestFragment同样是继承于BaseRequestFragment,但却比SingleRequestFragment复杂的多。它是用来处理要发Api来获取一个列表,并以listView为主体的Fragment。为此,ListRequestFragment持有一个listView,实现了与此listView相关的下拉刷新、加载更多、列表为空、列表加载错误等诸多方法。

public interface RequestListContract {

    interface View<ListItem> extends IRequestView {

        void renderDataList(List<ListItem> dataList, boolean canLoadMore, boolean refresh);

        void toastNetworkError(NetApiException error);

        void showNetworkError(boolean refresh);

        boolean showListLoading();

        void dismissListLoading();
    }

    interface Presenter<ListItem> extends IPresenter<View<ListItem>> {

        void load();

        void refresh(boolean showListLoading);

        void loadMore();
    }
}

而相应的SingleRequestPresenter和ListRequestPresenter除了实现Contract中的方法之外,主要是实现了一个默认回调DefaultCallback,在其中对返回的结果进行了处理。如果请求成功,则进行数据解析,并把解析后的结构传给Fragment进行渲染。



综上所述,使用这套MVP基类结构,并把它与网络请求库(Volley、Retrofit)、数据解析库(gson)搭配使用后,开发者可以专注于UI绘制、请求发送,对于请求的结果处理几乎不用再花费什么工作量。特别是对于以列表为主体的界面而言,由于存在多种刷新机制,同时也存在多种出错机制,如果从头写非常麻烦。而如果在此结构上开发,感觉就会像由地狱来到了天堂...

猜你喜欢

转载自blog.csdn.net/wlkdb/article/details/74369799