2017-08-06 66 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