【发布时间】:2017-04-26 12:04:00
【问题描述】:
我有两个使用公共存储库的片段。
我正在尝试为此存储库实施缓存管理系统。
这个想法是:
其中一个片段被加载,它调用getData()方法,该方法使用getDataFromNetwork()对远程JSON Api进行网络调用,获取结果并将其作为List<Aqicn>(data我的代码中的变量)。
下一个片段被加载。如果它发生在 60 秒之前,则没有网络调用,数据直接来自我的数据列表中的缓存,使用 getDataFromMemory()。
RxJava Observable.switchIfEmpty() 用于知道 Observable(我的 ArrayList)是否为空并调用正确的方法。
我不知道如何首次亮相,所以我只是在我的主布局上放了一个按钮。当我启动我的应用程序时,第一个片段会自动加载,getData() 第一次被调用。当我按下这个按钮时,它会加载第二个片段,getData() 被第二次调用。
如果我在 60 秒之前按下此按钮,我不应该对 JSON api 进行网络调用,但是......我有一个,我总是会得到第二个网络调用,并且我的缓存数据没有被使用。我的代码有什么问题?
public class CommonRepository implements Repository {
private static final String TAG = CommonRepository.class.getSimpleName();
private long timestamp;
private static final long STALE_MS = 60 * 1000; // Data is stale after 60 seconds
private PollutionApiService pollutionApiService;
private ArrayList<Aqicn> data;
public CommonRepository(PollutionApiService pollutionApiService) {
this.pollutionApiService = pollutionApiService;
this.timestamp = System.currentTimeMillis();
data = new ArrayList<>();
}
@Override
public Observable<Aqicn> getDataFromNetwork(String city, String authToken) {
Observable<Aqicn> aqicn = pollutionApiService.getPollutionObservable(city, authToken)
.doOnNext(new Action1<Aqicn>() {
@Override
public void call(Aqicn aqicn) {
data.add(aqicn);
}
});
return aqicn;
}
private boolean isUpToDate() {
return System.currentTimeMillis() - timestamp < STALE_MS;
}
@Override
public Observable<Aqicn> getDataFromMemory() {
if (isUpToDate()) {
return Observable.from(data);
} else {
timestamp = System.currentTimeMillis();
data.clear();
return Observable.empty();
}
}
@Override
public Observable<Aqicn> getData(String city, String authToken) {
return getDataFromMemory().switchIfEmpty(getDataFromNetwork(city, authToken));
}
}
======= 编辑:我将代码简化到最少 ==========
public class CommonRepository implements Repository {
private PollutionApiService pollutionApiService;
private static Observable<Aqicn> cachedData = null;
public CommonRepository(PollutionApiService pollutionApiService) {
this.pollutionApiService = pollutionApiService;
}
@Override
public Observable<Aqicn> getDataFromNetwork(String city, String authToken) {
Observable<Aqicn> aqicn = pollutionApiService.getPollutionObservable(city, authToken);
cachedData = aqicn;
return aqicn;
}
@Override
public Observable<Aqicn> getData(String city, String authToken) {
if(cachedData == null) {
return getDataFromNetwork(city, authToken);
}
return cachedData;
}
}
刚刚意识到无论我在做什么,当我做 return cachedData 时,网络调用就完成了......
===== EDIT 发现问题但未找到解决方案 ==========
事情是在我的构造函数中,我初始化了我的污染ApiService。 这对 JSON 请求使用 Dagger 并返回一个 Observable :
public interface PollutionApiService {
@GET("feed/{city}/")
Observable<Aqicn> getPollutionObservable(@Path("city") String city, @Query("token") String token);
}
我不知道这一切的细节是如何运作的,但我是这样解释的。 Dagger 创建一个 PollutionApiService 提供者,它是一个 Observable。当我做return cachedData 时,这个 Observable 被订阅了,所以网络调用完成了......但不知道如何修复它。事实上,每次我发出return cachedData 时,都会有一个网络调用。
【问题讨论】:
-
你想缓存给定参数的所有请求吗?如果您首先使用 city: 'Hamburg' 和 auth: X 调用 getData,然后再调用 'Berlin'、'X',这两个请求是否都应该缓存 60 秒?在您当前的实现中,您只需为每个请求添加元素到缓存中。
-
我的两个调用中的参数都是一样的。
标签: android caching rx-java repository-pattern