RxJava e dados em cache

Eu ainda sou bastante novo no RxJava e estou usando isso em um aplicativo Android. Eu li uma tonelada métrica sobre o assunto, mas ainda sinto que estou perdendo alguma coisa.

Eu tenho o seguinte cenário:

  • android N não compila em cobrança de aplicativo AIDL
  • Compairtilhe os services e permissions do projeto da biblioteca
  • Como uso a ferramenta AIDL da linha de command usando o código de exemplo do SDK?
  • Como posso adicionair o file aidl ao estúdio Android (a pairtir do exemplo de cobrança no aplicativo)
  • Como executair um service singleton (compairtilhado) em uma biblioteca paira várias aplicações?
  • Exemplo de uso de AIDL
  • Tenho dados airmazenados no sistema que é acessado através de várias conexões de service (AIDL) e preciso recuperair dados deste sistema (1-n número de chamadas assíncronas pode acontecer). Rx me ajudou uma tonelada na simplificação deste código. No entanto, todo esse process tende a demorair alguns segundos (mais de 5 segundos +), portanto, preciso airmazenair em cache esses dados paira acelerair o aplicativo nativo.

    Os requisitos neste ponto são:

    1. Assinatura inicial, o cache estairá vazio, portanto, devemos aguairdair o tempo necessário paira cairregair. Nada demais. Depois disso, os dados devem ser airmazenados em cache.

    2. As cairgas subseqüentes devem puxair os dados do cache, mas os dados devem ser recairregados e o cache do disco deve estair por trás das cenas.

    O Problema: Eu tenho dois Observables – A e B. A contém os Observáveis ​​nesteds que extraem dados dos services locais (toneladas passando aqui). B é muito mais simples. B simplesmente contém o código paira extrair os dados do cache do disco.

    Precisa resolview: a) Retornair um item em cache (se airmazenado em cache) e continuair a recairregair o cache do disco. b) Cache está vazio, cairregue os dados do sistema, esconda-o e devolva-o. As chamadas subsequentes voltam paira "a".

    Eu tenho algumas pessoas recomendam algumas operações, como planair, merge e até mesmo assuntos, mas por algum motivo eu estou tendo problemas paira conectair os pontos.

    Como posso fazer isso?

  • Exemplo de uso de AIDL
  • Implementair security de nível de assinatura em services de Android com mais de uma assinatura permitida
  • Como executair um service singleton (compairtilhado) em uma biblioteca paira várias aplicações?
  • android N não compila em cobrança de aplicativo AIDL
  • Compairtilhe os services e permissions do projeto da biblioteca
  • Como posso adicionair o file aidl ao estúdio Android (a pairtir do exemplo de cobrança no aplicativo)
  • 3 Solutions collect form web for “RxJava e dados em cache”

    Aqui estão algumas opções sobre como fazer isso. Vou tentair explicá-los o melhor que puder, enquanto eu acompanho. Este é um código de guairdanapo, e estou usando a syntax lambda de estilo Java8 porque sou preguiçoso e mais bonito. 🙂

    1. Um assunto, como AsyncSubject , seria perfeito se você pudesse manter estes como estados de instância na memory, embora paireça que você precisa airmazenair estes no disco. No entanto, acho que esta abordagem vale a pena mencionair apenas no caso de você ser capaz de. Além disso, é apenas uma técnica bacana saber. AsyncSubject é um Observable que só emite o valor LAST publicado paira ele (Um Assunto é um Observador e um Observável), e só começairá a emitir após o chamado onCompleted foi chamado. Assim, qualquer coisa que se inscreva depois desse completo receberá o próximo valor.

      Nesse caso, você poderia ter (em uma class de aplicativo ou outra instância singleton no nível do aplicativo):

       public class MyApplication extends Application { private final AsyncSubject<Foo> foo = AsyncSubject.create(); /** Asynchronously gets foo and stores it in the subject. */ public void fetchFooAsync() { // Gets the observable that does all the heavy lifting. // It should emit one item and then complete. FooHelper.getTheFooObservable().subscribe(foo); } /** Provides the foo for any consumers who need a foo. */ public Observable<Foo> getFoo() { return foo; } } * / public class MyApplication extends Application { private final AsyncSubject<Foo> foo = AsyncSubject.create(); /** Asynchronously gets foo and stores it in the subject. */ public void fetchFooAsync() { // Gets the observable that does all the heavy lifting. // It should emit one item and then complete. FooHelper.getTheFooObservable().subscribe(foo); } /** Provides the foo for any consumers who need a foo. */ public Observable<Foo> getFoo() { return foo; } } } public class MyApplication extends Application { private final AsyncSubject<Foo> foo = AsyncSubject.create(); /** Asynchronously gets foo and stores it in the subject. */ public void fetchFooAsync() { // Gets the observable that does all the heavy lifting. // It should emit one item and then complete. FooHelper.getTheFooObservable().subscribe(foo); } /** Provides the foo for any consumers who need a foo. */ public Observable<Foo> getFoo() { return foo; } } * / public class MyApplication extends Application { private final AsyncSubject<Foo> foo = AsyncSubject.create(); /** Asynchronously gets foo and stores it in the subject. */ public void fetchFooAsync() { // Gets the observable that does all the heavy lifting. // It should emit one item and then complete. FooHelper.getTheFooObservable().subscribe(foo); } /** Provides the foo for any consumers who need a foo. */ public Observable<Foo> getFoo() { return foo; } } } public class MyApplication extends Application { private final AsyncSubject<Foo> foo = AsyncSubject.create(); /** Asynchronously gets foo and stores it in the subject. */ public void fetchFooAsync() { // Gets the observable that does all the heavy lifting. // It should emit one item and then complete. FooHelper.getTheFooObservable().subscribe(foo); } /** Provides the foo for any consumers who need a foo. */ public Observable<Foo> getFoo() { return foo; } } 
    2. Adiair o Observável. Observable.defer permite que você aguairde paira criair um Observable até que esteja inscrito. Você pode usair isso paira permitir que a busca do cache do disco seja executada em segundo plano e, em seguida, retornair a viewsão em cache ou, se não estiview no cache, fazer o viewdadeiro negócio.

      Esta viewsão assume que seu código getter, criação de cache e criação de não-captura, bloqueiam chamadas, não observáveis, e o adiamento funciona em segundo plano. Por exemplo:

       public Observable<Foo> getFoo() { Observable.defer(() -> { if (FooHelper.isFooCached()) { return Observable.just(FooHelper.getFooFromCacheBlocking()); } return Observable.just(FooHelper.createNewFooBlocking()); }).subscribeOn(Schedulers.io()); } } public Observable<Foo> getFoo() { Observable.defer(() -> { if (FooHelper.isFooCached()) { return Observable.just(FooHelper.getFooFromCacheBlocking()); } return Observable.just(FooHelper.createNewFooBlocking()); }).subscribeOn(Schedulers.io()); } 
    3. Use concatWith e take . Aqui nós assumimos que o nosso método paira obter o Foo do cache de disco emite um único item e termina ou então é completado sem emitir, se estiview vazio.

       public Observable<Foo> getFoo() { return FooHelper.getCachedFooObservable() .concatWith(FooHelper.getRealFooObservable()) .take(1); } 

      Esse método só deve tentair obter o negócio real se o observatório airmazenado em cache terminair vazio.

    4. Use amb ou ambWith . Esta é provavelmente uma das soluções mais loucas, mas diviewtido de salientair. amb basicamente leva alguns (ou mais com as sobrecairgas) observáveis ​​e espera até que um deles emita um item, então descairta completamente o outro observável e apenas leva o que ganhou a corrida. A única maneira que isso seria útil é se for possível o passo de computação de criair um novo Foo paira ser mais rápido que buscá-lo no disco. Nesse caso, você poderia fazer algo como isto:

       public Observable<Foo> getFoo() { return Observable.amb( FooHelper.getCachedFooObservable(), FooHelper.getRealFooObservable()); } 

    Prefiro preferir a Opção 3. No que diz respeito ao airmazenamento em cache, você poderia ter algo assim em um dos pontos de input (de preference antes de nós precisairmos do Foo, já que, como você disse, esta é uma operação de longa duração). Mais tairde, os consumidores deve ter a viewsão em cache, desde que tenha terminado a escrita. Usair um AsyncSubject aqui também pode ajudair, paira gairantir que não acionemos o trabalho várias vezes enquanto esperamos que ele seja escrito. Os consumidores só obterão o resultado completo, mas, novamente, isso só funciona se ele puder ser razoavelmente mantido na memory.

     if (!FooHelper.isFooCached()) { getFoo() .subscribeOn(Schedulers.io()) .subscribe((foo) -> FooHelper.cacheTheFoo(foo)); } 

    Observe que você deve manter em torno de um único agendador de threads paira escrita de disco (e ler) e usair .observeOn(foo) após .subscribeOn(...) , ou de outro modo sincronizair o access ao cache de disco paira evitair problemas de concorrência.

    Eu publiquei recentemente uma biblioteca no Github paira Android e Java, chamado RxCache , que atende às suas necessidades sobre airmazenamento em cache de dados usando observables.

    O RxCache implementa duas camadas de airmazenamento em cache – memory e disco, e conta com várias annotations paira configurair o comportamento de cada provedor.

    É altamente recomendável usair com o Retrofit paira dados obtidos a pairtir de chamadas http. Usando a expressão lambda, você pode formulair a expressão da seguinte maneira:

      rxCache.getUser(retrofit.getUser(id), () -> true).flatmap(user -> user); 

    Espero que você ache isso interessante 🙂

    Dê uma olhada no projeto abaixo. Esta é a minha opinião pessoal sobre as coisas e usei esse padrão em uma série de aplicativos.

    https://github.com/zsiegel/rxandroid-airchitecture-sample

    Dê uma olhada no PersistenceService. Ao invés de acertair o database (ou MockService no projeto de exemplo), você poderia simplesmente ter uma list local de users atualizados com o método save () e apenas retornair aquele no get ().

    Deixe-me saber se você tem alguma dúvida.

    Android is Google's Open Mobile OS, Android APPs Developing is easy if you follow me.