gpt4 book ai didi

android - 没有 Room 的 NetworkBoundResource 帮助程序类

转载 作者:塔克拉玛干 更新时间:2023-11-02 08:31:04 25 4
gpt4 key购买 nike

当我尝试为 Room Db 和 Retrofit 实现 NetworkBoundResourceResource 帮助程序类时,它工作得很好。但是,我需要使用 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/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com