這是一個基於 Retrofit的Reactive緩存庫,可用於Android 和Java。可以將你的緩存成需求轉成一個接口java
添加JitPack倉庫在你的build.gradle文件 (項目根目錄下):react
allprojects { repositories { jcenter() maven { url "https://jitpack.io" } } }
添加依賴庫,在項目模塊中git
dependencies { compile "com.github.VictorAlbertos.RxCache:core:1.4.6" compile "io.reactivex:rxjava:1.1.5" }
定義一個接口CacheProvidergithub
public interface CacheProviders { //這裏設置緩存失效時間爲2分鐘。 @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); }
public interface RestApi { String URL_BASE = "https://api.github.com"; String HEADER_API_VERSION = "Accept: application/vnd.github.v3+json"; @Headers({HEADER_API_VERSION}) @GET("/users") Observable<List<User>> getUsers(@Query("since") int lastIdQueried, @Query("per_page") int perPage); @Headers({HEADER_API_VERSION}) @GET("/users/{username}/repos") Observable<List<Repo>> getRepos(@Path("username") String userName); @Headers({HEADER_API_VERSION}) @GET("/users/{username}") Observable<Response<User>> getUser(@Path("username") String username); }
將RestApi中須要緩存的接口方法在CacheProviders寫相應的方法,如:json
Observable<List<Repo>> getRepos(@Path("username") String userName);
對應api
Observable<Reply<List<Repo>>> getRepos(Observable<List<Repo>> oRepos, DynamicKey userName, EvictDynamicKey evictDynamicKey);
默認若是未配置如下參數,全部請求若是有緩存數據將不會從新從服務器獲取緩存
@LifeCache設置緩存過時時間. 若是沒有設置@LifeCache
, 數據將被永久緩存理除非你使用了 EvictProvider,EvictDynamicKey or EvictDynamicKeyGroup .服務器
DynamicKey驅逐與一個特定的鍵使用EvictDynamicKey
相關的數據。好比分頁,排序或篩選要求app
DynamicKeyGroup。驅逐一組與key關聯的數據,使用EvictDynamicKeyGroup
。好比分頁,排序或篩選要求maven
最後,使用 RxCache.Builder
實例化提供者interface
,提供一個有效的文件系統路徑容許RxCache寫磁盤上。
//cacheDir緩存文件路徑 ort rx.Observable; import rx.functions.Func1; import sample_data.cache.CacheProviders; import sample_data.entities.Repo; import sample_data.entities.User; import sample_data.net.RestApi; public class Repository { public static final int USERS_PER_PAGE = 25; public static Repository init(File cacheDir) { return new Repository(cacheDir); } private final CacheProviders cacheProviders; private final RestApi restApi; public Repository(File cacheDir) { //persistence設置爲緩存文件路徑cacheDir,using設置成你所定義的接口類class cacheProviders = new RxCache.Builder() .persistence(cacheDir) .using(CacheProviders.class); restApi = new Retrofit.Builder() .baseUrl(RestApi.URL_BASE) .addCallAdapterFactory(RxJavaCallAdapterFactory.create()) .addConverterFactory(GsonConverterFactory.create()) .build().create(RestApi.class); } /** * * @param update 是否更新,若是設置爲true,緩存數據將被清理,而且向服務器請求數據 * @return */ public Observable<Reply<List<User>>> getUsers(int idLastUserQueried, final boolean update) { //這裏設置idLastUserQueried爲DynamicKey, return cacheProviders.getUsers(restApi.getUsers(idLastUserQueried, USERS_PER_PAGE), new DynamicKey(idLastUserQueried), new EvictDynamicKey(update)); } //對應每一個不一樣的userName,配置緩存 public Observable<Reply<List<Repo>>> getRepos(final String userName, final boolean update) { //以userName爲DynamicKey,若是update爲true,將會從新獲取數據並清理緩存。 return cacheProviders.getRepos(restApi.getRepos(userName), new DynamicKey(userName), new EvictDynamicKey(update)); } public Observable<Reply<User>> loginUser(final String userName) { return restApi.getUser(userName).map(new Func1<Response<User>, Observable<Reply<User>>>() { @Override public Observable<Reply<User>> call(Response<User> userResponse) { if (!userResponse.isSuccess()) { try { ResponseError responseError = new Gson().fromJson(userResponse.errorBody().string(), ResponseError.class); throw new RuntimeException(responseError.getMessage()); } catch (JsonParseException | IOException exception) { throw new RuntimeException(exception.getMessage()); } } //用戶登錄,這裏設置 new EvictProvider(true),表示登錄不緩存,爲實時登錄 return cacheProviders.getCurrentUser(Observable.just(userResponse.body()), new EvictProvider(true)); } }).flatMap(new Func1<Observable<Reply<User>>, Observable<Reply<User>>>() { @Override public Observable<Reply<User>> call(Observable<Reply<User>> replyObservable) { return replyObservable; } }).map(new Func1<Reply<User>, Reply<User>>() { @Override public Reply<User> call(Reply<User> userReply) { return userReply; } }); } public Observable<String> logoutUser() { return cacheProviders.getCurrentUser(Observable.<User>just(null), new EvictProvider(true)) .map(new Func1<Reply<User>, String>() { @Override public String call(Reply<User> user) { return "Logout"; } }) .onErrorReturn(new Func1<Throwable, String>() { @Override public String call(Throwable throwable) { return "Logout"; } }); } public Observable<Reply<User>> getLoggedUser(boolean invalidate) { Observable<Reply<User>> cachedUser = cacheProviders.getCurrentUser(Observable.<User>just(null), new EvictProvider(false)); Observable<Reply<User>> freshUser = cachedUser.flatMap(new Func1<Reply<User>, Observable<Reply<User>>>() { @Override public Observable<Reply<User>> call(Reply<User> userReply) { return loginUser(userReply.getData().getLogin()); } }); if (invalidate) return freshUser; else return cachedUser; } private static class ResponseError { private final String message; public ResponseError(String message) { this.message = message; } public String getMessage() { return message; } } }
interface Providers { Observable<List<Mock>> getMocksPaginateWithFiltersEvictingPerFilter(Observable<List<Mock>> oMocks, DynamicKeyGroup filterPage, EvictDynamicKey evictFilter); }
public class Repository { private final Providers providers; public Repository(File cacheDir) { providers = new RxCache.Builder() .persistence(cacheDir) .using(Providers.class); } 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)); } //在實際的使用狀況下,這裏是當你創建你觀察到的與昂貴的操做。 //若是你正在使用HTTP調用能夠改造出來的盒子。 private Observable<List<Mock>> getExpensiveMocks() { return Observable.just(Arrays.asList(new Mock(""))); } }
Demo地址RxCacheSamples.
-dontwarn io.rx_cache.internal.**