RxCache不支持泛型持久化踩坑记录

"踩坑还是必要的"

Posted by Daisy on July 11, 2017

“慢慢来才最快. ”

踩坑记录

前段时间将公司的项目架构重新改了一遍,改的途中肯定会遇到坑,记录下来总比烂在脑子里好
简单介绍一下RxCache,一个缓存库,Rx大家族中的一员。配合RxJava用起来很爽.

记录开始

使用RxCache的时候发现不支持泛型序列化。泛型的类大致如下

class Response<T> {

    int code;

   T data;

 } 这是我现在见到的主流的封装网络请求返回体的格式,Data为可变的类型,其他的属性不变,问题在于RxCache不支持泛型的序列化,OK,我们来解决,既然你不支持泛型那我使用非泛型来缓存,所以我将Retrofit和RxCache的请求网络的代码变成了这样

RxCache

@LifeCache(duration = 5, timeUnit = TimeUnit.MINUTES)
Observable<Reply<JsonObject>> getHomePage(Observable<JsonObject> homePage, DynamicKey idLastUserQueried, EvictProvider evictProvider);

Retrofit

@FormUrlEncoded
@POST(HttpApi.NEWINDEX)
Observable<JsonObject> getHomePage(@FieldMap Map<String, String> maps);

这样发现确实可以缓存,但是我们使用起来很不方便,我们不可能拿着JSONObject去操作,这时候轮到RxJava登场,转换一下数据格式对于RxJava来说是很Easy的事.

RxJava

mRepositoryManager.obtainRxCacheService(CommonCache.class)
            .getHomePage(homePage
                    , new DynamicKey(1) // 因为是首页 所以一般来说是固定的内容 五分钟自动刷新一次
                    , new EvictProvider(false)) // 如果为true 代表强制刷新 不获取缓存
            .flatMap(new Function<Reply<JsonObject>, ObservableSource<BaseBean<IndexInfo>>>() {
                @Override
                public ObservableSource<BaseBean<IndexInfo>> apply(@NonNull Reply<JsonObject> jsonObjectReply) throws Exception {
                    return Observable.just(jsonObjectReply.getData(),BaseBean.class);
                }
            });

以为已经完了?

no,这才刚刚开始

现在的json解析库解析基本都是这么一句话

mGson.fromJson(jsonObjectReply.getData(),BaseBean.class)

对于普通的解析是够的,但是我们需要的类型是泛型的,所以后来我改成了这样

return Observable.just(mGson.fromJson(jsonObjectReply.getData(), new BaseBean<IndexInfo>().getClass()));

yes,我以为搞定了,已经不报错了不是吗?但是运行时开始报错了

Error:(62, 47) 错误: 不兼容的类型: Observable<BaseBean>无法转换为ObservableSource<BaseBean<IndexInfo>>

后面我明白泛型在运行时的getclass并不能取到泛型的class,OK此路不通,另路,与此同时我想到为什么Gson(我这里使用的是Gson)不能替我干这些事呢? 为什么他不能帮我去搞定呢?所以我发现了这种写法

 Type objectType = new TypeToken<BaseBean<IndexInfo>>() {}.getType();
 BaseBean<IndexInfo> indexInfoBaseBean = mGson.fromJson(jsonObjectReply.getData(), objectType);
 return Observable.just(indexInfoBaseBean);

OK.That’s done.踩坑完毕

参考链接:
http://www.cnblogs.com/qq78292959/p/3781808.html
http://bbs.csdn.net/topics/390376611/
https://github.com/VictorAlbertos/RxCache/issues/41

2017/11/1 9:58:27 更新,前段时间项目又用到了缓存,安装上面的做法确实可以解决RxCache缓存泛型的问题,但是我觉得并不够优雅,在P层加了很多无关的东西,下面是在github上找到的另一个解决办法。

// 一般来说BaseBean都是长这样
public class BaseBean<T>{
	String msg; 
	List<T> results;
}


// RxCache之所以不能解析T的类型是因为无法获取明确的类型,那我们给他一个明确的类型
public class ApiResponse extends BaseBean<ApiResponse.FocusListItem> {

    public static class FocusListItem {
        。。。
    }
}

// Cache模块的接口
Observable<Reply<ApiResponse>> getFocusList(Observable<ApiResponse> observable, EvictProvider evictProvider);

亲测是有效的,记录下来,以备后记…