Как интегрировать библиотеку подкачки Android с NetworkBoundResource

Мое приложение использует библиотеку архитектурных компонентов Android и отображает список элементов получен из API-интерфейса REST с разбивкой на страницы с эффектом бесконечной прокрутки.

Я пытаюсь использовать библиотеку подкачки в сочетании с NetworkBoundResource, чтобы при прокрутке списка , следующие элементы извлекаются из базы данных и отображаются, если они существуют, и одновременно вызывается API для обновления элементов в БД.

Я не смог найти ни одного примера сосуществования этих двух паттернов.

Вот ДАО:

@Query("SELECT * FROM items ORDER BY id DESC")
LivePagedListProvider<Integer,MyItem> loadListPaginated();

Вот моя реализация NetworkBoundResource:

public class PagedListNetworkBoundResource extends NetworkBoundResource<PagedList<MyItem>, List<MyItem>> {

    @Override
    protected void saveCallResult(@NonNull List<MyItem> items) {
        // Inserting new items into DB
        dao.insertAll(items);
    }

    @Override
    protected boolean shouldFetch(@Nullable PagedList<MyItem> data) {
        return true;
    }

    @NonNull
    @Override
    protected LiveData<PagedList<MyItem>> loadFromDb() {
        return Transformations.switchMap(dao.loadListPaginated().create(INITIAL_LOAD_KEY, PAGE_SIZE),
                new Function<PagedList<MyItem>, LiveData<List<MyItem>>>() {

            @Override
            public LiveData<PagedList<MyItem>> apply(final PagedList<MyItem> input) {
                // Here I must load nested objects, attach them, 
                // and return the fully loaded items
            }
        });
    }

    @NonNull
    @Override
    protected LiveData<ApiResponse<List<MyItem>>> createCall() {
        // I don't get the current paged list offset to perform a call to the API
        return ...;
    }
}

person mlumeau    schedule 28.11.2017    source источник


Ответы (2)


Я также много искал о NetworkBoundResource и пришел к выводу, что NetworkBoundResource и Paging Lib не связаны друг с другом. У них обоих есть собственный функционал

Согласно статье Google о библиотеке подкачки https://developer.android.com/topic/libraries/architecture/paging.html

1. для загрузки данных из локальной базы данных вам нужно использовать DataSource My Dao

@Dao
public interface UserDao {
    @Insert(onConflict = OnConflictStrategy.REPLACE)
    void insert(User... user);
    @Insert(onConflict = OnConflictStrategy.REPLACE)
    void insert(List<User> users);

    @Query("Select * from User ")
    public abstract DataSource.Factory<Integer,User> getList();
}

2. затем запрашивая данные из сети, нам нужно реализовать класс BoundaryCallback с LivePagedListBuilder

public class UserBoundaryCallback extends PagedList.BoundaryCallback<User> {
    public static final String TAG = "ItemKeyedUserDataSource";
    GitHubService gitHubService;
    AppExecutors executors;
    private MutableLiveData networkState;
    private MutableLiveData initialLoading;
    public UserBoundaryCallback(AppExecutors executors) {
        super();
        gitHubService = GitHubApi.createGitHubService();
        this.executors = executors;
        networkState = new MutableLiveData();
        initialLoading = new MutableLiveData();
    }
    public MutableLiveData getNetworkState() {
        return networkState;
    }

    public MutableLiveData getInitialLoading() {
        return initialLoading;
    }

    @Override
    public void onZeroItemsLoaded() {
        //super.onZeroItemsLoaded();
        fetchFromNetwork(null);
    }

    @Override
    public void onItemAtFrontLoaded(@NonNull User itemAtFront) {
        //super.onItemAtFrontLoaded(itemAtFront);
    }

    @Override
    public void onItemAtEndLoaded(@NonNull User itemAtEnd) {
        // super.onItemAtEndLoaded(itemAtEnd);
        fetchFromNetwork(itemAtEnd);
    }
    public void fetchFromNetwork(User user) {
        if(user==null) {
            user = new User();
            user.userId = 1;
        }
        networkState.postValue(NetworkState.LOADING);
        gitHubService.getUser(user.userId,20).enqueue(new Callback<List<User>>() {
            @Override
            public void onResponse(Call<List<User>> call, Response<List<User>> response) {
                executors.diskIO().execute(()->{
                    if(response.body()!=null)
                        userDao.insert(response.body());
                        networkState.postValue(NetworkState.LOADED);
                });
            }

            @Override
            public void onFailure(Call<List<User>> call, Throwable t) {
                String errorMessage;
                errorMessage = t.getMessage();
                if (t == null) {
                    errorMessage = "unknown error";
                }
                Log.d(TAG,errorMessage);
                networkState.postValue(new NetworkState(Status.FAILED, errorMessage));
            }
        });
    }

}

3. Мой код виртуальной машины для загрузки данных из БД + сеть

public class UserViewModel extends ViewModel {

    public LiveData<PagedList<User>> userList;
    public LiveData<NetworkState> networkState;
    AppExecutors executor;
    UserBoundaryCallback userBoundaryCallback;

    public UserViewModel() {
        executor = new AppExecutors();
    }
    public void init(UserDao userDao)
    {
        PagedList.Config pagedListConfig =
                (new PagedList.Config.Builder()).setEnablePlaceholders(true)
                        .setPrefetchDistance(10)
                        .setPageSize(20).build();
        userBoundaryCallback = new UserBoundaryCallback(executor);
        networkState = userBoundaryCallback.getNetworkState();
        userList = (new LivePagedListBuilder(userDao.getList(), pagedListConfig).setBoundaryCallback(userBoundaryCallback))
                .build();
    }
}
person Amar Ubhe    schedule 24.01.2018

Это предполагает, что каждый элемент в обратном вызове содержит индекс/смещение. Обычно это не так — элементы могут содержать только идентификаторы.

person Chris    schedule 25.01.2018