此博文根据前面两篇文章 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布局