前面一篇文章介绍了Retrofit的基本用法,没有看过的童鞋可以移步:Android网络请求框架之Retrofit(一),现在我们来继续介绍Retrofit配合RxJava、RxAndroid的用法。
配合Rx是为了体现函数式编程的思想,其实用法差别不大,只是在接口里定义方法的返回值有所差别,当然,build.gradle文件里需要导入两个库地址
io.reactivex:rxjava:1.0.14
io.reactivex:rxandroid:1.0.1
下面我们以更新任务为例,观察两种方式的区别
public interface ITask {
//RX模式的方法定义之一
@PUT("/task/{Id}")
Observable update(@Path("Id") String Id,@Body HashMap body);
//RX模式的方法定义之二
@PUT("/task/{Id}")
Call _update(@Path("Id") String Id,@Body HashMap body);
//常规异步式的方法定义
@PUT("/task/{Id}")
void update_(@Path("Id") String Id,@Body HashMap body,Callback callback);
}
方法很容易区别,一个是返回参数在回调接口里,一个是直接返回,但返回的不是最终的对象。
按照常规的调用
HashMap map = new HashMap<>();
map.put("title", title);
map.put("content", content);
map.put("responsiblePersons", Arrays.asList(new Reviewer(mTask.getResponsiblePerson())));
map.put("members", mTask.getMembers());
map.put("actualendAt", mTask.getActualEndAt());
map.put("remindflag", mTask.getRemindTime() > 0);
map.put("remindtime", mTask.getRemindTime());
map.put("reworkflag", switch_approve.isChecked());
if (!TextUtils.isEmpty(mTask.getAttachmentUUId()) && mTask.getAttachments().size() > 0) {
map.put("attachmentUUId", mTask.getAttachmentUUId());
}
if (!TextUtils.isEmpty(mTask.getProjectId())) {
map.put("projectId", mTask.getProjectId());
}
RestAdapterFactory.getInstance().build(Config_project.API_URL()).create(ITask.class).update_(mTask.getId(), map,new RCallback (){
@overide
public void success(Task task,Response r){
task.setAck(true);
Toast(getString(R.string.app_add) + getString(R.string.app_succeed));
Intent intent = new Intent();
intent.putExtra("data", task);
setResult(Activity.RESULT_OK, intent);
onBackPressed();
}
@Overide
public void failure(RetrofitError e){
}
});
这种调用没什么好说的,和前面一篇文章里的一样,服务器返回的结果会封装在RCallback里面,并且回调方法在主线程。
下面我们看看按照Rx模式调用之一
HashMap map = new HashMap<>();
map.put("title", title);
map.put("content", content);
map.put("responsiblePersons", Arrays.asList(new Reviewer(mTask.getResponsiblePerson())));
map.put("members", mTask.getMembers());
map.put("actualendAt", mTask.getActualEndAt());
map.put("remindflag", mTask.getRemindTime() > 0);
map.put("remindtime", mTask.getRemindTime());
map.put("reworkflag", switch_approve.isChecked());
if (!TextUtils.isEmpty(mTask.getAttachmentUUId()) && mTask.getAttachments().size() > 0) {
map.put("attachmentUUId", mTask.getAttachmentUUId());
}
if (!TextUtils.isEmpty(mTask.getProjectId())) {
map.put("projectId", mTask.getProjectId());
}
RestAdapterFactory.getInstance().build(Config_project.API_URL()).create(ITask.class).update(mTask.getId(), map)
.observeOn(AndroidSchedulers.mainThread())//指定订阅的线程-主线程
.subscribe(new Subscriber() {//订阅
//处理完成
@Override
public void onCompleted() {
}
//处理出错
@Override
public void onError(Throwable e) {
e.printStackTrace();
}
//处理过程
@Override
public void onNext(Task task) {
task.setAck(true);
Toast(getString(R.string.app_add)+getString(R.string.app_succeed));
Intent intent = new Intent();
intent.putExtra("data", task);
setResult(Activity.RESULT_OK, intent);
onBackPressed();
}
});
在这里,接口定义的方法直接返回了一个Observable对象,指定这个对象发生订阅的线程,然后订阅事件,最后也是异步回调的,不过在这个过程中,我们可以指定回调方法发生的线程,看起来的话onNext方法和success方法其实没啥区别,都带回了我们需要的数据,但是从代码层次上来看,Rx模式的代码逻辑层次更清楚。
下面我们再看看按照Rx模式调用之二
HashMap map = new HashMap<>();
map.put("title", title);
map.put("content", content);
map.put("responsiblePersons", Arrays.asList(new Reviewer(mTask.getResponsiblePerson())));
map.put("members", mTask.getMembers());
map.put("actualendAt", mTask.getActualEndAt());
map.put("remindflag", mTask.getRemindTime() > 0);
map.put("remindtime", mTask.getRemindTime());
map.put("reworkflag", switch_approve.isChecked());
if (!TextUtils.isEmpty(mTask.getAttachmentUUId()) && mTask.getAttachments().size() > 0) {
map.put("attachmentUUId", mTask.getAttachmentUUId());
}
if (!TextUtils.isEmpty(mTask.getProjectId())) {
map.put("projectId", mTask.getProjectId());
}
RestAdapterFactory.getInstance().build(Config_project.API_URL()).create(ITask.class)._update(mTask.getId(), map).enqueue(new RCallback() {
@Override
public void success(Task task) {
task.setAck(true);
Toast(getString(R.string.app_add)+getString(R.string.app_succeed));
Intent intent = new Intent();
intent.putExtra("data", task);
setResult(Activity.RESULT_OK, intent);
onBackPressed();
}
@Override
public void onFailure(Throwable error) {
}
});
这里是反回了一个Call对象,调用enqueue的时候就像我们常规模式调用时那样传入callback接口,从里面获取数据。
当然RX模式的好处远不止这一个,比如说,当我们需要显示等待dialog的时候,常规的异步式调用可能就需要我们维护一个progressdialog,但Rx模式就可以很方便的实现。Subscriber有一个空实现的方法onStart,是在开始连接服务器之前调用的,我们可以封装一个commonSubscriber,在 onStart方法里去显示一个progressdialog,在onError或onComplete方法里去自动销毁这个progressdialog。
public abstract class CommonSubscriber extends Subscriber {
private CustomProgressDialog dialog;
public CommonSubscriber(Activity context) {
dialog = new CustomProgressDialog(context);
}
@Override
public void onStart() {
super.onStart();
dialog.show();
}
@Override
public void onNext(Serializable serializable) {
BaseBen baseBen = (BaseBen) serializable;
if(null!=baseBen) {
if ((!TextUtils.isEmpty(baseBen.getErrorCode())&&baseBen.getErrorCode().contains( ErrorUtil.ERROR_TOKEN_ERROR)) || ((!(baseBen instanceof TokenInfo)) && null == BusApplication.getInstance().getTokenInfo())) {
BusApplication.getInstance().backToLogin();
}
}
}
@Override
public void onError(Throwable e) {
dialog.dismiss();
dialog=null;
}
@Override
public void onCompleted() {
dialog.dismiss();
dialog=null;
}
}
关于Rx相关的知识,我也知道得很有限,有一些比较专业的用法我也不敢信笔涂鸦,有兴趣的小伙伴可以去查阅一下相关的资料,或许就会有更大的发现。比如说可以指定多次observeOn,但是subscribeOn只认可第一次;可以用filter方法过滤调一些返回值,可以用flatMap封装下一步需要的参数等等。
最后我贴出一段我用纯Rx模式实现的请求代码供大家参考
//-------------------------------RxJava实现方式开始--------------------------------
Observable.just(schedule)
.subscribeOn(AndroidSchedulers.mainThread())
.observeOn(AndroidSchedulers.mainThread())
//判断行程是否有效,过滤掉无效行程
.filter(new Func1() {
@Override
public Boolean call(TourSchedule tourSchedule) {
if (null == schedule) {
ptrFrameLayout.refreshComplete();
dialog.dismiss();
ToolToast.showShort("车次信息错误,无法获取订单");
}
return null != schedule;
}
})
//网络请求置于IO线程
.observeOn(Schedulers.io())
//先去请求服务器数据
.flatMap(new Func1>>() {
@Override
public Observable> call(TourSchedule schedule) {
HashMap map = new HashMap<>();
map.put("busNoId", schedule.getBusNoId());
map.put("busId", schedule.getBusId());
map.put("day", schedule.getDay());
map.put("planId", schedule.getPlanId());
return ServiceGenerator.getInstance().create(IOrderForm.class, BusApplication.getInstance().getToken()).getOrderFormList_(map);
}
})
//截获错误,不回调onError方法,使流程继续
.onErrorReturn(new Func1>() {
@Override
public CommonListBen call(Throwable throwable) {
return null;
}
})
.observeOn(Schedulers.newThread())
//请求的结果转换为最终需要的数据
.map(new Func1, ArrayList>() {
@Override
public ArrayList call(CommonListBen travelOrderFormCommonListBen) {
return null == travelOrderFormCommonListBen ? null : travelOrderFormCommonListBen.getData();
}
})
//处理服务器返回的数据,混合缓存
.flatMap(new Func1, Observable>>() {
@Override
public Observable> call(ArrayList travelOrderForms) {
if (mDao == null)
mDao = new TravleOrderFormDao(mContext);
//从数据库获取
if (null == travelOrderForms) {
//需要取存数据,以planId为主键
TravelOrderFormData dataDb = mDao.get(schedule.getPlanId());
if (null != dataDb) {
Gson gson = new Gson();
Type type = new TypeToken>() {
}.getType();
travelOrderForms = gson.fromJson(dataDb.getJson(), type);
}
}
//存数据库
else {
TravelOrderFormData data = new TravelOrderFormData();
data.setPlanId(schedule.getPlanId());
Gson gson = new Gson();
data.setJson(gson.toJson(travelOrderForms));
mDao.add(data);
}
return Observable.just(travelOrderForms);
}
})
//显示最后获得的结果
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Subscriber>() {
@Override
public void onCompleted() {
dialog.dismiss();
ptrFrameLayout.refreshComplete();
}
@Override
public void onError(Throwable e) {
dialog.dismiss();
ptrFrameLayout.refreshComplete();
}
@Override
public void onNext(ArrayList datas) {
travelOrderForms = datas;
handleCustomers();
dataChange();
}
});
//-------------------------------RxJava实现方式结束--------------------------------