Android MVP模式基類結構
阿新 • • 發佈:2019-02-01
相信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繪製、請求傳送,對於請求的結果處理幾乎不用再花費什麼工作量。特別是對於以列表為主體的介面而言,由於存在多種重新整理機制,同時也存在多種出錯機制,如果從頭寫非常麻煩。而如果在此結構上開發,感覺就會像由地獄來到了天堂...