Ответ 1
Кажется, у вас есть несколько заблуждений.
Как правило, никогда не удастся позвонить в сеть из потока Main (UI), но если у вас много данных, возможно, будет нормально извлекать данные из БД в основном потоке. И это то, что делает пример Google.
1.
Демонстрация использует структуру исполнителей и определяет фиксированный пул с 3 потоками для networkIO, однако в демо только рабочая задача определена для одного вызова, то есть FetchNextSearchPageTask.
Прежде всего, поскольку Java 8 вы можете создать простую реализацию некоторых интерфейсов (так называемых "функциональных интерфейсов" ), используя синтаксис лямбда. Это то, что происходит в 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
, а затем из этого потока остальная часть работы будет возвращена в основной поток.
2.
Почему @MainThread применяется здесь для networkIO?
и
Все остальные сетевые запросы, похоже, выполняются в основном потоке.
Это не так. В основном потоке создается только обертка результата, т.е. LiveData<ApiResponse<RequestType>>
. Сетевой запрос выполняется в другом потоке. Это не легко увидеть, потому что библиотека Retrofit используется для выполнения всей связанной с сетью тяжелой атлетики, и она прекрасно скрывает такие детали реализации. Тем не менее, если вы посмотрите на LiveDataCallAdapter, который обертывает Retrofit в LiveData
, вы можете видеть, что Используется Call.enqueue, который фактически является асинхронным вызовом (запланировано внутренним образом с помощью Retrofit).
На самом деле, если не для функции "разбиения на страницы", для примера не потребуется networkIO
Executor
. "Pagination" - сложная функция, и поэтому она реализуется с использованием явного FetchNextSearchPageTask
, и это место, где я думаю, что пример Google выполняется не очень хорошо: FetchNextSearchPageTask
не использует повторную логику запроса (т.е. processResponse
) из RepoRepository
, а просто предполагает, что это тривиально (что сейчас, но кто знает о будущем...). Также нет планирования задания слияния на diskIO
Executor
, которое также не согласуется с остальной частью обработки ответа.