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)文章:
1 概述
2 基本使用
3 RxCache使用場景
4 RxCache API
4.1 EvictProvider:驅(qū)逐緩存數(shù)據(jù)
5 Actionable RxCache API
6 高級選項(xiàng)
6.3.1 配置要保留的數(shù)據(jù)的大小限制(以兆字節(jié)為單位)
6.3.2 如果未加載到數(shù)據(jù)铐拐,使用過期的緩存數(shù)據(jù)
7 其他
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:
- @LifeCache 設(shè)置緩存過期時(shí)間. 如果沒有設(shè)置@LifeCache , 數(shù)據(jù)將被永久緩存忙芒,直到你使用了 EvictProvider, EvictDynamicKey or EvictDynamicKeyGroup .
- @Actionable 提供了使用提供程序執(zhí)行寫入操作的簡單方法。 詳情參考 here
- @SchemeMigration 和 @Migration 提供了一種處理版本之間遷移的簡單機(jī)制讳侨。 詳情參考 here
- @Expirable 決定該P(yáng)rovider是否將被排除在清除范圍之外.詳情參考 here
- @EncryptKey 和 @Encrypt 提供了一種在持久層上加密/解密數(shù)據(jù)的簡單方法呵萨。詳情參考 here
<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
- https://twitter.com/_victorAlbertos
- https://www.linkedin.com/in/victoralbertos
- https://github.com/VictorAlbertos
<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>
翻譯
- 翻譯:qingmei2
參考
- 《你不知道的Retrofit緩存庫RxCache》by @JessYan:講述了RxCache的使用懊缺,以及相關(guān)功能的原理分析。