2017-08-06 69 views
15

我目前检查出以下指南:https://developer.android.com/topic/libraries/architecture/guide.htmlAndroid的体系结构组件网线

的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和本地数据库交互默认使用工作者线程是不好的做法吗?

我也看看下面的演示(GithubBrowserSample):https://github.com/googlesamples/android-architecture-components
这让我困惑,从线程的角度来看。
该演示使用了executors框架,并为networkIO定义了一个包含3个线程的固定池,但是在演示中,仅为一个调用定义了一个工作任务,即FetchNextSearchPageTask。所有其他网络请求似乎都在主线程上执行。

有人可以澄清理由吗?

回答

7

看来你有一些误解。

通常,从Main(UI)线程调用网络永远不会正常,但除非您有大量数据,否则可能无法在主线程中从数据库中获取数据。这就是Google的例子。

1.

的演示使用执行人框架,并限定了与3个线程NETWORKIO固定池,然而,在只有一个工人的任务是为一个呼叫,即,定义FetchNextSearchPageTask演示。

首先,从Java 8开始,您可以使用lambda语法创建一些接口(所谓的“功能接口”)的简单实现。这是NetworkBoundResource发生的事情:在第一个任务(processResponsesaveCallResult

  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))) 
       ); 
      }); 

计划由diskIO提供一个线程Executor,然后从该线程工作的其余部分被安排回主线程。

2.

为什么@MainThread应用于这里NETWORKIO?

所有其它网络的请求似乎是在主线程上执行。

事实并非如此。在主线程上仅创建结果包装即LiveData<ApiResponse<RequestType>>。网络请求在不同的线程上完成。这并不容易看到,因为Retrofit库用于完成所有与网络相关的繁重工作,并很好地隐藏了这些实现细节。尽管如此,如果您看看将Retrofit包装为LiveDataLiveDataCallAdapter,则可以看到使用Call.enqueue,这实际上是一个异步调用(由Retrofit内部调度)。

实际上,如果不是“分页”功能,该示例根本不需要networkIOExecutor。 “分页”是一个复杂的功能,因此它使用明确的FetchNextSearchPageTask来实现,这是我认为Google示例做得不是很好的地方:FetchNextSearchPageTask不会重复使用来自RepoRepository的请求解析逻辑(即processResponse),而只是假设这是微不足道的(现在是这样,但谁知道未来......)。此外,没有将合并作业调度到diskIOExecutor,这与其他响应处理不一致。

+1

感谢您的澄清并指出改进的可能性。我确实误解了注释,即网络请求是通过Retrofit异步执行的,并且仅仅是主线程上的包装。 – Trace