原创

Android RxJava+Retrofit统一处理API返回,根据返回值决定是否Retry,绑定Activity生命周期

假设有个登录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

 

正文到此结束
Loading...