假设有个登录API,登录返回的值是
{"code":0,msg:"登录成功","data":{"username":"xxx","nikename":"xxx"...}}
{"code":-100,msg:"用户不存在","data":null}
{"code":-101,msg:"密码错误","data":null}
...
用其他框架Http请求的时候,比如默认回调是HttpCallback,我们一般会对这个HttpCallback加一层封装比如MyHttpCallback,在MyHttpCallback里面
1) JSON转成Bean //也有很多框架自带Gson
2) code<0的时候弹出一个Toast显示msg
OkHttpUtils .get() .url("http://xxx") .addParams("username", "xxx") .addParams("password", "xxx") .build() .execute(new MyHttpCallback<User>() { @Override public void onError(Exception e) { } @Override public void onFailure(int code, String msg) { } @Override public void onSuccess(int code, String msg, User user) { } });
返回分为3种情况:
第一种是连接服务端失败(比如常见的404、500、502等)
第二种是请求成功但服务端告知我们参数有误
第三种是完全正确的
那使用RxJava+Retrofit该如何写出效果类似MyHttpCallback的功能呢?
1) 一般第一反应就是在Subscriber的onNext里面去判断,这样的写法满足不了这样的需求:code<0的时候要Retry
2) Retrofit我们都采用Gson处理返回的数据,如果我返回的结果比较简单,比如根据手机号返回一个验证码{"code":0,msg:"获取验证码成功","data":"8451"},还是要建立一个Bean类,有点麻烦,我想不写这个Bean类,在onNext传入的参数可不可以直接是JSONObject或者String
3) 我们会经常在onNext里面去处理UI,那我们应该知道需要在Activity的onDestroy()取消订阅。第一想法就是在Activity声明一个全局变量
private CompositeSubscription compositeSubscription;
每次订阅的时候都添加到compositeSubscription
Subscription subscription = xxx .xxx() .retryWhen(xxx) .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()); .subscribe(xxx); compositeSubscription.add(subscription);
然后在onDestroy()里面
compositeSubscription.unsubscribe();
这样写法没什么问题,只是每次订阅都要重复这2句
Subscription subscription = xxx; compositeSubscription.add(subscription);
不是链式了,不好看。
4) 我们的项目里应该有很多公共的部分
.subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread());
比如我的项目里这部分都是一样的,每个请求都写这么长一串也不太好看。
直接上代码,看看最终的写法
public class MainActivity extends BaseActivity implements View.OnClickListener { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); } @Override public void onClick(View view) { DX168API.get() .login("xxx", "xxx") .retryWhen(new RetryWhenNetworkException()) //可以设置重试次数,延迟重试 .compose(new DX168Transformer()) //一些通用的处理,如subscribeOn和observeOn .lift(new BindActivityOperator(this)) //绑定Activity,可以指定Activity的生命周期,用来取消订阅 .subscribe(new DX168Subscriber<User>(getApplicationContext()) { @Override public void onSuccess(User user) { //TODO } }); DX168API.get() .getRegisterVerifyCode("18888888888") .retryWhen(new RetryWhenNetworkException()) .compose(new DX168Transformer()) .lift(new BindActivityOperator(this)) .subscribe(new DX168Subscriber<String>(getApplicationContext()) { @Override public void onSuccess(String data) { //TODO // data就是verifyCode } }); } }
public class DX168GsonResponseBodyConverter<T> implements Converter<ResponseBody, T> { private final Gson gson; private final Type type; DX168GsonResponseBodyConverter(Gson gson, Type type) { this.gson = gson; this.type = type; } @Override public T convert(ResponseBody responseBody) throws IOException { String value = responseBody.string(); try { JSONObject response = new JSONObject(value); int code = response.optInt("code"); String msg = response.optString("msg"); if (code == DX168API.RESULT_OK) { //如果返回结果是JSONObject或者DX168Response则无需经过Gson if (type.toString().equals(JSONObject.class.toString())) { return (T) response; } else if (type.toString().equals(DX168Response.class.toString())) { Object data = response.opt("data"); DX168Response dx168Response = new DX168Response(code, msg, data); return (T) dx168Response; } else { return gson.fromJson(value, type); } } else { //返回的code不是RESULT_OK时Toast显示msg throw new DX168Exception(code, msg, value); } } catch (JSONException e) { //服务端返回的不是JSON,服务端出问题 throw new DX168Exception(-1, "", value); } } }
public abstract class DX168Subscriber<T> extends Subscriber<DX168Response> { private Context context; public DX168Subscriber(Context applicationContext) { this.context = applicationContext.getApplicationContext(); } @Override public void onError(Throwable throwable) { Throwable e = throwable; while (throwable.getCause() != null) { e = throwable; throwable = throwable.getCause(); } if (e instanceof ConnectException || e instanceof SocketTimeoutException || e instanceof TimeoutException) { onNetworkException(e); } else if (e instanceof DX168Exception) { onDX168Exception((DX168Exception) e); } else { onUnknownException(e); } } @Override public void onNext(DX168Response dx168Response) { Object data = dx168Response.getData(); if (data == JSONObject.NULL) { data = null; } onSuccess((T) data); } public abstract void onSuccess(T data); @Override public void onCompleted() { } public void onDX168Exception(DX168Exception e) { Toast.makeText(context, e.getMessage(), Toast.LENGTH_SHORT).show(); } public void onNetworkException(Throwable e) { Toast.makeText(context, "网络较慢,请稍候...", Toast.LENGTH_SHORT).show(); } public void onUnknownException(Throwable e) { Toast.makeText(context, e.toString(), Toast.LENGTH_SHORT).show(); } }
public class RetryWhenNetworkException implements Func1<Observable<? extends Throwable>, Observable<?>> { private int count = 5; private long delay = 5000; private long increaseDelay = 5000; public RetryWhenNetworkException() { } public RetryWhenNetworkException(int count, long delay) { this.count = count; this.delay = delay; } public RetryWhenNetworkException(int count, long delay, long increaseDelay) { this.count = count; this.delay = delay; this.increaseDelay = increaseDelay; } @Override public Observable<?> call(Observable<? extends Throwable> observable) { return observable .zipWith(Observable.range(1, count + 1), new Func2<Throwable, Integer, Wrapper>() { @Override public Wrapper call(Throwable throwable, Integer integer) { return new Wrapper(throwable, integer); } }).flatMap(new Func1<Wrapper, Observable<?>>() { @Override public Observable<?> call(Wrapper wrapper) { if ((wrapper.throwable instanceof ConnectException || wrapper.throwable instanceof SocketTimeoutException || wrapper.throwable instanceof TimeoutException) && wrapper.index < count + 1) { //如果超出重试次数也抛出错误,否则默认是会进入onCompleted return Observable.timer(delay + (wrapper.index - 1) * increaseDelay, TimeUnit.MILLISECONDS); } return Observable.error(wrapper.throwable); } }); } private class Wrapper { private int index; private Throwable throwable; public Wrapper(Throwable throwable, int index) { this.index = index; this.throwable = throwable; } } }
public class BaseActivity extends Activity { private List<SubscriberWrapper> subscribers; public void addSubscriber(Subscriber subscriber, ActivityLifecycle unsubscribeOn) { if (subscribers == null) { subscribers = new ArrayList<>(); } subscribers.add(new SubscriberWrapper(subscriber, unsubscribeOn)); } private class SubscriberWrapper { Subscriber subscriber; ActivityLifecycle unsubscribeOn; public SubscriberWrapper(Subscriber subscriber, ActivityLifecycle unsubscribeOn) { this.subscriber = subscriber; this.unsubscribeOn = unsubscribeOn; } } @Override protected void onStop() { for (SubscriberWrapper wrapper : subscribers) { if (wrapper.unsubscribeOn == ActivityLifecycle.OnStop) { wrapper.subscriber.unsubscribe(); subscribers.remove(wrapper); } } super.onStop(); } @Override protected void onDestroy() { for (SubscriberWrapper wrapper : subscribers) { if (wrapper.unsubscribeOn == ActivityLifecycle.OnDestroy) { wrapper.subscriber.unsubscribe(); subscribers.remove(wrapper); } } super.onDestroy(); } }
就这样吧,有兴趣的看看代码,不清楚的或者有不足的地方,欢迎交流。
来自:http://www.jianshu.com/p/930d7d728230