RxJava+Retrofit2緩存庫:RxCache中文文檔

RxCache官方文檔翻譯

本文翻譯自:RxCache官方GitHub地址
版本號:RxCache 1.8.1-2.x

歡迎轉(zhuǎn)載,轉(zhuǎn)發(fā)請注明文章來源
http://write.blog.csdn.net/mdeditor#!postId=78056742 @卻把清梅嗅

中文文檔已發(fā)布GitHub,詳情請點擊

RxCache基本使用方法、Demo請參閱筆者的相關(guān)文章:

Android RxCache使用詳解

Android RxCache原理解析


1 概述

2 基本使用

2.1 依賴配置

2.2 接口配置

2.3 新建Provider實例并使用它

2.4 再次回顧整個流程

3 RxCache使用場景

4 RxCache API

4.1 EvictProvider:驅(qū)逐緩存數(shù)據(jù)

4.2 DynamicKey:篩選數(shù)據(jù)

4.3 DynamicKeyGroup:分頁和過濾

5 Actionable RxCache API

6 高級選項

6.1 數(shù)據(jù)遷移

6.2 數(shù)據(jù)加密

6.3 常規(guī)配置

6.3.1 配置要保留的數(shù)據(jù)的大小限制(以兆字節(jié)為單位)

6.3.2 如果未加載到數(shù)據(jù),使用過期的緩存數(shù)據(jù)

6.4 Android注意事項

6.5 和Retrofit搭配使用

7 其他

7.1 RxCache原理

7.2 代碼混淆

7.3 關(guān)于作者

7.4 RxCache Swift版本

7.5 作者其它使用RxJava的庫

8 關(guān)于中文文檔

<h2 id="1">概述</h2>

本庫的 目標(biāo) 很簡單: 就像Picasso 緩存您的圖片一樣,毫不費力緩存您的數(shù)據(jù)對象。

每個Android Application都是一個客戶端應(yīng)用程序,這意味著僅僅為緩存數(shù)據(jù)創(chuàng)建數(shù)據(jù)庫并進(jìn)行維護(hù)毫無意義。

事實上,傳統(tǒng)方式通過數(shù)據(jù)庫來緩存數(shù)據(jù)并沒有解決根本性的問題:以更加靈活簡單的方式配置緩存。

靈感來源于 Retrofit , RxCache是一個用于Android和Java的響應(yīng)式緩存庫,它可將您的緩存需求轉(zhuǎn)換為一個接口進(jìn)行配置。

當(dāng)提供一個 observable, single, maybe or flowable (這些是RxJava2支持的響應(yīng)式數(shù)據(jù)類型) 這些由耗時操作提供的數(shù)據(jù),RxCache確定是否需要subscribe,或覆蓋先前緩存的數(shù)據(jù)。

此決定是基于RxCache的Providers進(jìn)行配置的。

<h2 id="2">基本使用</h2>

<h3 id="2.1">依賴配置</h3>

在您的Project級的build.gradle中添加JitPack倉庫:

allprojects {
    repositories {
        jcenter()
        maven { url "https://jitpack.io" }
    }
}

將下列的依賴添加到Module的build.gradle中:

dependencies {
    compile "com.github.VictorAlbertos.RxCache:runtime:1.8.1-2.x"
    compile "io.reactivex.rxjava2:rxjava:2.0.6"
}

因為RxCache在內(nèi)部使用 Jolyglot 對數(shù)據(jù)進(jìn)行序列化和反序列化, 您需要選擇下列的依賴中選擇一個進(jìn)行添加:

dependencies {
    // To use Gson 
    compile 'com.github.VictorAlbertos.Jolyglot:gson:0.0.3'
    
    // To use Jackson
    compile 'com.github.VictorAlbertos.Jolyglot:jackson:0.0.3'
    
    // To use Moshi
    compile 'com.github.VictorAlbertos.Jolyglot:moshi:0.0.3'
}

<h3 id="2.2">接口配置</h3>

聲明一個接口,常規(guī)使用方式中(以Retrofit網(wǎng)絡(luò)請求為例),創(chuàng)建和API需求同樣多的Providers來緩存您的數(shù)據(jù)。

這意味著,項目中Retrofit的APIService接口有多少個抽象方法的API需要實現(xiàn)緩存,一一對應(yīng),就需要Providers提供多少個緩存API方法

interface Providers {
        
        @ProviderKey("mocks")
        Observable<List<Mock>> getMocks(Observable<List<Mock>> oMocks);
    
        @ProviderKey("mocks-5-minute-ttl")
        @LifeCache(duration = 5, timeUnit = TimeUnit.MINUTES)   //緩存有效期5分鐘
        Observable<List<Mock>> getMocksWith5MinutesLifeTime(Observable<List<Mock>> oMocks);
    
        @ProviderKey("mocks-evict-provider")
        Observable<List<Mock>> getMocksEvictProvider(Observable<List<Mock>> oMocks, EvictProvider evictProvider);
    
        @ProviderKey("mocks-paginate")
        Observable<List<Mock>> getMocksPaginate(Observable<List<Mock>> oMocks, DynamicKey page);
    
        @ProviderKey("mocks-paginate-evict-per-page")
        Observable<List<Mock>> getMocksPaginateEvictingPerPage(Observable<List<Mock>> oMocks, DynamicKey page, EvictDynamicKey evictPage);
        
        @ProviderKey("mocks-paginate-evict-per-filter")
        Observable<List<Mock>> getMocksPaginateWithFiltersEvictingPerFilter(Observable<List<Mock>> oMocks, DynamicKeyGroup filterPage, EvictDynamicKey evictFilter);
}

RxCache暴露了evictAll()方法來清除一行中的整個緩存。

RxCache的Provider配置中,方法所需要的參數(shù)用來配置Provider處理緩存的方式:

  • 無論如何,必不可少的參數(shù)是RxJava提供的響應(yīng)式基本數(shù)據(jù)類型(如Observable),這個參數(shù)的意義是將你想緩存的Retrofit接口作為參數(shù)傳入,并以相同的RxJava數(shù)據(jù)類型作為返回。

    這意味著,您可以不配置任何可選項,但是您必須將您要緩存的數(shù)據(jù)作為參數(shù)交給RxCache進(jìn)行緩存.

  • EvictProvider 是否驅(qū)逐與該Provider相關(guān)聯(lián)的所有緩存數(shù)據(jù).

    該對象通過構(gòu)造方法進(jìn)行實例化,創(chuàng)建時需要傳入boolean類型的參數(shù),當(dāng)參數(shù)為true時,RxCache會直接驅(qū)逐該Provider的緩存數(shù)據(jù),進(jìn)行最新的網(wǎng)絡(luò)請求并進(jìn)行緩存;若參數(shù)為false,若緩存數(shù)據(jù)未過期,正常加載緩存數(shù)據(jù)

  • @ProviderKey 保護(hù)用戶數(shù)據(jù)的Provider方法的注解,強烈建議使用這個注解! 如果不使用該注解,該方法的名稱會被作為該Provider的key進(jìn)行文件緩存, 使用了代碼混淆的用戶很快會遇到問題,詳情請參閱 Proguard . 如果不使用代碼混淆,該注解也很有用,因為它可以確保您可以隨心所欲修改Provider數(shù)據(jù)緩存的方法名,而無需為舊緩存文件遷移問題而苦惱。

    該注解是最近版本添加的,在考慮到代碼混淆(方法名的改變導(dǎo)致緩存文件命名的改變)和緩存數(shù)據(jù)遷移,強烈建議使用該注解!

  • EvictDynamicKey 是否驅(qū)逐具體的緩存數(shù)據(jù) DynamicKey.

    緩存數(shù)據(jù)驅(qū)逐范圍比EvictProvider小(后者是驅(qū)逐所有緩存),比EvictDynamicKeyGroup大(后者是驅(qū)逐更精細(xì)分類的緩存),舉例,若將userId(唯一)作為參數(shù)傳入DynamicKey,清除緩存時,僅清除該userId下的對應(yīng)緩存

  • EvictDynamicKeyGroup 是否驅(qū)逐更加具體的緩存數(shù)據(jù) DynamicKeyGroup.

    和EvictDynamicKey對比,上述案例中,DynamicKeyGroup可以filter到某userId下緩存的某一頁數(shù)據(jù)進(jìn)行驅(qū)逐,其他緩存不驅(qū)逐

  • DynamicKey 通過傳入一個對象參數(shù)(比如userId)實現(xiàn)和對應(yīng)緩存數(shù)據(jù)的綁定, 清除該key相關(guān)聯(lián)的緩存數(shù)據(jù)請使用 EvictDynamicKey.
  • DynamicKeyGroup 通過傳入一個Group參數(shù)(比如userId,數(shù)據(jù)的分類)實現(xiàn)和對應(yīng)緩存數(shù)據(jù)的綁定, 清除該keyGroup相關(guān)聯(lián)的緩存數(shù)據(jù)請使用EvictDynamicKeyGroup.

Supported annotations:

<h3 id="2.3">新建Provider實例并使用它</h3>

最后,使用RxCache.Builder實例化Provider接口,并提供一個有效的文件系統(tǒng)路徑,這將允許RxCache在磁盤上寫入緩存數(shù)據(jù)。

//獲取緩存的文件存放路徑
File cacheDir = getFilesDir();
Providers providers = new RxCache.Builder()
                            .persistence(cacheDir, new GsonSpeaker())//配置緩存的文件存放路徑,以及數(shù)據(jù)的序列化和反序列化
                            .using(Providers.class);    //和Retrofit相似,傳入緩存API的接口

<h3 id="2.4">再次回顧整個流程</h3>

interface Providers {
    //配置要緩存的數(shù)據(jù),以及是否驅(qū)逐緩存數(shù)據(jù)并請求網(wǎng)絡(luò)
    @ProviderKey("mocks-evict-provider")
    Observable<List<Mock>> getMocksEvictProvider(Observable<List<Mock>> oMocks, EvictProvider evictProvider);
    
    //配置要緩存的數(shù)據(jù),簡單的緩存數(shù)據(jù)分類,以及是否驅(qū)逐該分類下的緩存數(shù)據(jù)并請求網(wǎng)絡(luò)
    @ProviderKey("mocks-paginate-evict-per-page")
    Observable<List<Mock>> getMocksPaginateEvictingPerPage(Observable<List<Mock>> oMocks, DynamicKey page, EvictDynamicKey evictPage);
    
    //配置要緩存的數(shù)據(jù),復(fù)雜的緩存數(shù)據(jù)分類,以及是否驅(qū)逐該詳細(xì)分類下的緩存數(shù)據(jù)并請求網(wǎng)絡(luò)
    @ProviderKey("mocks-paginate-evict-per-filter")
    Observable<List<Mock>> getMocksPaginateWithFiltersEvictingPerFilter(Observable<List<Mock>> oMocks, DynamicKeyGroup filterPage, EvictDynamicKey evictFilter);
}
public class Repository {
    private final Providers providers;
    
    //初始化RxCache的Provider
    public Repository(File cacheDir) {
        providers = new RxCache.Builder()
                .persistence(cacheDir, new GsonSpeaker())
                .using(Providers.class);
    }
    
    //參數(shù)update:是否加載最新數(shù)據(jù)
    public Observable<List<Mock>> getMocks(final boolean update) {
        return providers.getMocksEvictProvider(getExpensiveMocks(), new EvictProvider(update));
    }
    
    //參數(shù)page:第幾頁的數(shù)據(jù),update:是否加載該頁的最新數(shù)據(jù)
    public Observable<List<Mock>> getMocksPaginate(final int page, final boolean update) {
        return providers.getMocksPaginateEvictingPerPage(getExpensiveMocks(), new DynamicKey(page), new EvictDynamicKey(update));
    }
    
    //參數(shù)filter:某個條件(比如userName),參數(shù)page:第幾頁數(shù)據(jù),參數(shù)updateFilter:是否加載該userName該頁的最新數(shù)據(jù)
    public Observable<List<Mock>> getMocksWithFiltersPaginate(final String filter, final int page, final boolean updateFilter) {
        return providers.getMocksPaginateWithFiltersEvictingPerFilter(getExpensiveMocks(), new DynamicKeyGroup(filter, page), new EvictDynamicKey(updateFilter));
    }

    //這個方法的返回值代替了現(xiàn)實開發(fā)中,您通過耗時操作獲得的數(shù)據(jù)類型(比如Observable<T>)
    //如果這里您使用了Retrofit進(jìn)行網(wǎng)絡(luò)請求,那么可以說是拿來即用。
    private Observable<List<Mock>> getExpensiveMocks() {
        return Observable.just(Arrays.asList(new Mock("")));
    }
}

<h2 id="3">RxCache使用場景</h2>

  • 使用經(jīng)典的RxCache API進(jìn)行文件的讀寫操作。
  • 使用Actionable的API,專用于文件的寫操作。

<h2 id="4">RxCache API</h2>

下面的用例說明了一些常見的情況,這將有助于您了解“DynamicKey”和“DynamicKeyGroup”類的使用以及清除數(shù)據(jù)。

<h3 id="4.1">EvictProvider:驅(qū)逐緩存數(shù)據(jù)</h3>

不驅(qū)逐數(shù)據(jù)

Observable<List<Mock>> getMocks(Observable<List<Mock>> oMocks);

驅(qū)逐數(shù)據(jù)

Observable<List<Mock>> getMocksEvictProvider(Observable<List<Mock>> oMocks, EvictProvider evictProvider);

業(yè)務(wù)代碼中使用:


//接收到Observable時驅(qū)逐該Provider所有緩存數(shù)據(jù)并重新請求
getMocksEvictProvider(oMocks, new EvictProvider(true))

//這行會拋出一個IllegalArgumentException:“提供了EvictDynamicKey但沒有提供任何DynamicKey”
getMocksEvictProvider(oMocks, new EvictDynamicKey(true))

<h3 id="4.2">DynamicKey:篩選數(shù)據(jù)</h3>

指定某個條件,不驅(qū)逐該條件下的緩存數(shù)據(jù)

Observable<List<Mock>> getMocksFiltered(Observable<List<Mock>> oMocks, DynamicKey filter);

指定某個條件,可選擇是否驅(qū)逐該條件下的緩存數(shù)據(jù)

Observable<List<Mock>> getMocksFilteredEvict(Observable<List<Mock>> oMocks, DynamicKey filter, EvictProvider evictDynamicKey);

業(yè)務(wù)代碼中使用:


//接收到Observable時驅(qū)逐該Provider所有緩存數(shù)據(jù)并重新請求
getMocksFilteredEvict(oMocks, new DynamicKey("actives"), new EvictProvider(true))

//通過使用EvictDynamicKey,接收到Observable時,驅(qū)逐該DynamicKey("actives")下所有緩存數(shù)據(jù)并重新請求
getMocksFilteredEvict(oMocks, new DynamicKey("actives"), new EvictDynamicKey(true))

//這行拋出一個IllegalArgumentException:“提供了EvictDynamicKeyGroup,但沒有提供任何DynamicKeyGroup”
getMocksFilteredEvict(oMocks, new DynamicKey("actives"), new EvictDynamicKeyGroup(true))

<h3 id="4.3">DynamicKeyGroup:分頁和過濾</h3>

List數(shù)據(jù)的分頁和過濾,不驅(qū)逐緩存數(shù)據(jù)

Observable<List<Mock>> getMocksFilteredPaginate(Observable<List<Mock>> oMocks, DynamicKey filterAndPage);

List數(shù)據(jù)的分頁和過濾,包含是否驅(qū)逐緩存數(shù)據(jù)選項

Observable<List<Mock>> getMocksFilteredPaginateEvict(Observable<List<Mock>> oMocks, DynamicKeyGroup filterAndPage, EvictProvider evictProvider);

運行時使用:


//接收到Observable時驅(qū)逐該Provider所有緩存數(shù)據(jù)并重新請求
getMocksFilteredPaginateEvict(oMocks, new DynamicKeyGroup("actives", "page1"), new EvictProvider(true))

//通過使用EvictDynamicKey,接收到Observable時,驅(qū)逐該DynamicKey("actives", "page1")下所有緩存數(shù)據(jù)并重新請求
getMocksFilteredPaginateEvict(oMocks, new DynamicKeyGroup("actives", "page1"), new EvictDynamicKey(true))

//通過使用EvictDynamicKey,接收到Observable時,驅(qū)逐該DynamicKeyGroup("actives", "page1")下所有緩存數(shù)據(jù)并重新請求
getMocksFilteredPaginateInvalidate(oMocks, new DynamicKeyGroup("actives", "page1"), new EvictDynamicKeyGroup(true))

正如你所看到的,使用“DynamicKey”或“DynamicKeyGroup”以及“EvictProvider”類的重點就是在根據(jù)不同范圍下,驅(qū)逐緩存數(shù)據(jù)對象。

上述示例代碼中展示了方法接收“EvictProvider”的參數(shù),以及EvictProvider的子類DynamicKey、DynamicKeyGroup,保證更詳細(xì)的數(shù)據(jù)分類和篩選,并進(jìn)行緩存。

上述代碼中,我已經(jīng)做到了這一點,您總是可以通過自己的篩選,將數(shù)據(jù)的key類別縮小到你真正需要驅(qū)逐的類型。對于最后一個例子,我將在實際產(chǎn)品代碼中使用“EvictDynamicKey”,因為這樣我就可以對已過濾的項目進(jìn)行分頁,并將其按過濾器排除,例如通過刷新來觸發(fā)。

這里還有完整的例子 Android and Java projects.

<h2 id="5">Actionable RxCache API</h2>

限制:目前actionable的API僅支持Observable的數(shù)據(jù)類型。

這個actionable的API提供了一種Application執(zhí)行文件寫入操作的簡單方法。 盡管使用RxCache經(jīng)典的api也可以實現(xiàn)寫入操作,但經(jīng)典的api有著復(fù)雜性且容易出錯。實際上,Actions類是圍繞經(jīng)典api的進(jìn)行了一層包裝。

為了能夠使用該actionable API,首先,你需要添加 repository compiler 的依賴到您的build.gradle:

dependencies {
     // other classpath definitions here
     classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8'
 }

然后確保在您的app / build.gradle中應(yīng)用該插件,并添加編譯器依賴關(guān)系:

apply plugin: 'com.neenbedankt.android-apt'

dependencies {
    // apt command comes from the android-apt plugin
    apt "com.github.VictorAlbertos.RxCache:compiler:1.8.0-1.x"
}

配置完成后,為每個Provider添加注解 @Actionable annotation

編譯器會生成一個新的類,該類與接口名稱相同,但是附加了一個“Actionable”后綴,并暴露出和該接口同樣多的方法

參數(shù)供應(yīng)中的順序必須與以下示例保持一致:

public interface RxProviders {
    @Actionable
    Observable<List<Mock.InnerMock>> mocks(Observable<List<Mock.InnerMock>> message, EvictProvider evictProvider);

    @Actionable
    Observable<List<Mock>> mocksDynamicKey(Observable<List<Mock>> message, DynamicKey dynamicKey, EvictDynamicKey evictDynamicKey);

    @Actionable
    Observable<List<Mock>> mocksDynamicKeyGroup(Observable<List<Mock>> message, DynamicKeyGroup dynamicKeyGroup, EvictDynamicKeyGroup evictDynamicKey);
}

請注意,Observable內(nèi)的值必須是“List”類型,否則將拋出異常。

這樣上面的RxProviders接口將會在生成的“RxProvidersActionable”類中暴露出下面的方法:

RxProvidersActionable.mocks(RxProviders proxy);
RxProvidersActionable.mocksDynamicKey(RxProviders proxy, DynamicKey dynamicKey);
RxProvidersActionable.mocksDynamicKeyGroup(RxProviders proxy, DynamicKeyGroup dynamicKeyGroup);

這些方法返回“Actions”類的一個實例,現(xiàn)在你已經(jīng)可以嘗試使用每個可用的寫操作 Actions .建議您瀏覽ActionsTest類,以查看哪些操作適合更適合你的現(xiàn)實需求。

一些示例代碼:

ActionsProviders.mocks(rxProviders)
    .addFirst(new Mock())
    .addLast(new Mock())
    //Add a new mock at 5 position
    .add((position, count) -> position == 5, new Mock())

    .evictFirst()
    //Evict first element if the cache has already 300 records
    .evictFirst(count -> count > 300)
    .evictLast()
    //Evict last element if the cache has already 300 records
    .evictLast(count -> count > 300)
    //Evict all inactive elements
    .evictIterable((position, count, mock) -> mock.isInactive())
    .evictAll()

    //Update the mock with id 5
    .update(mock -> mock.getId() == 5, mock -> {
        mock.setActive();
        return mock;
    })
    //Update all inactive mocks
    .updateIterable(mock -> mock.isInactive(), mock -> {
        mock.setActive();
        return mock;
    })
    .toObservable()
    .subscribe(processedMocks -> {})

之前的每個Action只有在composed的observable接收到subscribe之后才會執(zhí)行。

<h2 id="6">高級選項</h2>

<h3 id="6.1">數(shù)據(jù)遷移</h3>

RxCache提供了一種處理版本之間緩存數(shù)據(jù)遷移的簡單方式。

簡單來說,最新的版本中某個接口返回值類型內(nèi)部發(fā)生了改變,從而獲取數(shù)據(jù)的方式發(fā)生了改變,但是存儲在本地的數(shù)據(jù),是未改變的版本,這樣在反序列化時就可能發(fā)生錯誤,為了規(guī)避這個風(fēng)險,作者就加入了數(shù)據(jù)遷移的功能

您需要為您的Provider接口添加注解 @SchemeMigration. 這個注解接受一個數(shù)組 @Migration ,反過來,Migration注釋同時接受一個版本號和一個Classes的數(shù)組,這些數(shù)組將從持久層中刪除。

@SchemeMigration({
            @Migration(version = 1, evictClasses = {Mock.class}),
            @Migration(version = 2, evictClasses = {Mock2.class}),
            @Migration(version = 3, evictClasses = {Mock3.class})
    })
interface Providers {}

只有當(dāng)RxCache使用的Class類中數(shù)據(jù)結(jié)構(gòu)發(fā)生了改變,才需要添加新的遷移注解。

比如說,您的緩存數(shù)據(jù)User中有 int userId這個屬性,新的版本中變成了 long userId,這樣緩存數(shù)據(jù)的反序列化就會出現(xiàn)問題,因此需要配置遷移注解

刪除類或刪除類的字段將由RxCache自動處理,因此當(dāng)字段或整個類被刪除時,不需要遷移新的注解。

@SchemeMigration({
            @Migration(version = 1, evictClasses = {Mock.class}),
            @Migration(version = 2, evictClasses = {Mock2.class})
    })
interface Providers {}

但是現(xiàn)在,“Mock”類已經(jīng)從項目中刪除了,所以不可能再引用它的類了。 要解決這個問題,只需刪除這行遷移的注解即可。

@SchemeMigration({
            @Migration(version = 2, evictClasses = {Mock2.class})
    })
interface Providers {}

因為RxCache需要內(nèi)部進(jìn)程才能清理內(nèi)存,所以數(shù)據(jù)最終將被全部清除。

<h3 id="6.2">數(shù)據(jù)加密</h3>

RxCache提供了一種加密數(shù)據(jù)的簡單機制。

您需要為您的Provider接口添加注解@EncryptKey. 這個annotation接受一個字符串作為加密/解密數(shù)據(jù)所必需的key。 但是,您需要使用@Encrypt對Provider的緩存進(jìn)行注解,以便緩存數(shù)據(jù)加密。 如果沒有設(shè)置@Encrypt,則不會進(jìn)行加密。

重要提示:如果提供的“key”值 @EncryptKey 在編譯期間進(jìn)行了修改,那么以前的緩存數(shù)據(jù)將無法被RxCache驅(qū)逐/獲取。

@EncryptKey("myStrongKey-1234")
interface Providers {
        @Encrypt
        Observable<List<Mock>> getMocksEncrypted(Observable<List<Mock>> oMocks);

        Observable<List<Mock>> getMocksNotEncrypted(Observable<List<Mock>> oMocks);
}

<h3 id="6.3">常規(guī)配置</h3>

RxCache允許在構(gòu)建Provider實例時設(shè)置某些參數(shù):

<h4 id="6.3.1">配置要保留的數(shù)據(jù)的大小限制(以兆字節(jié)為單位)</h4>

默認(rèn)情況下,RxCache將限制設(shè)置為100M,但您可以在構(gòu)建Provider實例時調(diào)用setMaxMBPersistenceCache方法來更改此值。

new RxCache.Builder()
            .setMaxMBPersistenceCache(maxMgPersistenceCache)
            .persistence(cacheDir)
            .using(Providers.class);

當(dāng)達(dá)到此限制時,RxCache將無法繼續(xù)緩存數(shù)據(jù)。 這就是為何當(dāng)緩存數(shù)據(jù)容量即將達(dá)到閾值時,RxCache有一個自動化的過程來驅(qū)逐任何記錄,即使沒有滿足失效時間的緩存數(shù)據(jù)也被驅(qū)逐。

唯一的例外是,當(dāng)您的Provider的某方法用@Expirable 注解注釋,并將其值設(shè)置為false將會被保存,而不會被RxCache自動化驅(qū)逐。

interface Providers {
    //即使緩存數(shù)據(jù)達(dá)到閾值,也不會被RxCache自動驅(qū)逐
    @Expirable(false)
    Observable<List<Mock>> getMocksNotExpirable(Observable<List<Mock>> oMocks);
}

<h4 id="6.3.2">如果未加載到數(shù)據(jù),使用過期的緩存數(shù)據(jù)</h4>

默認(rèn)情況下,如果緩存的數(shù)據(jù)已過期并且observable loader返回的數(shù)據(jù)為空,RxCache將拋出RuntimeException異常。

您可以修改此行為,允許RxCache在這種情況下提供被驅(qū)逐的數(shù)據(jù),使用方式很簡單,通過將useExpiredDataIfLoaderNotAvailable的值設(shè)置為true:

new RxCache.Builder()
            .useExpiredDataIfLoaderNotAvailable(true)   //RxCache提供被驅(qū)逐的數(shù)據(jù)
            .persistence(cacheDir)
            .using(Providers.class);

<h3 id="6.4">Android注意事項</h3>

要構(gòu)建由RxCache提供的接口實例,您需要提供對文件系統(tǒng)的引用。 在Android上,您可以從Application類獲取文件引用調(diào)用getFilesDir()。

此外,建議您在應(yīng)用程序的整個生命周期中使用此Android應(yīng)用程序類來提供RxCache的唯一實例(全局單例)。

為了在子線程上執(zhí)行Observable,并通過主UI線程上的onNext發(fā)出結(jié)果,您應(yīng)該使用RxAndroid提供的內(nèi)置方法。

即 observable.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe();

你可以查看Demo: Android example

<h3 id="6.5">和Retrofit搭配使用</h3>

RxCache和Retrofit完美搭配,兩者配合可以實現(xiàn)從始至終的自動管理緩存數(shù)據(jù)庫。
您可以檢查RxCache和Retrofit的一個示例。

<h2 id="7">其他</h2>

<h3 id="7.1">RxCache原理</h3>

RxCache的數(shù)據(jù)來源取決于下面三個數(shù)據(jù)層中某一層:

*內(nèi)存層 - >由Apache ReferenceMap提供支持。
*持久層 - > RxCache內(nèi)部使用Jolyglot來對對象進(jìn)行序列化和反序列化。
*加載器層(由客戶端庫提供的Observable請求,比如網(wǎng)絡(luò)請求)

*如果請求的數(shù)據(jù)在內(nèi)存中,并且尚未過期,則從內(nèi)存中獲取。
*否則請求的數(shù)據(jù)在持久層中,并且尚未過期,則從持久層獲取。
*否則從加載器層請求獲取數(shù)據(jù)。

<h3 id="7.2">代碼混淆</h3>

-dontwarn io.rx_cache.internal.**
-keepclassmembers enum io.rx_cache.Source { *; }

<h3 id="7.3">關(guān)于作者</h3>

Víctor Albertos

<h3 id="7.4">RxCache Swift版本:</h3>

RxCache: Reactive caching library for Swift.

<h3 id="7.5">作者其它使用RxJava的庫:</h3>

  • Mockery: Android and Java library for mocking and testing networking layers with built-in support for Retrofit.
  • RxActivityResult: A reactive-tiny-badass-vindictive library to break with the OnActivityResult implementation as it breaks the observables chain.
  • RxFcm: RxJava extension for Android Firebase Cloud Messaging (aka fcm).
  • RxSocialConnect: OAuth RxJava extension for Android.

<h2 id="8">關(guān)于中文文檔</h2>

翻譯

參考

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 推薦:看到如此多的 MVP+Dagger2+Retrofit+Rxjava 項目, 輕松拿 star, 心動了嗎?...
    JessYan閱讀 46,657評論 68 183
  • Spring Boot 參考指南 介紹 轉(zhuǎn)載自:https://www.gitbook.com/book/qbgb...
    毛宇鵬閱讀 47,290評論 6 342
  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn),斷路器,智...
    卡卡羅2017閱讀 136,715評論 19 139
  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 179,366評論 25 708
  • 評委辯友觀眾晚上好,我方觀點是:艾滋病是醫(yī)學(xué)問題,不是社會問題。 主要證據(jù)如下:第一點、艾滋病的定義是醫(yī)學(xué)定義,本...
    鯨翎閱讀 5,582評論 0 5

友情鏈接更多精彩內(nèi)容