RxCache的使用,RxCache与Retrofit2.0结合使用
最近学习了Retrofit2.0,接下来自然少不了Rxcache的学习,
RxCache是一个好用的缓存类库,可以直接和Retrofit结合使用
但是,我从上周六开始浏览网上的介绍,大部分都是直接从官方介绍那里直接翻译一遍就草草了事,没有什么具体的实现步骤
最后无奈只好下载了官方的Demo来看 Demo链接 点击打开链接,注意此学习此Demo,直接用AS打开RxCacheSamples根目录就可以了,不要选择根目录下的sample_android进行打开。
下边我跟据网上的资料和学习Demo自己写了一个Retrofit和rxcache结合使用的小练习:
retrofit可以看我上一篇的介绍:点击打开链接
一,添加依赖
compile "com.github.VictorAlbertos.RxCache:runtime:1.8.3-2.x" compile "io.reactivex.rxjava2:rxjava:2.1.6" compile 'com.squareup.retrofit2:adapter-rxjava2:2.4.0' //Caused by: java.lang.IllegalArgumentException: Could not locate call adapter for rx.Observable<> compile 'com.squareup.retrofit2:retrofit:2.4.0' compile 'com.squareup.retrofit2:converter-gson:2.4.0' compile 'com.github.VictorAlbertos.Jolyglot:gson:0.0.3' compile 'io.reactivex.rxjava2:rxandroid:2.0.0'
repositories { google() jcenter() maven { url "https://jitpack.io" } }
二:看下这个小Demo的结构:
可以按照以下的顺序创建类,更有助于消化吸收
News : 和Retrofit 中存放的数据类一样 就是一个Bena类
RestApi : Retrofit的接口类
CacheProvider : 用来创建一个RxCaChe的接口
Repository : Retrofit和RxCaChe的具体结合操作,以及是一个接口类
MainActivity : 执行网络请求操作
三:具体代码实现:
- 这个Demo我还是使用了和风天气的Api接口来实现,所以还是和在我上篇Retrofit中一样直接用GsonFormat创建一个News类,简单方便又实用,如下:
private List<HeWeather6Bean> HeWeather6; public List<HeWeather6Bean> getHeWeather6() { return HeWeather6; } public void setHeWeather6(List<HeWeather6Bean> HeWeather6) { this.HeWeather6 = HeWeather6; } public static class HeWeather6Bean { /** * basic : {"cid":"CN101010100","location":"北京","parent_city":"北京","admin_area":"北京","cnty":"中国","lat":"39.90498734","lon":"116.4052887","tz":"+8.00"} * update : {"loc":"2018-05-08 15:47","utc":"2018-05-08 07:47"} * status : ok * now : {"cloud":"0","cond_code":"100","cond_txt":"晴","fl":"23","hum":"24","pcpn":"0.0","pres":"1016","tmp":"25","vis":"10","wind_deg":"265","wind_dir":"西风","wind_sc":"2","wind_spd":"8"} */ private BasicBean basic; private UpdateBean update; private String status; private NowBean now; public BasicBean getBasic() { return basic; } public void setBasic(BasicBean basic) { this.basic = basic; } public UpdateBean getUpdate() { return update; } public void setUpdate(UpdateBean update) { this.update = update; } public String getStatus() { return status; } public void setStatus(String status) { this.status = status; } public NowBean getNow() { return now; } public void setNow(NowBean now) { this.now = now; }
News类的代码就不贴全了,
2:RestApi类: 跟普通的Retrofit接口没有什么区别
public interface RestApi { @POST("s6/weather/now?parameters") Observable<News> getUsers(@Query("key")String key, @Query("location")String location); }
3:CacheProvider类:
public interface CacheProvider { @LifeCache(duration = 2, timeUnit = TimeUnit.MINUTES)// Observable<Reply<News>> getRepos(Observable<News> ouser); }
请注意:1: @LifeCache设置缓存过期时间. 如果没有设置@LifeCache, 数据将被永久缓存
除非你使用了其他的清除缓存的标注,这个一会我们再说。
2: 此接口写的里面的第一个参数要写成你Retrofit接口中开头的一段,可以从上边的代码和下边的代码仔细看一下
当然,这里我们只设置了一个参数,也就是必需的参数
如果只设置这个所必需的参数和没有设置@LifeCache那么只要本地缓存没有消失,就会每次都进行本地读取数 据。其他参数是一些 清除缓存的标注,我们先进行一次简单的数据请求与缓存,再写关于其他标注的事情。 一会 再说。
4:Repository 类
//调用此处,用来生成一个缓存文件 public static Repository init(File cacheDir) { return new Repository(cacheDir); } private final CacheProvider cacheProvider; private final RestApi restApi; public Repository(File cacheDir) { cacheProvider = new RxCache.Builder() .persistence(cacheDir, new GsonSpeaker()) .using(CacheProvider.class); restApi = new Retrofit.Builder() .baseUrl("https://free-api.heweather.com/") .addConverterFactory(GsonConverterFactory.create()) .addCallAdapterFactory(RxJava2CallAdapterFactory.create()) .build() .create(RestApi.class); } //真正进行数据请求和缓存的接口 public Observable<Reply<News>> getRepos(String key, String location) { return cacheProvider.getRepos(restApi.getUsers(key, location)); }
5:MainActivity 进行网络请求和缓存操作
private Repository repository; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); repository = Repository.init(getFilesDir()); initData(); } private void initData() { repository.getRepos("fad6d6b2cda14ef69d260ea9a4415e31", "北京") .subscribeOn(Schedulers.newThread()) .subscribe(new Consumer<Reply<News>>() { @Override public void accept(Reply<News> newsReply) throws Exception { News.HeWeather6Bean bean = newsReply.getData().getHeWeather6().get(0); Log.e("TagSuccess", bean.getNow().getCond_txt()); } }, new Consumer<Throwable>() { @Override public void accept(Throwable throwable) throws Exception { Log.e("TagErr", throwable.getMessage()); } }); }
现在看下控制台Log 还有看一下我们的网络请求流量
E/TagSuccess: 晴
ok 然后我们马上在两分钟之内再次运行一下程序
再看一下Log 和流量状态:
E/TagSuccess: 晴
我们在第二次在两分钟之内运行程序的时候发现并没数据变动,可是控制台还是打印出了Log,说明我们第一次使用Retrofit结合RxCache进行网络请求和缓存成功了!,
至于为什么在两分钟之内,是因为我们在CacheProvider类中设置了@lifeCache是两分钟,你也可以等到两分钟或者改变一下@lifecache的时间在进行一次测试,看一下会不会有流量变化。
四 :ok 完成了上边的请求,我觉得应该对具体的代码流程有了清晰地理解
接下来看一下我们之前所说的 清除缓存的标注
- EvictProvider 可以明确地清理清理所有缓存数据.
- EvictDynamicKey 可以明确地清理指定的数据,
- EvictDynamicKeyGroup 允许明确地清理一组特定的数据.
DynamicKey 驱逐与一个特定的键使用
EvictDynamicKey
相关的数据。比如分页,排序或筛选要求DynamicKeyGroup。 驱逐一组与key关联的数据,使用
EvictDynamicKeyGroup
。比如分页,排序或筛选要求
这些标注实际上就是用来写在Cacheprovider接口中的一些参数
代码如下修改 修改或者添加的代码我都用红的标注了,一目了然。
CaCheProvider:
public interface CacheProvider { @LifeCache(duration = 2, timeUnit = TimeUnit.MINUTES) Observable<Reply<News>> getRepos(Observable<News> ouser, EvictProvider evictProvider); }Respository:
//真正进行数据请求和缓存的接口 public Observable<Reply<News>> getRepos(String key, String location,final boolean updata) { return cacheProvider.getRepos(restApi.getUsers(key, location),new EvictProvider(updata)); }
MainActivity:
private boolean upData;
upData=false; repository.getRepos("fad6d6b2cda14ef69d260ea9a4415e31", "北京",upData) .subscribeOn(Schedulers.newThread())
这边upData 设置成true的话就表示清除所有缓存了 ,可以看一下 你的控制台是不是每次打开都是有数据请求,
设置成false的话就是不删除缓存,就是跟不设置EvictProvider 一个样子了!
五:EvictDynamicKey 和DynamicKey
1:添加CacheProvider的接口 restApi的话就不用改了,还是用之前和风天气的接口
public interface CacheProvider { @LifeCache(duration = 2, timeUnit = TimeUnit.MINUTES) Observable<Reply<News>> getRepos(Observable<News> ouser, EvictProvider evictProvider); Observable<Reply<News>> getTwo(Observable<News> ouser,DynamicKey dynamicKey,EvictDynamicKey evictDynamicKey); }
2:Repository类
//真正进行数据请求和缓存的接口 public Observable<Reply<News>> getRepos(String key, String location,final boolean updata) { return cacheProvider.getRepos(restApi.getUsers(key, location),new EvictProvider(updata)); } public Observable<Reply<News>>getTwo(String key,String location, String data,final boolean updata){ return cacheProvider.getTwo(restApi.getUsers(key,location),new DynamicKey(data),new EvictDynamicKey(updata)); }
3:MainActivity
直接添加一个方法来调用 Repository类中新建的getTwo
private void two() { upData=true; repository.getTwo("fad6d6b2cda14ef69d260ea9a4415e31","济南", bean.getStatus(),upData) .subscribeOn(Schedulers.newThread()) .observeOn(AndroidSchedulers.mainThread()) .subscribe(new Consumer<Reply<News>>() { @Override public void accept(Reply<News> newsReply) throws Exception { Log.e("TwoTagSuccess", bean.getStatus() + ""); } }, new Consumer<Throwable>() { @Override public void accept(Throwable throwable) throws Exception { Log.e("aaaaaaaa",throwable.toString()); } }); }
之前的initdata()方法先执行进行获取数据,然后在执行这个 two方法用来删除getStatus()字段中的内容
可以对比一下 updata 是true 和flase 的流量情况是不是如下:
updata=true:删除这个字段的数据再次请求,可以看到 有两次流量请求
updata=flase:不删除,只有一次 流量请求
RxCache和ReFrofit结合使用就是如上了,
欢迎各位看到的小伙伴能够给出意见和建议。