此博文根据前面两篇文章 Android MVP 架构初试
Android MVP 架构封装
再结合主流框架Retrofit2+Rxjava
来个实践
源码地址RxMVP
项目截图
Retrofit2+Rxjava 封装
JuHeService 数据请求接口
/**
* 请求示例:
* 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 聚合解梦封装的方法
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);
}
}
其中包含异常的处理
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;
}
}
BaseMvp封装
请参考上篇文章 Android MVP 架构封装
Retrofit2+Rxjava+MVP实践
MvpView
public interface MvpView extends BaseView {
//ListView的初始化
void setListItem(List<JuHeDream> data);
//Toast 消息
void showMessage(String messgae);
}
MvpPresenter
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("
");
}
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>
MainActivity
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();
}
}