2016-08-09 1 views
0

Ich versuche, eine Anfrage zu machen, die Daten vom Server zieht, bis es fertig ist, die Daten zu ziehen. Das Problem ist, dass die Antwort 21Data perPage hat. Aber es gibt ein Meta-Tag, um zu wissen, ob es eine nächste Seite gibt. Also, ich kann bis zum nextPage == totalPage ziehen.Wiederholen Sie eine Nachrüstung Observable Request

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

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

Meine Anfrage Logs

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) 

Wenn Sie bemerken, http://theUrl.net/lga?page=1&per_page=21 wurde zweimal und http://theUrl.net/lga?page=3&per_page=21 genannt wurde 3 mal aufgerufen.

Also entschied ich mich, meine alte RestClient Class Datei zu verwenden. Und es hat gut funktioniert. Aber es ist nichts falsch. Es lief die ganze Anfrage bis zum letzten. Ich kann immer noch nicht gefunden, was mit meiner ServiceGenerator class

RestClient Klasse falsch Datei

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

Antwort

1

Erstens, warum erstellen Sie einen neuen Client und Service für jeden einzelnen Anruf? Erstellen Sie sie einmal, speichern Sie sie und verwenden Sie sie erneut.

Zweitens würde ich sagen, dass Sie eine BehaviorSubject verwenden sollten (sorry für die Java-8, aber es macht die Logik viel mehr sichtbar):

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

Jetzt können Sie obs nehmen und die Objekte extrahieren und tun was du willst.

Edit: so etwas wie dieses post-Kommentar, sage ich versuchen würde:

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

Beachten Sie, dass Sie einmal für jeden Kontext die gleiche beobachtbare jedes Mal verwenden sollte getPages() und zurück; cache() kann mehrere Abonnenten und Abmeldungen verwalten.

+0

Vielen Dank. Das hat es irgendwie gelöst. Aber ich bleibe immer noch bei meiner Anfrage, die zweimal protokolliert wird. Irgendetwas stimmt nicht mit meiner ServiceGenerator-Klasse? Ich habe meine Frage bearbeitet –

+0

Zuerst versuchen Sie, Ihr Service-Objekt von 'ServiceGenerator.createService (ApiService.class, Token) zu cachen, oder verwenden Sie das Token als Parameter - die Dokumente sagen, es gibt eine @Header Annotation, die Sie verwenden können Ordnen Sie einen Parameter einem Header zu. Schließlich, wenn Sie nur die Ergebnisse behalten wollen, habe ich eine Bearbeitung hinzugefügt. –

+0

Ich habe die Annotation @header nicht mehr verwendet, nachdem ich sie einmal in 'Retrofit 1.9' verwendet habe und es hat nicht geklappt. Ich benutze 'Retrofit 2.1' jetzt aber. Würde es nochmal versuchen –

Verwandte Themen