Gestione della cache con RXJava

Sto cercando di implementare questo stream di lavoro con rxJava, ma sono sicuro se sto abusando o facendo cose sbagliate.

  • L'utente chiede di accedere
  • Se un loginResult è disponibile nella cache, emettere "LoginResult nella cache"
  • Altrimenti effettua la richiesta al webservice e cache il risultato se tutto è successo
  • Se si verifica un errore di ripetizione al massimo 3 volte e se c'è una quarta volta, quindi spurgare la cache.

Ecco il mio frammento completo del codice.

  • Come get l'attività di esecuzione dell'applicazione Nome in android 5.0 (L)?
  • Attendere il risultato della richiesta Async Volley e restituirlo
  • Come disegnare un path su una mappa usando il file kml?
  • Le variables statiche in Android e la memory insufficiente - alcune domande
  • Java - Convertire la string in un object URI valido
  • Android 2.3.1 Camera takePicture () Immagini multiple con un semplice button
  • public class LoginTask extends BaseBackground<LoginResult> { private static CachedLoginResult cachedLoginResult = new CachedLoginResult(); private XMLRPCClient xmlrpcClient; private UserCredentialsHolder userCredentialsHolder; @Inject public LoginTask(XMLRPCClient client, UserCredentialsHolder userCredentialsHolder) { this.xmlrpcClient = client; this.userCredentialsHolder = userCredentialsHolder; } @Override public LoginResult performRequest() throws Exception { return UserApi.login( xmlrpcClient, userCredentialsHolder.getUserName(), userCredentialsHolder.getPlainPassword()); } @Override public Observable<LoginResult> getObservable() { return cachedLoginResult.getObservable() .onErrorResumeNext( Observable.create( ((Observable.OnSubscribe<LoginResult>) subscriber -> { try { if (!subscriber.isUnsubscribed()) { subscriber.onNext(performRequest()); // actually performRequest } subscriber.onCompleted(); } catch (Exception e) { subscriber.onError(e); } }) ) .doOnNext(cachedLoginResult::setLoginResult) .retry((attempts, t) -> attempts < 3) .doOnError(throwable -> cachedLoginResult.purgeCache()) ); } private static class CachedLoginResult { private LoginResult lr = null; private long when = 0; private CachedLoginResult() { } public boolean hasCache() { return lr != null && when + TimeUnit.MILLISECONDS.convert(30, TimeUnit.MINUTES) > System.currentTimeMillis(); } public void setLoginResult(LoginResult lr) { if (lr != null) { this.lr = lr; this.when = System.currentTimeMillis(); } } public void purgeCache() { this.lr = null; this.when = 0; } public Observable<LoginResult> getObservable() { return Observable.create(new Observable.OnSubscribe<LoginResult>() { @Override public void call(Subscriber<? super LoginResult> subscriber) { if (!subscriber.isUnsubscribed()) { if (hasCache()) { subscriber.onNext(lr); subscriber.onCompleted(); } else { subscriber.onError(new RuntimeException("No cache")); } } } }); } } } 

    Dal momento che non riesco a trovare altri esempi simili e ho iniziato a "suonare" con rxjava solo 1 giorno fa non sono sicuro della mia implementazione.

    Grazie per il tuo tempo.

  • PhoneGap continua a funzionare su Android dopo onPause
  • RequestIdToken di login di Google restituisce null
  • Perché la verifica della firma sul server remoto è più sicura del dispositivo?
  • android: MapView non riconosce i clic
  • Intercetta le richieste POST in un WebView
  • Convertire UTC in ora locale corrente
  • 2 Solutions collect form web for “Gestione della cache con RXJava”

    Penso che questo codice è bene, buon lavoro 🙂

    Avevi ragione usare Observable.create nel tuo LoginTask perché altrimenti il ​​risultato della chiamata potrebbe essere memorizzato internamente e quindi retry non avrebbe aiutato molto …

    Penso però che sia inutile per l' Observable CachedLoginResult . Qui è ansible semplificare il codice utilizzando i methods di utilità Observable.just e Observable.error , come:

     public Observable<LoginResult> getObservable() { if (hasCache()) { return Observable.just(lr); } else { return Observable.error(new RuntimeException("No cache")); } } 

    Nota: memorizza just il valore che lo indica per emettere internamente, in modo che le risubscrizioni generino sempre questo valore. Questo è ciò che ho accennato sopra, non dovresti fare Observable.just(performRequest()).retry(3) ad esempio, perché il performRequest verrà chiamato solo una volta.

    Se capisco correttamente, vuoi eseguire una volta l'accesso e memorizzi il risultato in modo reattivo? Se è così, ecco un esempio di come farlo:

     import java.util.concurrent.ThreadLocalRandom; import rx.*; import rx.schedulers.Schedulers; import rx.subjects.AsyncSubject; public class CachingLogin { static class LoginResult { } /** Guarded by this. */ AsyncSubject<LoginResult> cache; public Observable<LoginResult> login(String username, String password) { AsyncSubject<LoginResult> c; boolean doLogin = false; synchronized (this) { if (cache == null || cache.hasThrowable()) { cache = AsyncSubject.create(); doLogin = true; } c = cache; } if (doLogin) { Observable.just(1).subscribeOn(Schedulers.io()) .map(v -> loginAPI(username, password)) .retry(3).subscribe(c); } return c; } public void purgeCache() { synchronized (this) { cache = null; } } static LoginResult loginAPI(String username, String password) { if (ThreadLocalRandom.current().nextDouble() < 0.3) { throw new RuntimeException("Failed"); } return new LoginResult(); } } 
    L'Android è un fan Android di Google, tutto su telefoni Android, Android Wear, Android Dev e applicazioni Android Games e così via.