2014-12-01 13 views
13

Sto cercando un esempio di flusso che sto cercando di implementare con l'aiuto di RxJava.Richieste di rete RxJava e memorizzazione nella cache

Supponiamo di voler mostrare un elenco di dati. Il flusso dovrebbe essere simile a questo:

  1. Leggere cache. Se contiene i dati, mostralo;
  2. inviare una richiesta di API al server:

    Se è tornato i dati, quindi memorizza nella cache e vederlo.

    Se restituito e errore e non c'erano dati memorizzati nella cache, quindi visualizzare un errore.

    Se restituito e errore e c'era qualcosa memorizzato nella cache, quindi non fare nulla.

In questo momento ho un method that does something similar (con un sacco di ispirazione da Jake's u2020). La differenza principale è che utilizza la cache in memoria, il che significa che non è necessario un separato Observable per la lettura dalla cache e può essere eseguito in modo sincrono.

Non so come combinare due osservabili (uno per la lettura dalla cache e l'altro per la chiamata API) e ottenere il flusso descritto sopra.

Qualche suggerimento?

+0

Sembra che tu abbia bisogno di 'amb': https://github.com/ReactiveX/RxJava/wiki/Conditional-and-Boolean-Operators#amb – zsxwing

+0

@zsxwing potresti fornire un esempio?Sono aperto a suggerimenti, anche se ho trovato una risposta (che non è perfetta). –

+0

Tenderei a lasciare la gestione della cache al client di rete. Se si utilizza HTTP, nella risposta sono presenti un'intestazione dedicata a indicare al client quale tipo di cache deve essere implementato, per quanto tempo deve essere conservato l'oggetto ... Senza contare che esiste anche la possibilità di verificare che la cache sia attiva ancora valido e aggiornarlo se necessario (codice di ritorno 304). – njzk2

risposta

1

Ecco la mia soluzione:

readDataFromCache().defaultIfEmpty(null) 
     .flatMap(new Func1<Data, Observable<Data>>() { 

      @Override 
      public Observable<Data> call(final Data data) { 
       if (data == null) { 
        // no cache, show the data from network or throw an error 
        return apiCall(); 
       } else { 
        return Observable.concat(
          Observable.just(data), 
          // something cached, show the data from network or do nothing. 
          apiCall().onErrorResumeNext(Observable.<Data>empty())); 
       } 
      } 
     }); 

non aggiungo il subscribeOn e observeOn perché non sono sicuro readDataFromCache() dovrebbe utilizzare ioScheduler o uiScheduler.

+0

L'unico problema che ho riscontrato è quando 'readDataFromCache()' restituisce un errore. 'onErrorResumeNext (Observable. empty())' deve essere aggiunto prima di 'defaultIfEmpty (null)' per ingoiare l'errore. –

2

Penso di aver risolto il mio problema. La catena osservabile assomiglia così:

apiCall() 
     .map(data -> dataInMemory = data) 
     .onErrorResumeNext(t -> data == null ? 
       Observable.just(Data.empty()) : Observable.empty()) 
     .startWith(readDataFromCache().map(data -> dataInMemory = data)) 
     .subscribeOn(ioScheduler) 
     .observeOn(uiScheduler) 
     .subscribe(dataRequest); 

Il punto principale è, che se readDataFromCache() getta un errore, chiamerà onCompleted() senza chiamare onError(). Quindi dovrebbe essere una custom Observable che puoi controllare.

Data.empty() è uno stub per i miei dati - lo Subscriber dovrebbe trattarlo come un errore.

dataInMemory è un membro nel mio controller che funge da cache in memoria.


EDIT: la soluzione non funziona correttamente. Il completamento di un caso d'uso (vedi commento) non è stato raggiunto.

EDIT 2: bene, la soluzione fa funzionare correttamente dopo qualche ritocco. La correzione restituiva diversi tipi di osservabili a seconda dello stato della cache in memoria. Tipo di sporco

+0

Bene, la mia soluzione non funziona. Se 'readDataFromCache()' funziona bene e mostra alcuni dati e 'apiCall()' restituisce un errore, mostra l'errore. –

Problemi correlati