- iOS/Objective-C 元类和类别
- objective-c - -1001 错误,当 NSURLSession 通过 httpproxy 和/etc/hosts
- java - 使用网络类获取 url 地址
- ios - 推送通知中不播放声音
当我尝试为 Room Db 和 Retrofit 实现 NetworkBoundResource
和 Resource
帮助程序类时,它工作得很好。但是,我需要使用 Retrofit only without Room 实现来自 RESTful 的搜索结果。 Resources
类很好,我不需要更改它。我想要做的是尝试删除此类中的数据库源。
public abstract class NetworkBoundResource<ResultType, RequestType> {
private final AppExecutors appExecutors;
private final MediatorLiveData<Resource<ResultType>> result = new MediatorLiveData<>();
@MainThread
public NetworkBoundResource(AppExecutors appExecutors) {
this.appExecutors = appExecutors;
result.setValue(Resource.loading(null));
LiveData<ResultType> dbSource = loadFromDb();
result.addSource(dbSource, data -> {
result.removeSource(dbSource);
if (shouldFetch(data)) {
fetchFromNetwork(dbSource);
} else {
result.addSource(dbSource, newData -> setValue(Resource.success(newData)));
}
});
}
@MainThread
private void setValue(Resource<ResultType> newValue) {
if (!Objects.equals(result.getValue(), newValue)) {
result.setValue(newValue);
}
}
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 -> 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 -> setValue(Resource.success(newData)))
);
});
} else {
onFetchFailed();
result.addSource(dbSource,
newData -> 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(@Nullable ResultType data);
@NonNull
@MainThread
protected abstract LiveData<ResultType> loadFromDb();
@NonNull
@MainThread
protected abstract LiveData<ApiResponse<RequestType>> createCall();
}
最佳答案
问题是任何加载的数据都必须首先通过数据库,然后将其从数据库加载到 UI,就像 NetworkBoundResource
所做的那样。因此,我所做的是分离持久数据库并创建一个临时字段来加载。
例如,如果我想编辑 original搜索方法,我建议:
public LiveData<Resource<List<Repo>>> search(String query) {
return new NetworkBoundResource<List<Repo>, RepoSearchResponse>(appExecutors) {
// Temp ResultType
private List<Repo> resultsDb;
@Override
protected void saveCallResult(@NonNull RepoSearchResponse item) {
// if you don't care about order
resultsDb = item.getItems();
}
@Override
protected boolean shouldFetch(@Nullable List<Repo> data) {
// always fetch.
return true;
}
@NonNull
@Override
protected LiveData<List<Repo>> loadFromDb() {
if (resultsDb == null) {
return AbsentLiveData.create();
}else {
return new LiveData<List<Repo>>() {
@Override
protected void onActive() {
super.onActive();
setValue(resultsDb);
}
};
}
}
@NonNull
@Override
protected LiveData<ApiResponse<RepoSearchResponse>> createCall() {
return githubService.searchRepos(query);
}
@Override
protected RepoSearchResponse processResponse(ApiResponse<RepoSearchResponse> response) {
RepoSearchResponse body = response.body;
if (body != null) {
body.setNextPage(response.getNextPage());
}
return body;
}
}.asLiveData();
}
我运行了它,它起作用了。
编辑:我创建了另一个更简单的类来处理这个问题(Daniel Wilson 的另一个答案具有更多功能并且已更新)。
但是,这个类没有依赖关系,被转换为基础只做fetch响应:
abstract class NetworkBoundResource<RequestType> {
private val result = MediatorLiveData<Resource<RequestType>>()
init {
setValue(Resource.loading(null))
fetchFromNetwork()
}
@MainThread
private fun setValue(newValue: Resource<RequestType>) {
if (result.value != newValue) {
result.value = newValue
}
}
private fun fetchFromNetwork() {
val apiResponse = createCall()
result.addSource(apiResponse) { response ->
result.removeSource(apiResponse)
when (response) {
is ApiSuccessResponse -> {
setValue(Resource.success(processResponse(response)))
}
is ApiErrorResponse -> {
onFetchFailed()
setValue(Resource.error(response.errorMessage, null))
}
}
}
}
protected fun onFetchFailed() {
}
fun asLiveData() = result as LiveData<Resource<RequestType>>
@WorkerThread
protected open fun processResponse(response: ApiSuccessResponse<RequestType>) = response.body
@MainThread
protected abstract fun createCall(): LiveData<ApiResponse<RequestType>>
}
所以在使用的时候,只能实现一个方法createCall()
:
fun login(email: String, password: String) = object : NetworkBoundResource<Envelope<User>>() {
override fun createCall() = api.login(email, password)
}.asLiveData()
关于android - 没有 Room 的 NetworkBoundResource 帮助程序类,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46923289/
我正在使用 Retrofit、LiveData、Room (Android AAC)。 NetworkBoundResource是googlesimple提供的网络资源和房间结合的好 helper .
在 Google NetworkBoundResource 类中,我无法理解 MediatorLiveData 的 addSource() 和 removeSource() 的顺序被使用。 例如--在
您对如何使用 NetworkBoundResource 实现存储库模式有任何想法吗?和 Kotlin 协程?我知道我们可以使用 GlobalScope 启动协程,但这可能会导致协程泄漏。我想将 vie
我遇到了一些有线问题。当我第一次订阅时,它会进行网络调用并将数据保存到数据库,但是 loadFromDb() 永远不会执行,并且不会引发任何错误。 为什么会发生这种情况? Flowable>>
我的应用使用 Android 的 Architecture components库并显示从具有无限滚动效果的分页 REST api 获取的项目列表。 我想做的是使用 Paging Library结合
当我尝试为 Room Db 和 Retrofit 实现 NetworkBoundResource 和 Resource 帮助程序类时,它工作得很好。但是,我需要使用 Retrofit only wit
Google的android架构组件教程here有一部分解释了如何抽象化通过网络获取数据的逻辑。在其中,他们创建了一个名为 NetworkBoundResource 的抽象类,使用 LiveData
我是一名优秀的程序员,十分优秀!