重构谷歌的NetworkBoundResource类以使用RxJava而不是LiveData
内容导读
互联网集市收集整理的这篇技术教程文章主要介绍了重构谷歌的NetworkBoundResource类以使用RxJava而不是LiveData,小编现在分享给大家,供广大互联网技能从业者学习和参考。文章包含8385字,纯文字阅读大概需要12分钟。
内容图文
![重构谷歌的NetworkBoundResource类以使用RxJava而不是LiveData](/upload/InfoBanner/zyjiaocheng/797/ea5eb3c928fb41428b7035f9b51854d6.jpg)
谷歌的android架构组件教程here有一个部分解释了如何抽象通过网络获取数据的逻辑.在其中,他们使用LiveData创建一个名为NetworkBoundResource的抽象类,以创建一个被动流作为所有被动网络请求的基础.
public abstract class NetworkBoundResource<ResultType, RequestType> {
private final AppExecutors appExecutors;
private final MediatorLiveData<Resource<ResultType>> result = new MediatorLiveData<>();
@MainThread
NetworkBoundResource(AppExecutors appExecutors) {
this.appExecutors = appExecutors;
result.setValue(Resource.loading(null));
LiveData<ResultType> dbSource = loadFromDb();
result.addSource(dbSource, data -> {
result.removeSource(dbSource);
if (shouldFetch()) {
fetchFromNetwork(dbSource);
} else {
result.addSource(dbSource, newData -> result.setValue(Resource.success(newData)));
}
});
}
private void fetchFromNetwork(final LiveData<ResultType> dbSource) {
LiveData<ApiResponse<RequestType>> apiResponse = createCall();
// we re-attach dbSource as a new source, it will dispatch its latest value quickly
result.addSource(dbSource, newData -> result.setValue(Resource.loading(newData)));
result.addSource(apiResponse, response -> {
result.removeSource(apiResponse);
result.removeSource(dbSource);
//noinspection ConstantConditions
if (response.isSuccessful()) {
appExecutors.diskIO().execute(() -> {
saveCallResult(processResponse(response));
appExecutors.mainThread().execute(() ->
// we specially request a new live data,
// otherwise we will get immediately last cached value,
// which may not be updated with latest results received from network.
result.addSource(loadFromDb(),
newData -> result.setValue(Resource.success(newData)))
);
});
} else {
onFetchFailed();
result.addSource(dbSource,
newData -> result.setValue(Resource.error(response.errorMessage, newData)));
}
});
}
protected void onFetchFailed() {
}
public LiveData<Resource<ResultType>> asLiveData() {
return result;
}
@WorkerThread
protected RequestType processResponse(ApiResponse<RequestType> response) {
return response.body;
}
@WorkerThread
protected abstract void saveCallResult(@NonNull RequestType item);
@MainThread
protected abstract boolean shouldFetch();
@NonNull
@MainThread
protected abstract LiveData<ResultType> loadFromDb();
@NonNull
@MainThread
protected abstract LiveData<ApiResponse<RequestType>> createCall();
}
根据我的理解,本课程的逻辑是:
a)创建一个名为“result”的MediatorLiveData作为主要返回对象,并将其初始值设置为Resource.loading(null)
b)从Android Room db获取数据作为dbSource LiveData,并将其作为源LiveData添加到“result”
c)在dbSource LiveData的第一次发射中,从“result”中删除dbSource LiveData并调用“shouldFetchFromNetwork()”
> IF TRUE,调用“fetchDataFromNetwork(dbSource)”,它通过“createCall()”创建网络调用,返回封装为ApiResponse对象的响应的LiveData
>将dbSource LiveData添加回“result”并将设置的值发送到Resource.loading(data)
>将apiResponce LiveData添加到“结果”并在第一次发射时删除dbSource和apiResponce LiveDatas
>如果apiResponse成功,则调用“saveCallResult(processResponse(response))”并将dbSource LiveData添加回“result”并将发出的值设置为Resource.success(newData)
>如果apiResponse失败,请调用“onFetchFailed()”并将dbSource LiveData添加回“result”并将发出的值设置为Resource.error(response.errorMessage,newData))
> IF FALSE,只需将dbSource LiveData添加到“result”并将发出的值设置为Resource.success(newData)
鉴于此逻辑是正确的解释,我试图重构此类以使用RxJava Observables而不是LiveData.这是我成功重构的尝试(我删除了初始的Resource.loading(null),因为我认为这是多余的).
public abstract class NetworkBoundResource<ResultType, RequestType> {
private Observable<Resource<ResultType>> result;
@MainThread
NetworkBoundResource() {
Observable<Resource<ResultType>> source;
if (shouldFetch()) {
source = createCall()
.subscribeOn(Schedulers.io())
.doOnNext(apiResponse -> saveCallResult(processResponse(apiResponse)))
.flatMap(apiResponse -> loadFromDb().toObservable().map(Resource::success))
.doOnError(t -> onFetchFailed())
.onErrorResumeNext(t -> {
return loadFromDb()
.toObservable()
.map(data -> Resource.error(t.getMessage(), data))
})
.observeOn(AndroidSchedulers.mainThread());
} else {
source = loadFromDb()
.toObservable()
.map(Resource::success);
}
result = Observable.concat(
loadFromDb()
.toObservable()
.map(Resource::loading)
.take(1),
source
);
}
public Observable<Resource<ResultType>> asObservable() {return result;}
protected void onFetchFailed() {}
@WorkerThread
protected RequestType processResponse(ApiResponse<RequestType> response) {return response.body;}
@WorkerThread
protected abstract void saveCallResult(@NonNull RequestType item);
@MainThread
protected abstract boolean shouldFetch();
@NonNull
@MainThread
protected abstract Flowable<ResultType> loadFromDb();
@NonNull
@MainThread
protected abstract Observable<ApiResponse<RequestType>> createCall();
}
由于我是RxJava的新手,我的问题是我是否正确地重构为RxJava并保持与此类的LiveData版本相同的逻辑?
解决方法:
public abstract class ApiRepositorySource<RawResponse extends BaseResponse, ResultType> {
// result is a Flowable because Room Database only returns Flowables
// Retrofit response will also be folded into the stream as a Flowable
private Flowable<ApiResource<ResultType>> result;
private AppDatabase appDatabase;
@MainThread
ApiRepositorySource(AppDatabase appDatabase) {
this.appDatabase = appDatabase;
Flowable<ApiResource<ResultType>> source;
if (shouldFetch()) {
source = createCall()
.doOnNext(this::saveCallResult)
.flatMap(apiResponse -> loadFromDb().toObservable().map(ApiResource::success))
.doOnError(this::onFetchFailed)
.onErrorResumeNext(t -> {
return loadFromDb()
.toObservable()
.map(data -> {
ApiResource apiResource;
if (t instanceof HttpException && ((HttpException) t).code() >= 400 && ((HttpException) t).code() < 500) {
apiResource = ApiResource.invalid(t.getMessage(), data);
} else {
apiResource = ApiResource.error(t.getMessage(), data);
}
return apiResource;
});
})
.toFlowable(BackpressureStrategy.LATEST);
} else {
source = loadFromDb()
.subscribeOn(Schedulers.io())
.map(ApiResource::success);
}
result = Flowable.concat(initLoadDb()
.map(ApiResource::loading)
.take(1),
source)
.subscribeOn(Schedulers.io());
}
public Observable<ApiResource<ResultType>> asObservable() {
return result.toObservable();
}
@SuppressWarnings("WeakerAccess")
protected void onFetchFailed(Throwable t) {
Timber.e(t);
}
@WorkerThread
protected void saveCallResult(@NonNull RawResult resultType) {
resultType.saveResponseToDb(appDatabase);
}
@MainThread
protected abstract boolean shouldFetch();
@NonNull
@MainThread
protected abstract Flowable<ResultType> loadFromDb();
@NonNull
@MainThread
protected abstract Observable<RawResult> createCall();
@NonNull
@MainThread
protected Flowable<ResultType> initLoadDb() {
return loadFromDb();
}
}
所以这是我在多次迭代后决定使用的内容.这是目前正在生产中,并适用于我的应用程序.这里有一些带走的笔记:
>创建BaseResponse界面
public interface BaseResponse {
void saveResponseToDb(AppDatabase appDatabase);
}
并在所有api响应对象类中实现它.这样做意味着您不必在每个ApiResource中实现save_to_database逻辑,如果需要,您可以将其默认为响应的实现.
>为简单起见,我选择在onErrorResumeNext块中处理Retrofit错误响应,但我建议您创建一个可以容纳所有这些逻辑的Transformer类.在这种情况下,我为ApiResources添加了额外的Status枚举值,称为INVALID,用于400级响应.
>您可能想要使用LiveData的Reactive Streams体系结构组件库
实现“android.arch.lifecycle:reactivestreams:$lifecycle_version”并向此类添加一个名为的方法
public LiveData<ApiResource<ResultType>> asLiveData {
return LiveDataReactiveStreams.fromPublisher(result);
}
理论上,这将完美地工作,因为我们的ViewModel不必将Observable排放转换为LiveData排放或实现View中Observables的生命周期逻辑.不幸的是,这个流在每次配置更改时都会重建,因为它会在所调用的任何onDestroy中处理LiveData(无论isFinishing是true还是false).因此,我们必须管理此流的生命周期,这首先会破坏使用它的目的,或者每次设备旋转时都会重复调用.
以下是创建ApiNetworkResource实例的UserRepository示例
@Singleton
public class UserRepository {
private final RetrofitApi retrofitApi;
private final AppDatabase appDatabase;
@Inject
UserRepository(RetrofitApi retrofitApi, AppDatabase appDatabase) {
this.retrofitApi = retrofitApi;
this.appDatabase = appDatabase;
}
public Observable<ApiResource<User>> getUser(long userId) {
return new ApiRepositorySource<UserResponse, User>(appDatabase) {
@Override
protected boolean shouldFetch() {
return true;
}
@NonNull
@Override
protected Flowable<User> loadFromDb() {
return appDatabase.userDao().getUserFlowable(userId);
}
@NonNull
@Override
protected Observable<UserResponse> createCall() {
return retrofitApi.getUserById(userId);
}
}.asObservable();
}
}
内容总结
以上是互联网集市为您收集整理的重构谷歌的NetworkBoundResource类以使用RxJava而不是LiveData全部内容,希望文章能够帮你解决重构谷歌的NetworkBoundResource类以使用RxJava而不是LiveData所遇到的程序开发问题。 如果觉得互联网集市技术教程内容还不错,欢迎将互联网集市网站推荐给程序员好友。
内容备注
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 gblab@vip.qq.com 举报,一经查实,本站将立刻删除。
内容手机端
扫描二维码推送至手机访问。