此博文根據前面兩篇文章 Android MVP 架構初試
Android MVP 架構封裝
再結合主流框架Retrofit2+Rxjava
來個實踐java
JuHeService 數據請求接口android
/** * 請求示例: * http://v.juhe.cn/dream/query * q:夢境關鍵字,如:黃金 須要utf8 urlencode * cid:指定分類,默認所有 * full: 是否顯示詳細信息,1:是 0:否,默認0 */ public interface JuHeService { @GET("dream/query") Observable<HttpJuHeResult<List<JuHeDream>>> getDreams(@QueryMap Map<String, Object> options); }
HttpJuHeMethods 聚合解夢封裝的方法git
public class HttpJuHeMethods { public static final String BASE_URL = "http://v.juhe.cn/"; private static final int DEFAULT_TIMEOUT = 5; private Retrofit retrofit; private JuHeService juheService; //構造方法私有 private HttpJuHeMethods() { //手動建立一個OkHttpClient並設置超時時間 OkHttpClient.Builder httpClientBuilder = new OkHttpClient.Builder(); httpClientBuilder.connectTimeout(DEFAULT_TIMEOUT, TimeUnit.SECONDS); httpClientBuilder.addInterceptor(new HttpLoggingInterceptor().setLevel(HttpLoggingInterceptor.Level.BODY)).build(); retrofit = new Retrofit.Builder() .client(httpClientBuilder.build()) .addConverterFactory(GsonConverterFactory.create()) .addCallAdapterFactory(RxJavaCallAdapterFactory.create()) .baseUrl(BASE_URL) .build(); juheService = retrofit.create(JuHeService.class); } //在訪問HttpMethods時建立單例 private static class SingletonHolder{ private static final HttpJuHeMethods INSTANCE = new HttpJuHeMethods(); } //獲取單例 public static HttpJuHeMethods getInstance(){ return SingletonHolder.INSTANCE; } /** * 用來統一處理Http的resultCode,並將HttpResult的Data部分剝離出來返回給subscriber * * @param <T> Subscriber真正須要的數據類型,也就是Data部分的數據類型 */ private class HttpResultFunc<T> implements Func1<HttpJuHeResult<T>, T> { @Override public T call(HttpJuHeResult<T> httpResult) { if (httpResult.getError_code() != 0) { throw new ApiException(httpResult.getError_code()); } return httpResult.getResult(); } } private <T> void toSubscribe(Observable<T> observable, Subscriber<T> subscriber){ observable.subscribeOn(Schedulers.io()) .unsubscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe(subscriber); } /** * 用於獲取聚合笑話的數據 * @param subscriber 由調用者傳過來的觀察者對象 * @param options 訪問參數 */ public void getJokesByHttpResultMap(Subscriber<List<JuHeDream>> subscriber, Map<String, Object> options){ // juheService.getJokesByRxJavaHttpResult(options) // .map(new HttpResultFunc<JuHeDream>()) // .subscribeOn(Schedulers.io()) // .unsubscribeOn(Schedulers.io()) // .observeOn(AndroidSchedulers.mainThread()) // .subscribe(subscriber); Observable<List<JuHeDream>> observable = juheService.getDreams(options) .map(new HttpResultFunc<List<JuHeDream>>()); toSubscribe(observable,subscriber); } }
其中包含異常的處理github
public class ApiException extends RuntimeException{ public final static int TIME_MUST_10=209501; public final static int TIME_OTHER=209502; public ApiException(int resultCode) { this(getApiExceptionMessage(resultCode)); } public ApiException(String detailMessage) { super(detailMessage); } /** * 因爲服務器傳遞過來的錯誤信息直接給用戶看的話,用戶未必可以理解 * 須要根據錯誤碼對錯誤信息進行一個轉換,在顯示給用戶 * @param code * @return */ private static String getApiExceptionMessage(int code){ String message = ""; switch (code) { case TIME_MUST_10: message = "必須爲10位時間戳"; break; case TIME_OTHER: message = "page、pagesize必須爲int類型,time爲10位時間戳"; break; default: message = "未知錯誤"; } return message; } }
請參考上篇文章 Android MVP 架構封裝
服務器
MvpView架構
public interface MvpView extends BaseView { //ListView的初始化 void setListItem(List<JuHeDream> data); //Toast 消息 void showMessage(String messgae); }
MvpPresenterapp
public class MvpPresenter extends BasePresenter<MvpView> { private Context mContext; private Subscriber subscriber; private List<JuHeDream> mDatas; public MvpPresenter(Context context) { this.mContext = context; } //獲取數據 public void getData(String q) throws UnsupportedEncodingException { if (q.isEmpty()) { mView.showMessage("請輸入解夢內容"); return; } mView.showLoading(); getDream(q); } public void onItemClick(int position) { List<String> stringList = mDatas.get(position).getList(); StringBuffer sbf = new StringBuffer(); for (String s : stringList) { sbf.append(s).append("\n\n\n"); } new SweetAlertDialog(mContext) .setTitleText(mDatas.get(position).getTitle()) .setContentText(sbf.toString()) .show(); } private void getDream(String q) throws UnsupportedEncodingException { String content = URLDecoder.decode(q, "utf-8"); Map<String, Object> options = new HashMap<String, Object>(); options.put("key", "f86ed9f21931cd311deffada92b58ac7"); options.put("full", "1"); options.put("q", content); subscriber = new Subscriber<List<JuHeDream>>() { @Override public void onCompleted() { mView.hideLoading(); } @Override public void onError(Throwable e) { mView.hideLoading(); mView.showMessage(e.toString()); } @Override public void onNext(List<JuHeDream> data) { for (JuHeDream juheDream:data) { Logger.e(juheDream.toString()); } mDatas = data; mView.setListItem(mDatas); } }; HttpJuHeMethods.getInstance().getJokesByHttpResultMap(subscriber,options); } public void destory(){ subscriber.unsubscribe(); } }
佈局文件框架
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:paddingBottom="@dimen/activity_vertical_margin" android:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin" android:orientation="vertical" tools:context=".view.MainActivity"> <LinearLayout android:layout_width="920px" android:layout_height="130px" android:layout_gravity="center_horizontal" android:layout_marginTop="20px" android:orientation="horizontal" > <LinearLayout android:layout_width="680px" android:layout_height="130px" android:background="@drawable/shape_query_normal_stroke" android:orientation="horizontal" > <ImageView android:layout_width="57px" android:layout_height="70px" android:layout_gravity="center_vertical" android:layout_marginLeft="40px" android:src="@drawable/login_yanzhengma" android:text="設置密碼" /> <View android:layout_width="0.5px" android:layout_height="match_parent" android:layout_marginLeft="40px" android:background="@color/line" /> <EditText android:id="@+id/id_dream_query" android:layout_width="wrap_content" android:layout_height="match_parent" android:layout_gravity="center_vertical" android:layout_marginLeft="13px" android:background="@null" android:hint="請輸入解夢的內容" android:singleLine="true" android:textColor="@color/textcolor" android:textSize="40px" /> </LinearLayout> <View android:layout_width="20px" android:layout_height="match_parent" /> <Button android:id="@+id/id_dream_btn" android:layout_width="0dp" android:layout_weight="1" android:layout_height="match_parent" android:background="@drawable/query" android:clickable="true" android:gravity="center" android:text="查詢" android:textColor="@android:color/white" android:textSize="40px" /> </LinearLayout> <ListView android:id="@+id/id_dream_result" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginTop="20dp" /> </LinearLayout>
MainActivityide
public class MainActivity extends BaseMvpActivity<MvpView, MvpPresenter> implements MvpView, AdapterView.OnItemClickListener { @BindView(R.id.id_dream_query) EditText dreamQuery; @BindView(R.id.id_dream_btn) Button dreamBtn; @BindView(R.id.id_dream_result) ListView listView; private Context mContext; MyAdapter myAdapter; SweetAlertDialog pd; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mContext = this; ButterKnife.bind(this); initEvent(); } private void initEvent() { listView.setOnItemClickListener(this); } @OnClick(R.id.id_dream_btn) public void onClick() { try { String q = dreamQuery.getText().toString(); presenter.getData(q); } catch (UnsupportedEncodingException e) { e.printStackTrace(); } } @Override public MvpPresenter initPresenter() { return new MvpPresenter(this); } @Override public void setListItem(List<JuHeDream> data) { if (myAdapter == null){ myAdapter = new MyAdapter(mContext, data); } if (listView.getAdapter() == null){ listView.setAdapter(myAdapter); } myAdapter.refresh(data); } @Override public void showMessage(String messgae) { Toast.makeText(mContext, messgae, Toast.LENGTH_SHORT).show(); } @Override public void showLoading() { if (pd == null) { pd = new SweetAlertDialog(mContext, SweetAlertDialog.PROGRESS_TYPE); pd.getProgressHelper().setBarColor(Color.parseColor("#A5DC86")); pd.setTitleText("Loading"); pd.setCancelable(true); } pd.show(); } @Override public void hideLoading() { pd.hide(); } @Override public void onItemClick(AdapterView<?> adapterView, View view, int position, long id) { presenter.onItemClick(position); } @Override protected void onDestroy() { presenter.destory(); super.onDestroy(); } }
源碼地址:https://github.com/Javen205/RxMVP佈局