2016-08-09 13 views
0

私は、データを取得し終えるまで、サーバーからデータを取得するリクエストを作成しようとしています。問題はこれです、レスポンスには21Data perPageがあります。しかし、次のページがあるかどうかを知るメタタグがあります。だから、私は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

まず、なぜあなたは一人ひとりの呼び出しのための新しいクライアントとサービスを作成しないファイルと間違っているものを見つけることができませんか?それらを一度作成し、保管して再使用してください。

第二に、私は(Javaの8申し訳ありませんが、それはロジックがはるかに目に見えるように)あなたがBehaviorSubjectを使うべきでしょうね。

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を取り、オブジェクトを抽出して行うことができますあなたが欲しいもの。

編集:ポストのコメント、私はこのような何かしようと言うと思います:1回)(あなたはgetPagesを使用する必要があります覚えておいて、各コンテキストで同じ各観測時間を返す

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

を。 cache()は、複数のサブスクライバとサブスクライブ解除を処理できます。

+0

ありがとうございました。それはそれを解決しました。しかし、私は依然として私のリクエストが2回記録されていることに悩まされています。 ServiceGeneratorクラスに問題がありますか?私は自分の質問を編集しました –

+0

最初に、 'ServiceGenerator.createService(ApiService.class、token)'からサービスオブジェクトをキャッシュしてみるか、そのトークンをパラメータとして使用してください - ドキュメントには@Header Annnotationがありますパラメータをヘッダにマップする。最後に、結果を保持したい場合は、編集を追加しました。 –

+0

'Retrofit 1.9'で@ headerアノテーションを一度使用した後、@headerアノテーションの使用を中止しましたが、うまくいきませんでした。私は 'Retrofit 2.1'を使用しています。もう一度試してみる –