【发布时间】:2017-10-13 02:24:03
【问题描述】:
上下文:
我有一个使用带有 RxJava 的 Retrofit2 来处理服务器端响应的 Android 应用程序。服务器端知道如何处理 etag,因此服务器可以将请求响应返回为 200(成功)或 304(未修改)。问题是我们希望能够在Subscriber#onNext() 中以不同方式处理这些响应。例如,我们有一个使用 SQLlite 实现的本地数据库,因此当服务器端请求返回 200 时,我们希望将该响应存储在本地数据库中,但如果请求响应返回 304 我们不想这样做,因为它是我们已经存储在数据库中的相同数据,再次保存是浪费时间。
我们使用Fernando Cejas Clean Architecture 作为我们的应用架构。
我们的交互器正在使用存储库,它们使用改造层来执行服务器端请求并返回像rx.Observable<List<SomeModelClass>> 这样的数据。我们的交互器也使用返回数据库数据的 DAO,例如 rx.Observable<List<SomeModelClass>>。因此,通过这样做,我们可以做一些非常酷的事情,例如:
public void GetDogsInteractor {
...
public void execute (Callback callback) {
mDogsRepository.getAllDogs()
.onErrorNext(ObservableUtils.ifExceptionIs(SomeServerSideException.class, mDogsDao.getDatabaseDogs()))
.subscribe(
new Subscriber<List<Dog>>() {
...
public void onError() {
callback.showError("Sorry no doggos on server-side nor database");
}
public void onNext(List<Dog> dogs) {
callback.showDogsOnUI(dogs);
}
...
}
);
}
...
}
正如您所见,我们的存储库和 DAO 具有相同的接口,这样在出现问题时可以很容易地相互插入。
解决方法:
假设我们希望仅当请求响应为 200 时才将所有 Dog 对象存储在数据库中,但如果请求响应为 304 时我们不存储。我能想到的唯一解决方案是过滤服务器 -如果响应是 304,则侧面响应并抛出异常,这样我可以处理 Subscriber#onNext() 中的 200 个请求和 Subscriber#onError() 中的 304s。这是存储库内部实现的外观:
public class DogRepository {
...
public rx.Observable<List<Dog>> getAllDogs() {
mRetrofitService.getAllDogsFromServerSide() //Returns rx.Observable<Response<List<Dog>>>
.flatMap(new Func1<Response<List<Dog>>, Observable<List<Dog>>>() {
@Override
public Observable<List<Dog>> call(Response<List<Dog>> serverSideResponse) {
//Check the response code, if its 200 just pass the response through, if its 304 throw an exception
if (serverSideResponse.getCode() == 304) {
return Observable.error(new NotModifiedException(serverSideResponse.getBody()));
} else {
return Observable.just(serverSideResponse.getBody());
}
}
})
}
...
}
然后我创建一个覆盖Subscriber#onError() 方法的自定义订阅者:
public class MySubscriber<T> extends rx.Subscriber<T> {
...
public void onError(Throwable e) {
if (e instance of NotModifiedException) {
onNotModified(((NotModifiedException) e).getBody()); //onNotModified() is a hook method
}
}
public void onNotModified(T model) {
//Optional to implement
}
...
}
那么最后我是这样用的:
public void GetDogsInteractor {
...
public void execute (Callback callback) {
mDogsRepository.getAllDogs()
.onErrorNext(ObservableUtils.ifExceptionIs(SomeServerSideException.class, mDogsDao.getDatabaseDogs()))
.subscribe(
new MySubscriber<List<Dog>>() {
...
public void onError() {
callback.showError("Sorry no doggos on server-side nor database");
}
public void onNotModified(List<Dog> dogs) {
callback.showDogsOnUI(dogs);
}
public void onNext(List<Dog> dogs) {
mDogDao.saveAllDogs(dogs)
callback.showDogsOnUI(dogs);
}
...
}
);
}
...
}
这样我什至可以使用 onErrorNext() 将其他流与 NotModifiedException 挂钩。
问题:
我的一些同事不太乐意处理这种抛出异常并将 304 响应作为“意外”处理。不能怪他们,这不是最好的解决方案。但我尝试了很多东西,这是唯一有效的方法。我的问题是;有没有办法在不使用异常的情况下实现这一点?更清洁的方式?
我尽可能地简化了这一点,但如果有什么你不明白的,请告诉我。
【问题讨论】:
标签: android retrofit rx-java observable