【问题标题】:Retrofit and RxJava, avoiding callback hell改造和 RxJava,避免回调地狱
【发布时间】:2016-03-27 06:59:51
【问题描述】:

所以目前,我使用日期参数(使用 Retrofit)发出异步网络请求,并且如果该请求返回的响应代码不是 200(或者如果它的 429、400,或者如果响应正文为空,最容易确定的),我在 1 天前使用日期参数发出新请求。同样,如果此请求返回的响应代码不是 200,我会再发出一个日期比前一个早 1 天的请求,如果前两个请求失败,则总共有 3 个可能的请求。

我目前正在通过一堆回调来实现这一点,并调用一个新方法设置来在每次尝试的第 -1 天执行请求。

我知道我可以通过 Rx 和 Rx 功能中内置的 Retrofits 实现更简洁的解决方案。这将如何实现?

【问题讨论】:

  • 什么改装版本?
  • @NikoYuwono 2.0.0-beta2

标签: android retrofit rx-java rx-android


【解决方案1】:

首先你需要在你的依赖中添加 RxAndroid 和 RxJava 适配器

compile 'com.squareup.retrofit:adapter-rxjava:2.0.0-beta2'
compile 'io.reactivex:rxandroid:1.0.1'

然后您需要将调用适配器注册到您的改造声明中

Retrofit retrofit = new Retrofit.Builder()
        .baseUrl(myBaseurl)
        .addConverterFactory(GsonConverterFactory.create())
        .addCallAdapterFactory(RxJavaCallAdapterFactory.create())
        .build();

然后您可以将您的服务接口返回类型从 Call 更改为 Observable

public interface MyAPIService {

    @POST("user")
    Call<User> getUser();

    @POST("user")
    Observable<Response<User>> getUserWithRxJava();

    @POST("user_friends")
    Observable<Response<List<User>>> getUserFriends();
}

这是一个链接调用的例子

myService.getUserWithRxJava()
    .observeOn(AndroidSchedulers.mainThread())
    .flatMap(new Func1<Response<User>, Observable<Response<List<User>>>>() {
        @Override
        public Observable<List<Home>> call(Response<User> responseUser) {
            // You can also use responseUser.code to get the response code
            // but isSuccess() function will return true if the code 
            // is in the range [200..300)
            if (responseUser.isSuccess()) {
                return myService.getUserFriends();
            } else {
                // You can also use Observable.empty() if you want to ignore unsuccessful response
                return Observable.error(myThrowable);
            }
        }
    })
    .subscribe(new Subscriber<Response<List<User>>>() {
        @Override
        public void onCompleted() {
            // TODO Completed
        }

        @Override
        public void onError(Throwable e) {
            // TODO Handle the error
        }

        @Override
        public void onNext(Response<List<User>> friendListResponse) {
            // TODO do something with the data
            // To get the serialized data you can use friendListResponse.body();
        }
    });

【讨论】:

    【解决方案2】:

    非 200 响应应返回为 RetrofitError 对象,其中包含带有状态代码的 Response 对象。

    你可以这样做:

    observable
        .retryWhen(new RetryStrategy())
        .subscribe(...);
    

    而RetryStrategy 可能看起来像这样(注意,我使用的是retrolambda,所以无论您在哪里看到-&gt;,只需替换为一个新的匿名内部类):

    public class RetryStrategy implements Func1<Observable<? extends Throwable>, Observable<?>> {
    
        public RetryStrategy() {}
    
        @Override
        public Observable<?> call(Observable<? extends Throwable> attempts) {
            return attempts.flatMap((throwable) -> {
                if (throwable instanceof RetrofitError) {
                    RetrofitError error = (RetrofitError) throwable;
                    if (error.getKind() == RetrofitError.Kind.HTTP) {
                        if (error.getResponse().getStatus() == 401) {
    
                            // This is where you attempt to recover
                            return someRecoveryObservable???;
                        }
                    }
                }
    
                // Bubble any other errors back up, e.g. connection loss.
                return Observable.error(throwable);
            });
        }
    }
    

    您还可以在此处通过添加对重试计数的支持来实现Exponential Backoff,并在恢复阶段使用Observable.timer(long, TimeUnit)(并根据当前的尝试次数计算时间)。这种方法有时会极大地改善不连贯的连接问题,尤其是在后台运行的“即发即弃”任务中。

    【讨论】:

      猜你喜欢
      • 2017-05-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-03-16
      • 2017-08-18
      • 2015-08-01
      相关资源
      最近更新 更多