2015-04-19 16 views
6

Sto tentando di creare un osservabile concatenando più chiamate di retrofit api. I passi sono:Utilizzo di RxJava + Retrofit per effettuare richieste API per ciascun elemento in un elenco

  1. ottenere un elenco di oggetti JSON utilizzando API chiamata
  2. Per ogni oggetto nella lista, effettuare un'altra chiamata API per ulteriori dettagli sulla voce
  3. dati Scrittura tratto da questo nuovo dettagliata oggetto in un file sul disco (questo si verifica per ogni elemento della lista)
  4. Infine restituire un osservabile di un oggetto separato che richiede che un file è stato creato per ciascuno degli oggetti precedenti

questo è ciò che Ho finora:

public static Observable<DownloadedFiles> downloadFiles() { 
    DownloadedFiles downloadedFiles = new DownloadedFiles(); 
    Observable.create(subscriber -> { 
     return getRestService().getObjectList() 
     .flatMapIterable(objects -> objects) 
     .flatMap(objectLimited -> getRestService().getObject(objectLimited.getPath())) 
     .doOnNext(objectFull -> { 

      try { 
       File file = new File(); 
       // Extract data from objectFull and write new file to disk 
       // ... 
       } catch (IOException e) { 
       subscriber.onError(e); 
      } 

      downloadedFiles.putFile(file); 
     }) 
     .toList() 
     .map(objects -> downloadedFiles) 
     .finallyDo(() -> { 
      subscriber.onNext(downloadedFiles); 
      subscriber.onCompleted(); 
     }); 
    }); 
} 

@GET("/api/...") 
Observable<List<Object>> getObjectList(); 

@GET("/api/.../{path}") 
Observable<Object> getObject(@Path("path") String path); 

Qualcuno potrebbe confermare che ho utilizzato gli operatori corretti. Grazie .

+0

È un po 'difficile dire che utente è nell'esempio? – alexwen

+0

@alexwen, scusa mi mancava una linea. Ho modificato l'esempio. – user3307102

risposta

2

Modifica: rimosso il file Observable.create, il retrofit è già visibile per te, devi solo trasformarlo.

Modifica 2: non è inoltre necessario fare nulla con subscriber.onError, se viene generato un errore esso chiamerà subscriber.onError da solo.

Abbastanza buono, non sono sicuro del motivo per cui è stata osservata la mappa piatta. Vorrei invece fare una mappa piatta per Observable :: from, anche raccogliere vale la pena aggiungere. Fondamentalmente ho intenzione di mappare 1 cosa a molti, quindi fare un po 'di azione, raccogliere i molti in uno e poi iscrivermi a quello una volta che ho raccolto tutti gli oggetti emessi.

public static Observable<DownloadedFiles> downloadFiles() {   
     return getRestService().getObjectList() 
     .flatMap(Observable::from) 
     .flatMap(objectLimited -> getRestService().getObject(objectLimited.getPath())) 
     .doOnNext(objectFull -> { 
      try { 
       File file = new File(); 
       // Extract data from objectFull and write new file to disk 
       // ... 
      } catch (IOException e) { 
       new IOException(e); 
      }}) 
     .collect(() -> new DownloadFiles<>(), (files, object) -> { files.add(object}); 
+0

Grazie, dove dovrei chiamare subscriber.onNext e subscriber.onCompleted? – user3307102

+0

Non è necessario. onNext viene chiamato con ogni elemento emesso attraverso la catena, nel tuo caso ci sarà solo 1 elemento emesso. Non appena verrà emesso 1 (il downloadFiles) verrà emesso onComplete verrà chiamato. onError verrà chiamato se c'è un problema in questa catena. Quindi quando ti iscrivi probabilmente faresti qualcosa come downloadFiles.subscribeOn (Schedulers.io()). ObservOn (AndroidSchedulers.mainThread()). Subscribe (new Observer() {})) – FriendlyMikhail

+0

Grande. Potresti spiegare perché un oggetto viene aggiunto ai file in collect()? Non è già stato preso cura della mia ultima riga in doOnNext? – user3307102

0

Penso che alcuni come questo dovrebbero funzionare per voi. Invece di tirare in una riserva di emettere così il DownloadedFile (s) a, si può semplicemente utilizzare osservabile dal servizio REST per mappare a ciascuno dei DownloadedFiles:

public static Observable<DownloadedFile> downloadFiles() { 
    final Observable<Observable<FullObject>> observable = getRestService().getObjectList() 
      .flatMapIterable(objects -> objects) 
      .map(objectLimited -> getRestService().getObject(objectLimited.getPath())); 

    return Observable.mergeDelayError(observable) 
      .map(fullObject -> { 
       try { 
        File file = new File("path"); 
        // Extract data from objectFull and write new file to disk 
        // ... 

        return new DownloadedFile(); 
       } catch (IOException e) { 
        throw OnErrorThrowable.from(OnErrorThrowable.addValueAsLastCause(e, fullObject)); 
       } 
      }); 
} 

Si consiglia di considerare l'utilizzo di mergeDelayError (Mappa()) invece di flatMap se si desidera emettere file salvati correttamente prima di propagare eventuali errori.

+1

'Oggetto objectToSave = getRestService(). GetObject (objectLimited.getPath());' non funziona perché getRestService(). GetObject() restituisce un osservabile. – user3307102

+0

Ho aggiornato l'esempio di conseguenza. – alexwen

Problemi correlati