簡介
提供Android緩存功能,包括對SD卡,內(nèi)存、Sharedpreference以及同時(shí)存儲(chǔ)SD卡和內(nèi)存的雙層緩存操作,緩存對象包括:實(shí)現(xiàn)序列化的對象,Bitmap以及字符數(shù)組。下載項(xiàng)目https://github.com/homeven/RxCache。
1.使用
導(dǎo)入項(xiàng)目依賴
implementation "io.reactivex:rxandroid:1.2.1"
implementation "io.reactivex:rxjava:1.1.6"
在調(diào)用緩存API之前需要初始化緩存配置,推薦在Application當(dāng)中進(jìn)行初始化.
//初始化緩存配置,包括磁盤緩存路徑,緩存大小,內(nèi)存緩存大小,加密策略等。
// 最后調(diào)用.install(this)方法完成初始化
CacheInstaller.get()
.configDiskCache("TestCache", 50 * 1024 * 1024, 1)
.install(this);
完成初始化之后就可以正常使用緩存操作了。
存儲(chǔ)
項(xiàng)目本身一共兩種緩存的調(diào)用方式:
- 直接在項(xiàng)目當(dāng)中進(jìn)行鏈?zhǔn)降恼{(diào)用。
- 一種是類似于retrofit的接口調(diào)用方式。
存儲(chǔ)的對象可以是實(shí)現(xiàn)序列化的對象,Bitmap以及字符數(shù)組。以緩存bitmap為例,看一下調(diào)用實(shí)例:
調(diào)用方式一
/**
* 定義接口
*/
public interface TestInerface {
//注解標(biāo)明請求方式,超時(shí)時(shí)間等等
//method設(shè)置當(dāng)前操作為put,調(diào)用緩存到SD卡以及內(nèi)存當(dāng)中的雙層緩存
@Method(methodType = MethodType.PUT,cacheType = CacheType.TWO_LAYER)
//設(shè)置過期時(shí)間為1天
@Lifecycle(time = 1,unit = TimeUnit.DAYS)
<T> Observable<Boolean> putData( @CacheKey String key,@CacheValue T value, @CacheClass Class<T> clazz);
}
//調(diào)用緩存存儲(chǔ)bitmap
TestInerface testInerface = RetrofitCache.create(TestInerface.class);
testInerface.putData("testKey", bitmap, Bitmap.class).observeOn(AndroidSchedulers.mainThread())
.subscribe(new Action1<Boolean>() {
@Override
public void call(Boolean aBoolean) {
Toast.makeText(TestActivity.this, aBoolean + "", Toast.LENGTH_SHORT).show();
}
});
整個(gè)存儲(chǔ)過程可分為兩步:
- 定義接口,并通過注解標(biāo)明請求方式,請求參數(shù)等。
- 在項(xiàng)目中調(diào)用緩存API。
整個(gè)API的調(diào)用過程與Retrofit很相似,在定義接口時(shí)的注解說明如下:
| 注解 | 類型 | 說明 |
|---|---|---|
| @Lifecycle | 方法注解 | 設(shè)置過期時(shí)間,包括時(shí)長和單位,存儲(chǔ)時(shí)調(diào)用 |
| @Method | 方法注解 | 設(shè)置緩存方法以及存儲(chǔ)方式 |
| @ShareName | 方法注解 | sharedPreference緩存時(shí)的文件名 |
| @Strategy | 方法注解 | 設(shè)置超時(shí)策略,讀取緩存時(shí)調(diào)用 |
| @CacheClass | 參數(shù)注解 | 設(shè)置緩存類,標(biāo)注一個(gè)Class對象 |
| @CacheKey | 參數(shù)注解 | 設(shè)置緩存的key值,標(biāo)注一個(gè)String對象 |
| @CacheValue | 參數(shù)注解 | 設(shè)置緩存內(nèi)容 |
調(diào)用方式二
直接通過鏈?zhǔn)秸{(diào)用
//調(diào)用put方法存儲(chǔ)數(shù)據(jù)
RxCache.get().setTimeout(1, TimeUnit.DAYS)
.putData2TwoLayer("diskKey", bitmap).observeOn(AndroidSchedulers.mainThread())
.subscribe(new Action1<Boolean>() {
@Override
public void call(Boolean aBoolean) {
Toast.makeText(TestActivity.this, aBoolean + "", Toast.LENGTH_SHORT).show();
}
});
//setTimeout方法設(shè)置超時(shí)時(shí)間
//putData2TwoLayer調(diào)用雙層緩存,參數(shù)為緩存的key值以及緩存內(nèi)容
調(diào)用存儲(chǔ)方法putXX后返回一個(gè)Observable<Boolean>對象,當(dāng)返回true時(shí)代表緩存成功,返回false代表緩存失敗。
兩種方法各有利弊
- 方式一方便對緩存的管理,并省去在項(xiàng)目中對緩存策略等的配置內(nèi)容。
- 方式二調(diào)用方式更直接,代碼也相對更少一些。
注意:無論哪種調(diào)用方式,都需要先初始化配置信息。
讀取
讀取方式和存儲(chǔ)類似,也分為兩種,詳細(xì)調(diào)用內(nèi)容不再贅述,直接看代碼。
//----------------------方式一------------------------------
//定義接口
public interface TestInerface {
//注解標(biāo)明請求方式,超時(shí)策略等等
//請求方式為get,讀取對象為從SD卡中讀取
@Method(methodType = MethodType.GET,cacheType = CacheType.DISK)
//設(shè)置超時(shí)策略,當(dāng)數(shù)據(jù)超時(shí)時(shí)返回null
@Strategy(key = ExpirationPolicies.ReturnNull)
<T> Observable<T> getData(@CacheKey String key, @CacheClass Class<T> clazz);
}
testInerface.getData("testKey",Bitmap.class).observeOn(AndroidSchedulers.mainThread())
.subscribe(new Action1<Bitmap>() {
@Override
public void call(Bitmap s) {
if (s != null) {
testImage.setImageBitmap(s);
} else {
Toast.makeText(TestActivity.this, "數(shù)據(jù)為null", Toast.LENGTH_SHORT).show();
}
}
});
//----------------------方式二------------------------------
RxCache.get().getDataTwoLayer("diskKey", Bitmap.class).observeOn(AndroidSchedulers.mainThread())
.subscribe(new Action1<Bitmap>() {
@Override
public void call(Bitmap s) {
if (s != null) {
testImage.setImageBitmap(s);
} else {
Toast.makeText(TestActivity.this, "數(shù)據(jù)為null", Toast.LENGTH_SHORT).show();
}
}
});
讀取緩存會(huì)返回一個(gè)Observable對象,通過subscribe()訂閱后可以拿到返回的數(shù)據(jù),并進(jìn)行操作。
注意:默認(rèn)執(zhí)行subscribe()的線程為調(diào)用時(shí)所在線程,如果需要修改線程,需自行調(diào)用observeOn()方法修改調(diào)用線程。
另外還有刪除和清空緩存等API,調(diào)用方式與存儲(chǔ)、讀取類似,省略這部分內(nèi)容,感興趣的可以自己下載試一下。https://github.com/bh4614910/RxCache
2.架構(gòu)設(shè)計(jì)
說完對整個(gè)API的使用,再來詳細(xì)看一下整個(gè)緩存的項(xiàng)目結(jié)構(gòu)。

整個(gè)項(xiàng)目可以大體分為三層
- 基礎(chǔ)層:主要負(fù)責(zé)存儲(chǔ)的基礎(chǔ)操作,包括對
SD卡、內(nèi)存以SharedPreference的基礎(chǔ)操作。 - 控制層:負(fù)責(zé)根據(jù)對不同的事務(wù)類型進(jìn)行分發(fā)。
- API:對外暴露的API,目前提供兩種API調(diào)用方式。
3.基礎(chǔ)層實(shí)現(xiàn)
基礎(chǔ)操作分為三種:sharedPreference、memory以及disk。對于三種存儲(chǔ)方式,提供統(tǒng)一的供上層調(diào)用的API接口CacheWrapper。
/**
* 緩存控制類接口
*/
public interface CacheWrapper {
/**
* 讀取緩存類
*
* @param <T> 緩存值類型,需要實(shí)現(xiàn)Parcelable接口
* @param key 緩存的key值
* @return 返回CacheResult<T>類型
*/
<T> CacheResource<T> get(String key, Class<T> clazz);
/**
* 存儲(chǔ)緩存類
*
* @param key 緩存的key值
* @param value 緩存值
* @param <T> 緩存值類型,需要實(shí)現(xiàn)Parcelable接口
* @return 返回true或者false表示緩存是否成功
*/
<T> boolean put(String key, CacheResource<T> value);
/**
* 清空緩存
*/
void clear();
/**
* 刪除某個(gè)值
*
* @param key 需要?jiǎng)h除的緩存值對應(yīng)key
* @return 返回true或者false表示刪除是否成功
*/
boolean remove(String key);
/**
* 構(gòu)造用工廠接口
*/
interface Factory {
}
interface Factory2 {
CacheWrapper create(Context context, CacheType type, String shareName);
}
}
各個(gè)存儲(chǔ)方法再各自實(shí)現(xiàn)對應(yīng)的存儲(chǔ)內(nèi)容。
sharedPreference是我們在項(xiàng)目當(dāng)中經(jīng)常用到的,為了讓它也滿足上層API的調(diào)用,我們對它的基礎(chǔ)操作進(jìn)行封裝PreferenceProvider,之后再對接口進(jìn)行具體實(shí)現(xiàn)DiskCacheWrapper。
memory也就是我們的內(nèi)存緩存,我們選用LruCache作為基礎(chǔ)操作類型,LruCache的核心思想就是要維護(hù)一個(gè)緩存對象列表,其中對象列表的排列方式是按照訪問順序?qū)崿F(xiàn)的,即一直沒訪問的對象,將放在隊(duì)尾,即將被淘汰。而最近訪問的對象將放在隊(duì)頭,最后被淘汰。有興趣的可以去了解一下LruCache的具體實(shí)現(xiàn)。
使用時(shí)我們先初始化LruCache并重寫sizeOf方法,計(jì)算存儲(chǔ)數(shù)據(jù)的大小,這里我提供了一個(gè)SizeUtil方便大小的計(jì)算,之后的調(diào)用方式非常簡單,直接看代碼
/**
* 內(nèi)存緩存控制類
*/
public class MemoryCacheWrapper implements CacheWrapper {
private LruCache<String, Object> memoryCache;
private static final int DEFAULT_MEMORY_CACHE_SIZE = (int) (Runtime.getRuntime().maxMemory() / 8);
public static MemoryCacheWrapper get(){
return MemoryCacheHolder.mInstance;
}
private MemoryCacheWrapper() {
memoryCache = new LruCache<String, Object>(getCacheSize()) {
@Override
protected int sizeOf(String key, Object value) {
if (Bitmap.class.isAssignableFrom(value.getClass())) {
return (int)SizeUtil.getBitmapSize((Bitmap) value);
} else {
return (int) SizeUtil.getValueSize(value);
}
}
};
}
/**
* 獲取緩存大小
*
* @return
*/
private int getCacheSize() {
int cacheSize = CacheInstaller.get().getMemorySize();
if (cacheSize <= 0) {
cacheSize = DEFAULT_MEMORY_CACHE_SIZE;
}
return cacheSize;
}
@Override
public <T> CacheResource<T> get(String key, Class<T> clazz) {
CacheResource<T> value = (CacheResource<T>) memoryCache.get(key);
if (value != null) {
return value;
}
return null;
}
@Override
public <T> boolean put(String key, CacheResource<T> value) {
if (value != null && memoryCache.get(key) == null) {
memoryCache.put(key, value);
return true;
} else {
LogUtil.log("value值為空或key值以及存在");
}
return false;
}
@Override
public void clear() {
memoryCache.evictAll();
}
@Override
public boolean remove(String key) {
Object object = memoryCache.remove(key);
if (object == null) {
return false;
} else {
return true;
}
}
private static class MemoryCacheHolder {
public static MemoryCacheWrapper mInstance = new MemoryCacheWrapper();
private MemoryCacheHolder() {
}
}
}
有些緩存模塊沒有使用LruCache,而是使用HashMap作為存儲(chǔ)結(jié)構(gòu),兩種方案都是可行的,這里使用LruCache主要是為了方便圖片的存儲(chǔ)。
細(xì)心的朋友會(huì)發(fā)現(xiàn)這里put的參數(shù)和get返回的數(shù)據(jù)都是CacheResource類型,我們把存儲(chǔ)的數(shù)據(jù),以及超時(shí)時(shí)間等統(tǒng)一的存儲(chǔ)進(jìn)這個(gè)數(shù)據(jù)結(jié)構(gòu),也就是說CacheResource作為控制層和基礎(chǔ)層傳遞的介質(zhì)。
之后就是disk也就是SD卡的存儲(chǔ)。這一部分使用DiskLruCache作為基礎(chǔ)操作類型,和sharedPreference一樣,首先我們對DiskLruCache的操作進(jìn)行封裝,以統(tǒng)一對上層調(diào)用的API。
/**
* Created by liubohua on 2018/7/24.
* 提供本地緩存基礎(chǔ)操作。
*/
public class DiskCacheProvider {
private DiskLruCache diskLruCache;
private Converter objectConverter;
private Converter bitmapConverter;
private Converter byteArrayConverter;
public DiskCacheProvider(File directory, int appVersion, long maxSize) {
objectConverter = new ObjectConverter();
bitmapConverter = new BitmapConverter();
byteArrayConverter = new ByteArrayConverter();
try {
diskLruCache = DiskLruCache.open(directory, appVersion, 1, maxSize);
} catch (IOException e) {
e.printStackTrace();
}
}
public CacheResource<Bitmap> getBitmap(String key) {
DiskLruCache.Snapshot snapShot = null;
try {
snapShot = diskLruCache.get(key);
if (snapShot != null) {
InputStream is = snapShot.getInputStream(0);
CacheResource<Bitmap> value = null;
value = bitmapConverter.read(is);
if (value != null) {
return value;
}
}
} catch (IOException e) {
e.printStackTrace();
} finally {
snapShot.close();
}
return null;
}
public CacheResource<Object> getObject(String key) {
DiskLruCache.Snapshot snapShot = null;
try {
snapShot = diskLruCache.get(key);
if (snapShot != null) {
InputStream is = snapShot.getInputStream(0);
CacheResource<Object> value = null;
value = objectConverter.read(is);
if (value != null) {
return value;
}
}
} catch (IOException e) {
e.printStackTrace();
} finally {
if(snapShot!=null){
snapShot.close();
}
}
return null;
}
public CacheResource<byte[]> getBytes(String key) {
DiskLruCache.Snapshot snapShot = null;
try {
snapShot = diskLruCache.get(key);
if (snapShot != null) {
InputStream is = snapShot.getInputStream(0);
CacheResource<byte[]> value = null;
value = byteArrayConverter.read(is);
if (value != null) {
return value;
}
}
} catch (IOException e) {
e.printStackTrace();
} finally {
if (snapShot != null) {
snapShot.close();
}
}
return null;
}
public boolean putObject(String key, CacheResource<Object> value) {
try {
DiskLruCache.Editor editor = diskLruCache.edit(key);
OutputStream outputStream = editor.newOutputStream(0);
boolean result = false;
result = objectConverter.write(value, outputStream);
if (result) {
editor.commit();
} else {
editor.abort();
}
return result;
} catch (IOException e) {
LogUtil.error("存儲(chǔ)報(bào)錯(cuò)", e);
}
return false;
}
public boolean putBitmap(String key, CacheResource<Bitmap> value) {
try {
DiskLruCache.Editor editor = diskLruCache.edit(key);
OutputStream outputStream = editor.newOutputStream(0);
boolean result = false;
result = bitmapConverter.write(value, outputStream);
if (result) {
editor.commit();
} else {
editor.abort();
}
return result;
} catch (IOException e) {
LogUtil.error("存儲(chǔ)報(bào)錯(cuò)", e);
}
return false;
}
public boolean putBytes(String key, CacheResource<byte[]> value) {
try {
DiskLruCache.Editor editor = diskLruCache.edit(key);
OutputStream outputStream = editor.newOutputStream(0);
boolean result = false;
result = byteArrayConverter.write(value, outputStream);
if (result) {
editor.commit();
} else {
editor.abort();
}
return result;
} catch (IOException e) {
LogUtil.error("存儲(chǔ)報(bào)錯(cuò)", e);
}
return false;
}
public boolean remove(String key) {
try {
return diskLruCache.remove(key);
} catch (IOException e) {
e.printStackTrace();
}
return false;
}
public void clear() {
try {
diskLruCache.delete();
} catch (IOException e) {
e.printStackTrace();
}
}
}
在這個(gè)類當(dāng)中除了對DiskLruCache的封裝外,還有三個(gè)轉(zhuǎn)換器ObjectConverter、BitmapConverter、ByteArrayConverter分別用于將三種存儲(chǔ)的數(shù)據(jù)類型轉(zhuǎn)換成對應(yīng)的流進(jìn)行存儲(chǔ)。以ObjectConverter為例,我們看一下這部分代碼。
/**
* 類與流的轉(zhuǎn)換器,需要實(shí)現(xiàn)序列化的對象
*/
public class ObjectConverter extends Converter<Object> {
public boolean write(CacheResource<Object> value, OutputStream outputStream) {
ObjectOutputStream oos = null;
try {
oos = new ObjectOutputStream(outputStream);
writeHeader(outputStream,value);
oos.writeObject(value.getData());
oos.flush();
return true;
} catch (IOException e) {
LogUtil.error("ObjectConverter數(shù)據(jù)解析出錯(cuò)", e);
} finally {
try {
oos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
return false;
}
public CacheResource<Object> read(InputStream inputStream) {
ObjectInputStream ois = null;
CacheResource<Object> cacheObject = new CacheResource<>();
try {
ois = new ObjectInputStream(inputStream);
readHeader(inputStream,cacheObject);
cacheObject.setData(ois.readObject());
return cacheObject;
} catch (IOException e) {
LogUtil.error("ObjectConverter數(shù)據(jù)解析出錯(cuò)", e);
} catch (ClassNotFoundException e) {
LogUtil.error("ObjectConverter數(shù)據(jù)解析出錯(cuò)", e);
} finally {
try {
ois.close();
} catch (IOException e) {
e.printStackTrace();
}
}
return null;
}
}
這個(gè)類繼承自Converter方法,這個(gè)類提供了readHeader(inputStream,cacheObject)和writeHeader(outputStream,value)方法,以魔法數(shù)字的形式存儲(chǔ)超時(shí)時(shí)間等除存儲(chǔ)內(nèi)容之外的數(shù)據(jù)。
之后把DiskCacheProvider封裝為DiskCacheWrapper供控制層調(diào)用。
4.控制層
控制層的工作主要有
- 根據(jù)不同的操作類型分發(fā)事務(wù)。
- 對超時(shí)時(shí)間加以判斷,觸發(fā)超時(shí)策略。
- 對
CacheResource的封裝和解析。 - 對
key值進(jìn)行加密
/**
* Cache管理類
*/
public class CacheManager {
private CacheWrapper wrapper;
private Encrypt encrypt;
public CacheManager(CacheWrapper wrapper, Encrypt encrypt) {
this.wrapper = wrapper;
this.encrypt = encrypt;
}
/**
* 獲取緩存內(nèi)容
*
*/
public <T> Observable<T> get(final String key, final CacheType type, final Class<T> clazz, final ExpirationPolicies policies) {
Observable<T> observable = Observable.create(new Observable.OnSubscribe<CacheResource<T>>() {
@Override
public void call(Subscriber<? super CacheResource<T>> subscriber) {
String cacheKey = encrypt.getEncryptKey(key);
CacheResource<T> cacheResource = null;
if(wrapper!=null){
cacheResource = wrapper.get(cacheKey,clazz);
}
subscriber.onNext(cacheResource);
subscriber.onCompleted();
}
}).filter(new Func1<CacheResource<T>, Boolean>() {
@Override
public Boolean call(CacheResource<T> resource) {
if (resource != null) {
if (resource.isExpired()) {
if (policies == ExpirationPolicies.ReturnNull) {
resource.setData(null);
}
remove(key).subscribe();
}
}
return true;
}
}).map(new Func1<CacheResource<T>, T>() {
public T call(CacheResource<T> resource) {
if (resource != null) {
return resource.getData();
} else {
return null;
}
}
}).subscribeOn(Schedulers.io());
return observable;
}
/**
* 添加緩存
*/
public <T> Observable<Boolean> put(final String key, final T value, final long timeout, final TimeUnit unit) {
Observable<Boolean> observable = Observable.create(new Observable.OnSubscribe<Boolean>() {
@Override
public void call(Subscriber<? super Boolean> subscriber) {
String cacheKey = encrypt.getEncryptKey(key);
CacheResource<T> cacheResource = new CacheResource<>(value, System.currentTimeMillis(), timeout, unit);
boolean result = false;
if (wrapper != null) {
result = wrapper.put(cacheKey, cacheResource);
}
subscriber.onNext(result);
subscriber.onCompleted();
}
}).subscribeOn(Schedulers.io());
return observable;
}
/**
* 移除緩存內(nèi)容
*
*/
public Observable<Boolean> remove(final String key) {
Observable<Boolean> observable = Observable.create(new Observable.OnSubscribe<Boolean>() {
@Override
public void call(Subscriber<? super Boolean> subscriber) {
boolean result = false;
String cacheKey = encrypt.getEncryptKey(key);
if (wrapper != null) {
wrapper.remove(cacheKey);
}
subscriber.onNext(result);
subscriber.onCompleted();
}
}).subscribeOn(Schedulers.io());
return observable;
}
/**
* 清空緩存
*/
public void clear() {
if (wrapper != null) {
wrapper.clear();
}
}
public static class CacheWrapperFactory implements CacheWrapper.Factory2 {
@Override
public CacheWrapper create(Context context, CacheType type, String shareName) {
if (type == CacheType.DISK) {
return new DiskCacheWrapper();
} else if (type == CacheType.MEMORY) {
return MemoryCacheWrapper.get();
} else if (type == CacheType.SHARED) {
return new ShareCacheWrapper(context, shareName);
} else if (type == CacheType.TWO_LAYER) {
return new TwoLayerWrapper();
}
return null;
}
}
}
對外提供加密接口Encrypt,用戶可以實(shí)現(xiàn)這個(gè)接口并實(shí)現(xiàn)自己的加密方式,默認(rèn)使用MD5加密。
5.封裝api
封裝的API主要有三部分:
-
CacheInstaller緩存的配置類 -
RxCache對外提供的存取操作API -
RetrofitCache以Retrofit的形式調(diào)用API
CacheInstaller以單例的形式對外提供,在一個(gè)項(xiàng)目當(dāng)中,該類應(yīng)該之初始化一次,簡單看一下這部分代碼。
public class CacheInstaller {
private static final long MAX_DISK_CACHE_SIZE = 50 * 1024 * 1024; // 50MB
private static final int DEFAULT_VERSION = 1;
private static final String DEFAULT_PATH = "cache";
private String diskPath;
private int memorySize;
private long diskSize =0l;
private int diskVersion = -1;
private boolean isInstall = false;
private Context context;
private Encrypt encrypt;
private CacheInstaller() {
}
private static class SingleTon {
private static CacheInstaller INSTANCE = new CacheInstaller();
}
public static CacheInstaller get() {
return SingleTon.INSTANCE;
}
/**
* 配置磁盤緩存配置
*/
public CacheInstaller configDiskCache(String diskPath, long diskSize, int diskVersion) {
if (isInstall) {
return this;
}
this.diskPath = diskPath;
this.diskSize = diskSize;
this.diskVersion = diskVersion;
return this;
}
/**
* 配置內(nèi)存緩存配置
*
*/
public CacheInstaller configMemoryCache(int memorySize) {
if (isInstall) {
return this;
}
this.memorySize = memorySize;
return this;
}
/**
* 配置全局加密方式
*
*/
public CacheInstaller encryptFactory(Encrypt.Factory factory) {
if (isInstall) {
return this;
}
if(factory!=null){
encrypt = factory.create();
}
return this;
}
/**
* 完成裝填工作
*/
public void install(Context context) {
this.isInstall = true;
this.diskPath = getDirectory(context);
this.diskVersion = getVersion();
this.diskSize = getCacheSize(context);
this.encrypt = createEncrypt();
this.context = context.getApplicationContext();
}
/**
* 重置裝填狀態(tài)
* 慎用
*/
public void resume() {
this.isInstall = false;
}
}
RxCache的代碼只是對外提供API,沒有邏輯代碼。
RetrofitCache使用動(dòng)態(tài)代理的方式。
public static <T> T create(Class<T> clazz) {
RetrofitProxy proxy = new RetrofitProxy();
try {
return (T) Proxy.newProxyInstance(RetrofitCache.class.getClassLoader(), new Class[]{clazz}, proxy);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
public class RetrofitProxy implements InvocationHandler {
RxCache rxCache;
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
car.wuba.saas.cache.retrofit.annotation.Method method1 = method.getAnnotation(car.wuba.saas.cache.retrofit.annotation.Method.class);
Strategy strategy = method.getAnnotation(Strategy.class);
Lifecycle lifecycle = method.getAnnotation(Lifecycle.class);
ShareName shareName = method.getAnnotation(ShareName.class);
Class CacheClazz = null;
Object CacheValue = null;
String CacheKey = null;
Annotation[][] allParamsAnnotations = method.getParameterAnnotations();
//獲取key、value等注解對應(yīng)的參數(shù)
if (allParamsAnnotations != null) {
for (int i = 0; i < allParamsAnnotations.length; i++) {
Annotation[] paramAnnotations = allParamsAnnotations[I];
if (paramAnnotations != null) {
for (Annotation annotation : paramAnnotations) {
if (annotation instanceof CacheClass) {
CacheClazz = (Class) args[I];
}
if (annotation instanceof CacheKey) {
CacheKey = (String) args[I];
}
if (annotation instanceof CacheValue) {
CacheValue = args[I];
}
}
}
}
}
//初始化各項(xiàng)參數(shù)
if (method1 != null) {
MethodType methodKey = method1.methodType();
CacheType typeValue = method1.cacheType();
long time = 0;
TimeUnit unit = null;
if (lifecycle != null) {
time = lifecycle.time();
unit = lifecycle.unit();
}
ExpirationPolicies policies = ExpirationPolicies.ReturnNull;
if (strategy != null) {
policies = strategy.key();
}
String name = "";
if (shareName != null) {
name = shareName.name();
}
rxCache = RxCache.get();
if (methodKey == MethodType.PUT) {
return putMethod(typeValue, time, unit, CacheKey, CacheValue, name);
} else if (methodKey == MethodType.GET) {
return getMethod(typeValue, policies, CacheKey, CacheClazz, name);
} else if (methodKey == MethodType.REMOVE) {
return removeMethod(typeValue, CacheKey, name);
} else if (methodKey == MethodType.CLEAR) {
clearMethod(typeValue, name);
}
}
return null;
}
總結(jié)
緩存SDK參考了Glide以及okHttp等內(nèi)部的緩存形式,并結(jié)合我們當(dāng)前的項(xiàng)目結(jié)構(gòu)和需求進(jìn)行構(gòu)建,本人還是個(gè)新手,有什么問題還希望大神們多多指教。感興趣的小伙伴也可以自己下載,修改來試試。下載鏈接https://github.com/homeven/RxCache
作者:銀灬楓
鏈接:http://www.itdecent.cn/p/a16ee1ff4da1
來源:簡書
簡書著作權(quán)歸作者所有,任何形式的轉(zhuǎn)載都請聯(lián)系作者獲得授權(quán)并注明出處。