重复改造可观察的请求

时间:2016-08-09 18:55:39

标签: rx-java retrofit2 rx-android okhttp3

我正在尝试提取从服务器提取数据的请求,直到它完成提取数据为止。问题是这样,响应每页21Data。但是,有一个元标记可以知道下一页是否存在。所以,我可以拉到nextPage == totalPage

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

    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();
            }
        }
    }

我的请求记录

    E/ServiceGen: http://theUrl.net/
    D/OkHttp: --> GET http://theUrl.net/lga?page=1&per_page=21 http/1.1
    D/OkHttp: x-mobile: true
    D/OkHttp: --> END GET
    D/OkHttp: --> GET http://theUrl.net/lga?page=1&per_page=21 http/1.1
    D/OkHttp: x-mobile: true
    D/OkHttp: --> END GET
    D/OkHttp: <-- 200 OK http://theUrl.net/lga?page=1&per_page=21 (929ms)
    D/OkHttp: Date: Wed, 10 Aug 2016 09:01:00 GMT
    D/OkHttp: Content-Type: application/json; charset=utf-8
    D/OkHttp: <-- 200 OK http://theUrl.net/lga?page=1&per_page=21 (933ms)
    D/OkHttp: Date: Wed, 10 Aug 2016 09:01:00 GMT
    D/OkHttp: Content-Type: application/json; charset=utf-8
    D/OkHttp: --> GET http://theUrl.net/lga?page=2&per_page=21 http/1.1
    D/OkHttp: --> END GET
    D/OkHttp: --> GET http://theUrl.net/lga?page=2&per_page=21 http/1.1
    D/OkHttp: --> END GET
    D/OkHttp: --> GET http://theUrl.net/lga?page=2&per_page=21 http/1.1
    D/OkHttp: --> END GET
    D/OkHttp: <-- 400 Bad Request http://theUrl.net/lga?page=2&per_page=21 (695ms)
    D/OkHttp: <-- END HTTP (177-byte body)
    D/OkHttp: <-- 400 Bad Request http://theUrl.net/lga?page=2&per_page=21 (696ms)
    D/OkHttp: <-- END HTTP (177-byte body)
    D/OkHttp: <-- 400 Bad Request http://theUrl.net/lga?page=2&per_page=21 (696ms)

如果您注意到http://theUrl.net/lga?page=1&per_page=21被调用了两次而http://theUrl.net/lga?page=3&per_page=21被调用了3次。

所以,我决定使用我的旧RestClient Class文件。它工作得很好。但是,没有错。它将整个请求运行到最后。我仍然无法找到ServiceGenerator class

的错误

RestClient类文件

    public class RestClient {

        private static final String TAG = "RestClient";
        private static ApiService apiEndpointInterface;
        private static Context context;

        /*static {
            setupRestClient();
        }*/

        public static ApiService get(Context cont) {
            context = cont;
            if (apiEndpointInterface != null)
                return apiEndpointInterface;

            setupRestClient();
            return apiEndpointInterface;
        }

        private static void setupRestClient() {
            // Define the interceptor, add authentication headers
            Interceptor interceptor = chain -> {
                Request newRequest = chain.request().newBuilder()
                        /*.addHeader("x-mobile", "true")*/
                        .addHeader("Authorization", "Bearer " + PrefUtils.getToken(context)).build();
                return chain.proceed(newRequest);
            };

            // Add the interceptor to OkHttpClient
            OkHttpClient.Builder builder = new OkHttpClient.Builder();
            builder.interceptors().add(interceptor);
            builder.addInterceptor(new HttpLoggingInterceptor().setLevel(HttpLoggingInterceptor.Level.BODY));
            builder.addNetworkInterceptor(new StethoInterceptor());
            builder.connectTimeout(30000, TimeUnit.SECONDS);
            builder.readTimeout(30000, TimeUnit.SECONDS);
            OkHttpClient client = builder.build();

            Retrofit retrofit = new Retrofit.Builder()
                    .baseUrl(BuildConfig.HOST)
                    .addCallAdapterFactory(RxJavaCallAdapterFactory.createWithScheduler(Schedulers.io()))
                    .addConverterFactory(GsonConverterFactory.create(CustomGsonParser.returnCustomParser()))
                    .client(client)
                    .build();
            apiEndpointInterface = retrofit.create(ApiService.class);
        }

        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();
            }
        }
    }

1 个答案:

答案 0 :(得分:1)

首先,为什么要为每次通话创建新的客户端和服务?创建它们一次,存储它们并重复使用它们。

其次,我说你应该使用BehaviorSubject(对不起Java 8,但它使逻辑更加明显):

BehaviorSubject<Integer> subject = new BehaviorSubject<>();
Observable<T> obs = 
    subject
    .flatMap(page ->
        getPage(page)
        .doOnNext(result -> {
            if(result has next page) subject.onNext(page+1);
            else                     subject.onComplete();
        }), 1)
    ;

现在您可以使用obs并提取对象并执行您想要的操作。

编辑:发表评论后,我会说尝试这样的事情:

public static Observable<LgaListResponse> getPages(Context acontext) {
  String token = PrefUtils.getToken(acontext);
  BehaviorSubject<Integer> pageControl = BehaviorSubject.<Integer>create(1);
  return pageControl.concatMap(integer -> {
        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.onComplete();
                    }
                });
  }).cache();
}

请记住,您应该使用一次getPages(),并且每次为每个Context返回相同的Observable; cache()可以处理多个订阅者和取消订阅。