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镐侯,詳情請點(diǎn)擊

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

Android RxCache使用詳解

Android RxCache原理解析


1 概述

2 基本使用

2.1 依賴配置

2.2 接口配置

2.3 新建Provider實(shí)例并使用它

2.4 再次回顧整個(gè)流程

3 RxCache使用場景

4 RxCache API

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

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

4.3 DynamicKeyGroup:分頁和過濾

5 Actionable RxCache API

6 高級選項(xiàng)

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注意事項(xiàng)

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 緩存您的圖片一樣,毫不費(fèi)力緩存您的數(shù)據(jù)對象。

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

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

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

當(dāng)提供一個(gè) observable, single, maybe or flowable (這些是RxJava2支持的響應(yīng)式數(shù)據(jù)類型) 這些由耗時(shí)操作提供的數(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"
}

因?yàn)镽xCache在內(nèi)部使用 Jolyglot 對數(shù)據(jù)進(jìn)行序列化和反序列化, 您需要選擇下列的依賴中選擇一個(gè)進(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>

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

這意味著贡珊,項(xiàng)目中Retrofit的APIService接口有多少個(gè)抽象方法的API需要實(shí)現(xiàn)緩存,一一對應(yīng)涉馁,就需要Providers提供多少個(gè)緩存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()方法來清除一行中的整個(gè)緩存门岔。

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

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

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

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

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

  • @ProviderKey 保護(hù)用戶數(shù)據(jù)的Provider方法的注解晦墙,強(qiáng)烈建議使用這個(gè)注解悦昵! 如果不使用該注解,該方法的名稱會被作為該P(yáng)rovider的key進(jìn)行文件緩存, 使用了代碼混淆的用戶很快會遇到問題晌畅,詳情請參閱 Proguard . 如果不使用代碼混淆但指,該注解也很有用,因?yàn)樗梢源_保您可以隨心所欲修改Provider數(shù)據(jù)緩存的方法名抗楔,而無需為舊緩存文件遷移問題而苦惱棋凳。

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

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

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

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

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

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

Supported annotations:

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

最后,使用RxCache.Builder實(shí)例化Provider接口跨跨,并提供一個(gè)有效的文件系統(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">再次回顧整個(gè)流程</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:某個(gè)條件(比如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));
    }

    //這個(gè)方法的返回值代替了現(xiàn)實(shí)開發(fā)中屁桑,您通過耗時(shí)操作獲得的數(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時(shí)驅(qū)逐該P(yáng)rovider所有緩存數(shù)據(jù)并重新請求
getMocksEvictProvider(oMocks, new EvictProvider(true))

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

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

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

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

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

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

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


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

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

//這行拋出一個(gè)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ù)選項(xiàng)

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

運(yùn)行時(shí)使用:


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

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

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

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

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

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

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

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

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

這個(gè)actionable的API提供了一種Application執(zhí)行文件寫入操作的簡單方法虹茶。 盡管使用RxCache經(jīng)典的api也可以實(shí)現(xiàn)寫入操作,但經(jīng)典的api有著復(fù)雜性且容易出錯(cuò)隅要。實(shí)際上蝴罪,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"
}

配置完成后廓啊,為每個(gè)Provider添加注解 @Actionable annotation

編譯器會生成一個(gè)新的類欢搜,該類與接口名稱相同,但是附加了一個(gè)“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”類的一個(gè)實(shí)例疮装,現(xiàn)在你已經(jīng)可以嘗試使用每個(gè)可用的寫操作 Actions .建議您瀏覽ActionsTest類,以查看哪些操作適合更適合你的現(xiàn)實(shí)需求粘都。

一些示例代碼:

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 -> {})

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

<h2 id="6">高級選項(xiàng)</h2>

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

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

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

您需要為您的Provider接口添加注解 @SchemeMigration. 這個(gè)注解接受一個(gè)數(shù)組 @Migration 樊展,反過來,Migration注釋同時(shí)接受一個(gè)版本號和一個(gè)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這個(gè)屬性,新的版本中變成了 long userId,這樣緩存數(shù)據(jù)的反序列化就會出現(xiàn)問題糯景,因此需要配置遷移注解

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

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

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

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

因?yàn)镽xCache需要內(nèi)部進(jìn)程才能清理內(nèi)存,所以數(shù)據(jù)最終將被全部清除脓魏。

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

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

您需要為您的Provider接口添加注解@EncryptKey. 這個(gè)annotation接受一個(gè)字符串作為加密/解密數(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í)設(shè)置某些參數(shù):

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

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

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

當(dāng)達(dá)到此限制時(shí)槽地,RxCache將無法繼續(xù)緩存數(shù)據(jù)。 這就是為何當(dāng)緩存數(shù)據(jù)容量即將達(dá)到閾值時(shí)烹卒,RxCache有一個(gè)自動化的過程來驅(qū)逐任何記錄闷盔,即使沒有滿足失效時(shí)間的緩存數(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注意事項(xiàng)</h3>

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

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

為了在子線程上執(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完美搭配蜒谤,兩者配合可以實(shí)現(xiàn)從始至終的自動管理緩存數(shù)據(jù)庫山宾。
您可以檢查RxCache和Retrofit的一個(gè)示例

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

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

RxCache的數(shù)據(jù)來源取決于下面三個(gè)數(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)系作者
  • 序言:七十年代末培他,一起剝皮案震驚了整個(gè)濱河市鹃两,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌舀凛,老刑警劉巖俊扳,帶你破解...
    沈念sama閱讀 222,590評論 6 517
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異猛遍,居然都是意外死亡馋记,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,157評論 3 399
  • 文/潘曉璐 我一進(jìn)店門懊烤,熙熙樓的掌柜王于貴愁眉苦臉地迎上來梯醒,“玉大人,你說我怎么就攤上這事腌紧∪紫埃” “怎么了?”我有些...
    開封第一講書人閱讀 169,301評論 0 362
  • 文/不壞的土叔 我叫張陵壁肋,是天一觀的道長号胚。 經(jīng)常有香客問我代箭,道長,這世上最難降的妖魔是什么涕刚? 我笑而不...
    開封第一講書人閱讀 60,078評論 1 300
  • 正文 為了忘掉前任嗡综,我火速辦了婚禮,結(jié)果婚禮上杜漠,老公的妹妹穿的比我還像新娘极景。我一直安慰自己,他們只是感情好驾茴,可當(dāng)我...
    茶點(diǎn)故事閱讀 69,082評論 6 398
  • 文/花漫 我一把揭開白布盼樟。 她就那樣靜靜地躺著,像睡著了一般锈至。 火紅的嫁衣襯著肌膚如雪晨缴。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,682評論 1 312
  • 那天峡捡,我揣著相機(jī)與錄音击碗,去河邊找鬼。 笑死们拙,一個(gè)胖子當(dāng)著我的面吹牛稍途,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播砚婆,決...
    沈念sama閱讀 41,155評論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼械拍,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了装盯?” 一聲冷哼從身側(cè)響起坷虑,我...
    開封第一講書人閱讀 40,098評論 0 277
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎埂奈,沒想到半個(gè)月后迄损,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,638評論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡挥转,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,701評論 3 342
  • 正文 我和宋清朗相戀三年海蔽,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片绑谣。...
    茶點(diǎn)故事閱讀 40,852評論 1 353
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖拗引,靈堂內(nèi)的尸體忽然破棺而出借宵,到底是詐尸還是另有隱情,我是刑警寧澤矾削,帶...
    沈念sama閱讀 36,520評論 5 351
  • 正文 年R本政府宣布壤玫,位于F島的核電站豁护,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏欲间。R本人自食惡果不足惜楚里,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,181評論 3 335
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望猎贴。 院中可真熱鬧班缎,春花似錦、人聲如沸她渴。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,674評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽趁耗。三九已至沉唠,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間苛败,已是汗流浹背满葛。 一陣腳步聲響...
    開封第一講書人閱讀 33,788評論 1 274
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留罢屈,地道東北人纱扭。 一個(gè)月前我還...
    沈念sama閱讀 49,279評論 3 379
  • 正文 我出身青樓,卻偏偏與公主長得像儡遮,于是被迫代替她去往敵國和親乳蛾。 傳聞我的和親對象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,851評論 2 361

推薦閱讀更多精彩內(nèi)容

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