使用RxJava / RxAndroid进行Retrofit2尾递归

时间:2016-08-08 19:55:53

标签: android rx-java retrofit2 rx-android

我真的想把RetrofitRxJava / RxAndroid一起使用。我在以前的应用中使用普通Retrofit2 Callback方法完成了此操作,而没有使用Reactive Programming,并且它运行正常。所以,就是这样。我需要Tail Recall一个函数来从服务器获取所有Local GovernmentAPI使用分页(I have to construct the URL with ?page=1, perPage=2)。我要做到这一点,直到我得到整个数据。因此,下面是我的Rx代码

    public static Observable<LgaListResponse> getPages(Context acontext) {
    String token = PrefUtils.getToken(acontext);
    BehaviorSubject<Integer> pageControl = BehaviorSubject.<Integer>create(1);
    Observable<LgaListResponse> ret2 = pageControl.asObservable().concatMap(integer -> {
        if (integer > 0) {
            Log.e(TAG, "Integer: " + integer);
            return ServiceGenerator.createService(ApiService.class, token)
                    .getLgas(String.valueOf(integer), String.valueOf(21))
                    .doOnNext(lgaListResponse -> {
                        if (lgaListResponse.getMeta().getPage() != lgaListResponse.getMeta().getPageCount()) {
                            pageControl.onNext(initialPage + 1);
                        } else {
                            pageControl.onNext(-1);
                        }
                    });
        } else {
            return Observable.<LgaListResponse>empty().doOnCompleted(pageControl::onCompleted);
        }
    });

    return Observable.defer(() -> ret2);
}

我的ServiceGenerator Class

    public class ServiceGenerator {

        private static final String TAG = "ServiceGen";
        private static OkHttpClient.Builder builder = new OkHttpClient.Builder();

        private static Retrofit.Builder retrofitBuilder =
                new Retrofit.Builder()
                        .baseUrl(BuildConfig.HOST)
                        .addCallAdapterFactory(RxJavaCallAdapterFactory.createWithScheduler(Schedulers.io()))
                        .addConverterFactory(GsonConverterFactory.create(CustomGsonParser.returnCustomParser()));

        public static <S> S createService(Class<S> serviceClass, String token) {

            builder.addInterceptor(new HttpLoggingInterceptor().setLevel(HttpLoggingInterceptor.Level.BODY));
            /*builder.addNetworkInterceptor(new StethoInterceptor());*/
            builder.connectTimeout(30000, TimeUnit.SECONDS);
            builder.readTimeout(30000, TimeUnit.SECONDS);
            if (token != null) {
                Interceptor interceptor = chain -> {
                    Request newRequest = chain.request().newBuilder()
                            .addHeader("x-mobile", "true")
                            .addHeader("Authorization", "Bearer " + token).build();
                    return chain.proceed(newRequest);
                };
                builder.addInterceptor(interceptor);
            }
            OkHttpClient client = builder.build();

            Retrofit retrofit = retrofitBuilder.client(client).build();
            Log.e(TAG, retrofit.baseUrl().toString());
            return retrofit.create(serviceClass);
        }

        public static Retrofit retrofit() {
            OkHttpClient client = builder.build();
            return retrofitBuilder.client(client).build();
        }

        public static class CustomGsonParser {

            public static Gson returnCustomParser(){
                return new GsonBuilder()
                        .setExclusionStrategies(new ExclusionStrategy() {
                            @Override
                            public boolean shouldSkipField(FieldAttributes f) {
                                return f.getDeclaringClass().equals(RealmObject.class);
                            }

                            @Override
                            public boolean shouldSkipClass(Class<?> clazz) {
                                return false;
                            }
                        })
                        .create();
            }
        }
    }

所以,我在第一次调用时注意到,我收到了回复,但在第二次调用时,440Error被抛出。 URL已形成,但请求将引发400Error。我不知道为什么抛出一个400如果我使用POSTMAN进行测试,一切正常。而且,我也测试了我的旧代码。 Log太长了,所以我把它放在pastebin LOGS任何帮助中谢谢。我用RxAndroid / RxJava写了这个应用程序的大部分内容。感谢

1 个答案:

答案 0 :(得分:1)

我建议你简化一些事情(并删除递归)。首先使用类似

的内容构建页面
public static Observable<LgaListResponse> getPages(Context acontext, int initialPage, int perPage) {  
    String token = PrefUtils.getToken(acontext);
    BehaviorSubject<Integer> pagecontrol = BehaviorSubject.<Integer>create(initialPage);
    Observable<LgaListResponse> ret2 = pagecontrol.asObservable().concatMap(
        new Func1<Integer,Observable<LgaListResponse>>() {
            Observable<LgaListResponse> call(Integer pageNumber) {
                if (pageNumber > 0) {
                    return ServiceGenerator.createService(ApiService.class, token)
                                           .getLgas(String.valueOf(aKey), String.valueOf(perPage))
                                           .doOnNext(
                                                new Action1<LgaListResponse>() {
                                                    void call(LgaListResponse page) {
                                                        if (page.getMeta().getPage() != page.getMeta().getPageCount()) {
                                                            pagecontrol.onNext(page.getMeta().getNextPage());
                                                        } else {
                                                            pagecontrol.onNext(-1);
                                                        }         
                                                    }
                                                }
                                            );
                }                                               
                else {
                    return Observable.<LgaListResponse>empty().doOnCompleted(()->pagecontrol.onCompleted());
                }           
            }
        }
    );

    return Observable.defer(
                new Func0<Observable<LgaListResponse>() {
                    Observable<LgaListResponse> call() {
                        return ret2;
                    }
                }
            );            
}

然后订阅生成的observable。它看起来很可怕,因为我已经避免使用lambdas,但它应该有效。