Retrofit緩存庫(kù)RxCache怎么理解,針對(duì)這個(gè)問(wèn)題,這篇文章詳細(xì)介紹了相對(duì)應(yīng)的分析和解答,希望可以幫助更多想解決這個(gè)問(wèn)題的小伙伴找到更簡(jiǎn)單易行的方法。
井陘礦ssl適用于網(wǎng)站、小程序/APP、API接口等需要進(jìn)行數(shù)據(jù)傳輸應(yīng)用場(chǎng)景,ssl證書未來(lái)市場(chǎng)廣闊!成為創(chuàng)新互聯(lián)公司的ssl證書銷售渠道,可以享受市場(chǎng)價(jià)格4-6折優(yōu)惠!如果有意向歡迎電話聯(lián)系或者加微信:18982081108(備注:SSL證書合作)期待與您的合作!
前言
Retrofit無(wú)疑是當(dāng)下最火的網(wǎng)絡(luò)請(qǐng)求庫(kù),與同門師兄Okhttp配合使用,簡(jiǎn)直是每個(gè)項(xiàng)目的標(biāo)配,因?yàn)镺khttp自帶緩存,所以很多人并不關(guān)心其他緩存庫(kù),但是使用過(guò)Okhttp緩存的小伙伴,肯定知道Okhttp的緩存必須配合Header使用,比較麻煩,也不夠靈活,所以現(xiàn)在為大家推薦一款專門為Retrifit打造的緩存庫(kù)RxCache.
項(xiàng)目地址: RxCache Demo地址: RxCacheSample
簡(jiǎn)介
RxCache使用注解來(lái)為Retrofit配置緩存信息,內(nèi)部使用動(dòng)態(tài)代理和Dagger來(lái)實(shí)現(xiàn),這個(gè)庫(kù)的資料相對(duì)較少,官方教程又是全英文的,這無(wú)疑給開(kāi)發(fā)者增加了使用難度,其實(shí)我英文也不好,但是源碼是通用的啊,所以我為大家從源碼的角度來(lái)講解此庫(kù),此庫(kù)源碼的難點(diǎn)其實(shí)都在Dagger注入上,我先為大家講解用法,后面會(huì)再寫篇文章講解源碼,在學(xué)習(xí)Dagger的朋友除了建議看看我的MVPArms外,還可以看看這個(gè)RxCache的源碼,能學(xué)到很多東西,先給張RxCache的架構(gòu)圖,讓大家嘗嘗鮮,請(qǐng)期待我后面的源碼分析.
使用
1.定義接口,和Retrofit類似,接口中每個(gè)方法和Retrofit接口中的方法一一對(duì)應(yīng),每個(gè)方法的參數(shù)中必須傳入對(duì)應(yīng)Retrofit接口方法的返回值(返回值必須為Observable,否則報(bào)錯(cuò)),另外幾個(gè)參數(shù)DynamicKey,DynamicKeyGroup和EvictProvider不是必須的,但是如果要傳入,每個(gè)都只能傳入一個(gè)對(duì)象,否則報(bào)錯(cuò),這幾個(gè)參數(shù)的意義是初學(xué)者最困惑的,后面會(huì)分析.
/** * 此為RxCache官方Demo */ public interface CacheProviders { @LifeCache(duration = 2, timeUnit = TimeUnit.MINUTES) Observable<Reply<List<Repo>>> getRepos(Observable<List<Repo>> oRepos, DynamicKey userName, EvictDynamicKey evictDynamicKey); @LifeCache(duration = 2, timeUnit = TimeUnit.MINUTES) Observable<Reply<List<User>>> getUsers(Observable<List<User>> oUsers, DynamicKey idLastUserQueried, EvictProvider evictProvider); Observable<Reply<User>> getCurrentUser(Observable<User> oUser, EvictProvider evictProvider); }
2.將接口實(shí)例化,和Retrofit構(gòu)建方式類似,將接口通過(guò)using方法傳入,返回一個(gè)接口的動(dòng)態(tài)代理對(duì)象,調(diào)用此對(duì)象的方法傳入對(duì)應(yīng)參數(shù)就可以實(shí)現(xiàn)緩存了,通過(guò)注解和傳入不同的參數(shù)可以實(shí)現(xiàn)一些自定義的配置, so easy~
CacheProviders cacheProviders = new RxCache.Builder() .persistence(cacheDir, new GsonSpeaker()) .using(CacheProviders.class);
詳解
其實(shí)RxCache的使用比較簡(jiǎn)單,上面的兩步就可以輕松的實(shí)現(xiàn)緩存,此庫(kù)的的特色主要集中在對(duì)緩存的自定義配置,所以我來(lái)主要講講那些參數(shù)和注解是怎么回事?
參數(shù)
Observable
此Observable的意義為需要將你想緩存的Retrofit接口作為參數(shù)傳入(返回值必須為Observable),RxCache會(huì)在沒(méi)有緩存,或者緩存已經(jīng)過(guò)期,或者EvictProvider為true時(shí),通過(guò)這個(gè)Retrofit接口重新請(qǐng)求***的數(shù)據(jù),并且將服務(wù)器返回的結(jié)果包裝成Reply返回,返回之前會(huì)向內(nèi)存緩存和磁盤緩存中各保存一份.
值得一提的是,如果需要知道返回的結(jié)果是來(lái)自哪里(本地,內(nèi)存還是網(wǎng)絡(luò)),是否加密,則可以使用Observable<Reply<List<Repo>>>作為方法的返回值,這樣RxCache則會(huì)使用Reply包裝結(jié)果,如果沒(méi)這個(gè)需求則直接在范型中聲明結(jié)果的數(shù)據(jù)類型Observable<List<Repo>>
例外
如果構(gòu)建RxCache的時(shí)候?qū)seExpiredDataIfLoaderNotAvailable設(shè)置成true,會(huì)在數(shù)據(jù)為空或者發(fā)生錯(cuò)誤時(shí),忽視EvictProvider為true或者緩存過(guò)期的情況,繼續(xù)使用緩存(前提是之前請(qǐng)求過(guò)有緩存).
DynamicKey & DynamicKeyGroup
有很多開(kāi)發(fā)者最困惑的就是這兩個(gè)參數(shù)的意義,兩個(gè)一起傳以及不傳會(huì)有影響嗎?說(shuō)到這里就要提下,RxCache是怎么存儲(chǔ)緩存的,RxCache并不是通過(guò)使用URL充當(dāng)標(biāo)識(shí)符來(lái)儲(chǔ)存和獲取緩存的.
那是什么呢?
沒(méi)錯(cuò)RxCache就是通過(guò)這兩個(gè)對(duì)象加上上面CacheProviders接口中聲明的方法名,組合起來(lái)一個(gè)標(biāo)識(shí)符,通過(guò)這個(gè)標(biāo)識(shí)符來(lái)存儲(chǔ)和獲取緩存.
標(biāo)識(shí)符規(guī)則為:
方法名 + $d$d$d$" + dynamicKey.dynamicKey + "$g$g$g$" + DynamicKeyGroup.group
dynamicKey或DynamicKeyGroup為空時(shí)則返回空字符串,即什么都不傳的標(biāo)識(shí)符為:
"方法名$d$d$d$$g$g$g$"
什么意思呢?
比如RxCache,的內(nèi)存緩存使用的是Map,它就用這個(gè)標(biāo)識(shí)符作為Key,put和get數(shù)據(jù)(本地緩存則是將這個(gè)標(biāo)識(shí)符作為文件名,使用流寫入或讀取這個(gè)文件,來(lái)儲(chǔ)存或獲取緩存),如果儲(chǔ)存和獲取的標(biāo)識(shí)符不一致那就取不到想取的緩存.
和我們有什么關(guān)系呢?
舉個(gè)例子,我們一個(gè)接口具有分頁(yè)功能,我們使用RxCache給他設(shè)置了3分鐘的緩存,如果這兩個(gè)對(duì)象都不傳入?yún)?shù)中,它會(huì)默認(rèn)使用這個(gè)接口的方法名去存儲(chǔ)和獲取緩存,意思是我們之前使用這個(gè)接口獲取到了***頁(yè)的數(shù)據(jù),三分鐘以內(nèi)多次調(diào)用這個(gè)接口,請(qǐng)求其他分頁(yè)的數(shù)據(jù),它返回的緩存還是***頁(yè)的數(shù)據(jù),直到緩存過(guò)期,所以我們現(xiàn)在想具備分頁(yè)功能,必須傳入DynamicKey,DynamicKey內(nèi)部存儲(chǔ)有一個(gè)key,我們?cè)跇?gòu)建的時(shí)候傳入頁(yè)數(shù),RxCache將會(huì)根據(jù)不同的頁(yè)數(shù)分別保存一份緩存,它內(nèi)部做的事就是將方法名+DynamicKey變成一個(gè)String類型的標(biāo)識(shí)符去獲取和存儲(chǔ)緩存.
DynamicKey和DynamicKeyGroup有什么關(guān)系呢?
DynamicKey存儲(chǔ)有一個(gè)Key,DynamicKey的應(yīng)用場(chǎng)景: 請(qǐng)求同一個(gè)接口,需要參照一個(gè)變量的不同返回不同的數(shù)據(jù),比如分頁(yè),構(gòu)造時(shí)傳入頁(yè)數(shù)就可以了.
DynamicKeyGroup存儲(chǔ)有兩個(gè)key,DynamicKeyGroup是在DynamicKey基礎(chǔ)上的加強(qiáng)版,應(yīng)用場(chǎng)景:請(qǐng)求同一個(gè)接口不僅需要分頁(yè),每頁(yè)又需要根據(jù)不同的登錄人返回不同的數(shù)據(jù),這時(shí)候構(gòu)造DynamicKeyGroup時(shí),在構(gòu)造函數(shù)中***個(gè)參數(shù)傳頁(yè)數(shù),第二個(gè)參數(shù)傳用戶標(biāo)識(shí)符就可以了.
理論上DynamicKey和DynamicKeyGroup根據(jù)不同的需求只用傳入其中一個(gè)即可,但是也可以兩個(gè)參數(shù)都傳,以上面的需求為例,兩個(gè)參數(shù)都傳的話,它會(huì)先取DynamicKey的Key(頁(yè)數(shù))然后再取DynamicKeyGroup的第二個(gè)Key(用戶標(biāo)識(shí)符),加上接口名組成標(biāo)識(shí)符,來(lái)獲取和存儲(chǔ)數(shù)據(jù),這樣就會(huì)忽略DynamicKeyGroup的***個(gè)Key(頁(yè)數(shù)).
EvictProvider & EvictDynamicKey & EvictDynamicKeyGroup
這三個(gè)對(duì)象內(nèi)部都保存有一個(gè)boolean類型的字段,其意思為是否驅(qū)逐(使用或刪除)緩存,RxCache在取到未過(guò)期的緩存時(shí),會(huì)根據(jù)這個(gè)boolean字段,考慮是否使用這個(gè)緩存,如果為true,就會(huì)重新通過(guò)Retrofit獲取新的數(shù)據(jù),如果為false就會(huì)使用這個(gè)緩存.
這三個(gè)對(duì)象有什么關(guān)系呢?
這三個(gè)對(duì)象是相互繼承關(guān)系,繼承關(guān)系為EvictProvider < EvictDynamicKey < EvictDynamicKeyGroup,這三個(gè)對(duì)象你只能傳其中的一個(gè),多傳一個(gè)都會(huì)報(bào)錯(cuò),按理說(shuō)你不管傳那個(gè)對(duì)象都一樣,因?yàn)槔锩娑急4嬗幸粋€(gè)boolean字段,根據(jù)這個(gè)字段判斷是否使用緩存.
不同在哪呢?
如果有未過(guò)期的緩存,并且里面的boolean為false時(shí),你傳這三個(gè)中的哪一個(gè)都是一樣的,但是在boolean為true時(shí),這時(shí)就有區(qū)別了,RxCache會(huì)在Retrofit請(qǐng)求到新數(shù)據(jù)后,在boolean為true時(shí)刪除對(duì)應(yīng)的緩存.
刪除規(guī)則是什么呢?
還是以請(qǐng)求一個(gè)接口,該接口的數(shù)據(jù)會(huì)根據(jù)不同的分頁(yè)返回不同的數(shù)據(jù),并且同一個(gè)分頁(yè)還要根據(jù)不同用戶顯示不同的數(shù)據(jù)為例
三個(gè)都不傳,RxCache會(huì)自己new EvictProvider(false);,這樣默認(rèn)為false就不會(huì)刪除任何緩存
EvictDynamicKeyGroup 只會(huì)刪除對(duì)應(yīng)分頁(yè)下,對(duì)應(yīng)用戶的緩存.
EvictDynamicKey 會(huì)刪除那個(gè)分頁(yè)下的所有緩存,比如你請(qǐng)求的是***頁(yè)下user1的數(shù)據(jù),它不僅會(huì)刪除user1的數(shù)據(jù)還會(huì)刪除當(dāng)前分頁(yè)下其他user2,user3...的數(shù)據(jù).
EvictProvider 會(huì)刪除當(dāng)前接口下的所有緩存,比如你請(qǐng)求的是***頁(yè)的數(shù)據(jù),它不僅會(huì)刪除***頁(yè)的數(shù)據(jù),還會(huì)把這個(gè)接口下其他分頁(yè)的數(shù)據(jù)全刪除.
所以你可以根據(jù)自己的邏輯選擇傳那個(gè)對(duì)象,如果請(qǐng)求的這個(gè)接口沒(méi)有分頁(yè)功能,這時(shí)你不想使用緩存,按理說(shuō)你應(yīng)該傳EvictProvider,并且在構(gòu)造時(shí)傳入true,但是你如果傳EvictDynamicKey和EvictDynamicKeyGroup達(dá)到的效果也是一樣.
注解
@LifeCache
@LifeCache顧名思義,則是用來(lái)定義緩存的生命周期,當(dāng)Retrofit獲取到***的數(shù)據(jù)時(shí),會(huì)將數(shù)據(jù)及數(shù)據(jù)的配置信息封裝成Record,在本地和內(nèi)存中各保存一份,Record中則保存了@LifeCache的值(毫秒)和當(dāng)前數(shù)據(jù)請(qǐng)求成功的時(shí)間(毫秒)timeAtWhichWasPersisted.
以后每次取緩存時(shí),都會(huì)判斷timeAtWhichWasPersisted+@LifeCache的值是否小于當(dāng)前時(shí)間(毫秒),小于則過(guò)期,則會(huì)立即清理當(dāng)前緩存,并使用Retrofit重新請(qǐng)求***的數(shù)據(jù),如果EvictProvider為true不管緩存是否過(guò)期都不會(huì)使用緩存.
@EncryptKey & @Encrypt
這兩個(gè)注解的作用都是用來(lái)給緩存加密,區(qū)別在于作用域不一樣
@EncryptKey是作用在接口上
@EncryptKey("123")public interface CacheProviders { }
而@Encrypt是作用在方法上
@EncryptKey("123")public interface CacheProviders { @Encrypt Observable<Reply<User>> getCurrentUser(Observable<User> oUser, EvictProvider evictProvider); } }
如果需要給某個(gè)接口的緩存做加密的操作,則在對(duì)應(yīng)的方法上加上@Encrypt,在存儲(chǔ)和獲取緩存時(shí),RxCache就會(huì)使用@EncryptKey的值作為Key給緩存數(shù)據(jù)進(jìn)行加解密,因此每個(gè)Interface中的所有的方法都只能使用相同的Key.
值得注意的時(shí),RxCache只會(huì)給本地緩存進(jìn)行加密操作,并不會(huì)給內(nèi)存緩存進(jìn)行加密,給本地?cái)?shù)據(jù)加密使用的是Java自帶的CipherInputStream,解密使用的是CipherOutputStream
@Expirable
還記得我們?cè)跇?gòu)建RxCache時(shí),有一個(gè)setMaxMBPersistenceCache方法,這個(gè)可以設(shè)置,本地緩存的***容量,單位為MB,如果沒(méi)設(shè)置則默認(rèn)為100MB.
這個(gè)***容量和@Expirable又有什么關(guān)系呢?
當(dāng)然有!還記得我之前說(shuō)過(guò)在每次Retrofit重新獲取***數(shù)據(jù)時(shí),返回?cái)?shù)據(jù)前會(huì)將***數(shù)據(jù)在內(nèi)存緩存和本地緩存中各存一份.
存儲(chǔ)完畢后,會(huì)檢查現(xiàn)在的本地緩存大小,如果現(xiàn)在本地緩存中存儲(chǔ)的所有緩存大小加起來(lái)大于或者等于setMaxMBPersistenceCache中設(shè)置的大小(默認(rèn)為100MB)的百分之95,RxCache就會(huì)做一些操作,將總的緩存大小控制在百分之70以下.
做的什么操作?
很簡(jiǎn)單,RxCache會(huì)遍歷,構(gòu)建RxCache時(shí)傳入的cacheDirectory中的所有緩存數(shù)據(jù),一個(gè)個(gè)刪除直到總大小小于百分70,遍歷的順序不能保證,所以搞不好對(duì)你特別重要的緩存就被刪除了,這時(shí)@Expirable就派上用場(chǎng)了,在方法上使用它并且給它設(shè)置為false(如果沒(méi)使用這個(gè)注解,則默認(rèn)為true),就可以保證這個(gè)接口的緩存數(shù)據(jù),在每次需要清理時(shí)都幸免于難.
@Expirable(false) Observable<Reply<User>> getCurrentUser(Observable<User> oUser, EvictProvider evictProvider);
值得注意的是: 構(gòu)建RxCache時(shí)persistence方法傳入的cacheDirectory,是用來(lái)存放RxCache本地緩存的文件夾,這個(gè)文件夾里***不要有除RxCache之外的任何數(shù)據(jù),這樣會(huì)在每次需要遍歷清理緩存時(shí),節(jié)省不必要的開(kāi)銷,因?yàn)镽xCache并沒(méi)檢查文件名,不管是不是自己的緩存,他都會(huì)去遍歷獲取
@SchemeMigration & @Migration
這兩個(gè)注解是用來(lái)數(shù)據(jù)遷移的,用法:
@SchemeMigration({ @Migration(version = 1, evictClasses = {Mock.class}), @Migration(version = 2, evictClasses = {Mock2.class}) }) interface Providers {}
什么叫數(shù)據(jù)遷移呢?
簡(jiǎn)單的說(shuō)就是在***的版本中某個(gè)接口返回值類型內(nèi)部發(fā)生了改變,從而獲取數(shù)據(jù)的方式發(fā)生了改變,但是存儲(chǔ)在本地的數(shù)據(jù),是未改變的版本,這樣在反序列化時(shí)就可能發(fā)生錯(cuò)誤,為了規(guī)避這個(gè)風(fēng)險(xiǎn),作者就加入了數(shù)據(jù)遷移的功能.
有什么應(yīng)用場(chǎng)景呢?
可能上面的話,不是很好理解,舉個(gè)非常簡(jiǎn)單的例子:
public class Mock{ private int id; }
Mock里面有一個(gè)字段id,現(xiàn)在是一個(gè)整型int,能滿足我們現(xiàn)在的需求,但是隨著產(chǎn)品的迭代,發(fā)現(xiàn)int不夠用了
public class Mock{ private long id; }
為了滿足現(xiàn)在的需求,我們使用long代替int,由于緩存中的Mock還是之前未改變的版本,并且未過(guò)期,在使用本地緩存時(shí)會(huì)將數(shù)據(jù)反序列化,將int變?yōu)閘ong,就會(huì)出現(xiàn)問(wèn)題.
數(shù)據(jù)遷移是怎么解決上面的問(wèn)題呢?
其實(shí)非常簡(jiǎn)單,就是使用注解聲明,之前有緩存并且內(nèi)部修改過(guò)的class,RxCache會(huì)把含有這些class的緩存全部清除掉.
RxCache是怎么操作的呢?
值得一提的是,在每次創(chuàng)建接口的動(dòng)態(tài)代理時(shí),也就是在每次調(diào)用RxCache.using(CacheProviders.class)時(shí),會(huì)執(zhí)行兩個(gè)操作,清理含有@Migration中聲明的evictClasses的緩存,以及遍歷本地緩存文件夾清理所有已經(jīng)過(guò)期的緩存.
每次清理完需要數(shù)據(jù)遷移的緩存時(shí),會(huì)將version值***的@Migration的version值保存到本地.
@SchemeMigration({ @Migration(version = 1, evictClasses = {Mock.class}), @Migration(version = 3, evictClasses = {Mock3.class}), @Migration(version = 2, evictClasses = {Mock2.class}) }) interface Providers {}
如上面的聲明方式,它會(huì)將3保存到本地,每次調(diào)用using(),開(kāi)始數(shù)據(jù)遷移時(shí)會(huì)將上次保存的version值從本地取出來(lái),會(huì)在@SchemeMigration中查找大于這個(gè)version值的@Migration,取出里面evictClasses,去重后,遍歷所有本地緩存,只要緩存數(shù)據(jù)中含有你聲明的class,就將這個(gè)緩存清除.
比如evictClasses中聲明了Mock.class,會(huì)把以O(shè)bservable< List< Mock >>,Observable< Map< String,Mock > >,Observable < Mock[] >或者Observable< Mock >作為返回值的接口緩存全部清理掉,然后在將***version值記錄到本地.
所以每次有需要數(shù)據(jù)遷移的類時(shí),必須在@SchemeMigration中添加新的@Migration,并且注解中version的值必須+1,這樣才會(huì)達(dá)到數(shù)據(jù)遷移的效果.
@SchemeMigration({ @Migration(version = 1, evictClasses = {Mock.class}), @Migration(version = 3, evictClasses = {Mock3.class}), @Migration(version = 2, evictClasses = {Mock2.class}), @Migration(version = 4, evictClasses = {Mock2.class}) }) interface Providers {}
如在上面的基礎(chǔ)上,Mock2內(nèi)部又發(fā)生改變,又需要數(shù)據(jù)遷移,就要新添加個(gè)@Migration,version = 4(3+1),這時(shí)在調(diào)用using()時(shí)只會(huì)將version = 4的@Migration中evictClasses聲明的class進(jìn)行數(shù)據(jù)遷移(即清理含有這個(gè)class的緩存數(shù)據(jù)).
@Actionable
這個(gè)注解在官方介紹中說(shuō)明了會(huì)使用注解處理器給使用了這個(gè)注解的Interface,自動(dòng)生成一個(gè)相同類名以Actionable結(jié)尾的類文件,使用這個(gè)類的APi方便更好的執(zhí)行寫操作,沒(méi)使用過(guò),不做過(guò)多介紹.
在使用中發(fā)現(xiàn)了一個(gè)問(wèn)題,如果使用BaseResponse< T >,包裹數(shù)據(jù)的時(shí)候會(huì)出現(xiàn)錯(cuò)誤,如issue#41和issue#73.
分析問(wèn)題
上面說(shuō)了RxCache會(huì)將Retrofit返回的數(shù)據(jù)封裝到Record對(duì)象里,Record會(huì)判斷這個(gè)數(shù)據(jù)是那種類型,會(huì)先判斷這個(gè)數(shù)據(jù)是否是Collection(List的父類),數(shù)組還是Map,如果都不是他會(huì)默認(rèn)這個(gè)數(shù)據(jù)就是普通的對(duì)象.
Record里有三個(gè)字段分別儲(chǔ)存這個(gè)數(shù)據(jù)的,容器類名,容器里值的類名,和Map的Key類名,意思為如果數(shù)據(jù)類型為L(zhǎng)ist< String >,容器類名為L(zhǎng)ist,值類名為String,Key類名為空,如果數(shù)據(jù)類型為Map< String,Integer >,容器類名為Map,值類名為Integer,key類名為String.
這三個(gè)字段的作用就是,在取本地緩存時(shí)可以使用Gson根據(jù)字段類型恢復(fù)真實(shí)數(shù)據(jù)的類型,問(wèn)題就在這,因?yàn)槭褂玫氖荁aseResponse< T >包裹數(shù)據(jù),在上面的判斷里,他排除了這個(gè)數(shù)據(jù)是List,數(shù)組或Map后它只會(huì)認(rèn)定這個(gè)數(shù)據(jù)是普通的對(duì)象,這時(shí)他只會(huì)把三個(gè)字段里中值類名保存為BaseResponse其他則為空,范型的類型它并沒(méi)通過(guò)字段記錄,所以它在取的時(shí)候自然不會(huì)正確返回T的類型.
解決問(wèn)題
知道問(wèn)題所在后,我們現(xiàn)在就來(lái)解決問(wèn)題,解決這個(gè)問(wèn)題現(xiàn)在有兩個(gè)方向,一個(gè)是內(nèi)部解決,一個(gè)是外部解決,外部解決的方式就可以通過(guò)上面issue#73所提到的方式.
所謂內(nèi)部解決就要改這個(gè)框架的內(nèi)部代碼了,問(wèn)題就出在Record在數(shù)據(jù)為普通對(duì)象的時(shí)候,他不會(huì)使用字段保存范型的類型名,所以在取本地緩存的時(shí)候就無(wú)法正確恢復(fù)數(shù)據(jù)類型
解決的思路就是我們必須對(duì)數(shù)據(jù)為普通對(duì)象的時(shí)候做特殊處理,最簡(jiǎn)單的方式就是如果數(shù)據(jù)為對(duì)象時(shí)我們?cè)倥袛鄆nstanceof BaseResponse,如果為true我們就重復(fù)做上面的判斷.
即判斷BaseResponse中,T的類型是否為L(zhǎng)ist,數(shù)組,Map還是對(duì)象?
然后在用對(duì)應(yīng)的字段保存對(duì)應(yīng)的類型名,取本地緩存的時(shí)候就可以用Gson按這些字段恢復(fù)正確的數(shù)據(jù)類型,但是這樣強(qiáng)制的判斷instanceof對(duì)于一個(gè)框架來(lái)說(shuō)靈活性和擴(kuò)展性會(huì)大打折扣,所以我后面寫源碼分析的時(shí)候會(huì)認(rèn)真考慮下這個(gè)問(wèn)題,可以的話我會(huì)Pull Request給Rxcache.
關(guān)于Retrofit緩存庫(kù)RxCache怎么理解問(wèn)題的解答就分享到這里了,希望以上內(nèi)容可以對(duì)大家有一定的幫助,如果你還有很多疑惑沒(méi)有解開(kāi),可以關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道了解更多相關(guān)知識(shí)。
分享文章:Retrofit緩存庫(kù)RxCache怎么理解
當(dāng)前網(wǎng)址:http://jinyejixie.com/article20/igogco.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供面包屑導(dǎo)航、網(wǎng)站改版、Google、外貿(mào)網(wǎng)站建設(shè)、自適應(yīng)網(wǎng)站、定制網(wǎng)站
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來(lái)源: 創(chuàng)新互聯(lián)