我目前正在查看以下指南:https://developer.android.com/topic/libraries/architecture/guide.html
networkBoundResource类:
// ResultType: Type for the Resource data
// RequestType: Type for the API response
public abstract class NetworkBoundResource<ResultType, RequestType> {
// Called to save the result of the API response into the database
@WorkerThread
protected abstract void saveCallResult(@NonNull RequestType item);
// Called with the data in the database to decide whether it should be
// fetched from the network.
@MainThread
protected abstract boolean shouldFetch(@Nullable ResultType data);
// Called to get the cached data from the database
@NonNull @MainThread
protected abstract LiveData<ResultType> loadFromDb();
// Called to create the API call.
@NonNull @MainThread
protected abstract LiveData<ApiResponse<RequestType>> createCall();
// Called when the fetch fails. The child class may want to reset components
// like rate limiter.
@MainThread
protected void onFetchFailed() {
}
// returns a LiveData that represents the resource
public final LiveData<Resource<ResultType>> getAsLiveData() {
return result;
}
}
我在这里对线程的使用感到困惑。
为什么在这里将@MainThread应用于networkIO?
另外,为了保存到数据库中,将应用@WorkerThread,而使用@MainThread来获取结果。
默认情况下,使用辅助线程进行NetworkIO和本地db交互是不好的做法吗?
我还在检查以下演示(GithubBrowserSample):https://github.com/googlesamples/android-architecture-components
从线程的角度来看,这使我感到困惑。
该演示使用执行程序框架,并为networkIO定义了一个具有3个线程的固定池,但是在演示中,仅为一个调用定义了一个工作任务,即
FetchNextSearchPageTask
。所有其他网络请求似乎都在主线程上执行。有人可以阐明理由吗?
最佳答案
看来您有一些误解。
通常,从主线程(UI)调用网络永远是不可能的,但是除非您有大量数据,否则从主线程中的DB中获取数据可能是好的。这就是Google的例子。
1.
首先,由于Java 8,您可以使用lambda语法创建一些接口(interface)(所谓的“功能接口(interface)”)的简单实现。这就是NetworkBoundResource中发生的情况:
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)))
);
});
第一个任务(
processResponse
和saveCallResult
)在diskIO
Executor
提供的线程上进行调度,然后从该线程将其余工作调度回Main线程。2.
和
事实并非如此。在主线程上仅创建结果包装程序,即
LiveData<ApiResponse<RequestType>>
。网络请求是在其他线程上完成的。这不容易看到,因为Retrofit库用于完成所有与网络相关的繁重工作,并且很好地隐藏了此类实现细节。不过,如果您查看将Retrofit封装为LiveData
的LiveDataCallAdapter,则可以看到Call.enqueue实际上是异步调用(由Retrofit内部调度)。实际上,如果不使用“分页”功能,则该示例根本不需要
networkIO
Executor
。 “分页”是一个复杂的功能,因此使用显式的FetchNextSearchPageTask
来实现,这是我认为Google示例做得不太好的地方:FetchNextSearchPageTask
不会重用processResponse
的请求解析逻辑(即RepoRepository
),而只是假设它是微不足道的(现在是,但是谁知道 future ...)。此外,没有将合并作业调度到diskIO
Executor
上的安排,这也与其余响应处理不一致。