Подгрузка данных с API+DB используя offset и limit

222
14 марта 2018, 05:40

У меня есть вот такой метод API

@GET("apiV2/Friend/GetAllFriendsForUser")
Observable<Response<List<Friend>>> getAllFriendsForUser(@Query("userId") String userId, @Query("take") int take, @Query("skip") int skip);

с помощью которого я динамически подгружаю объекты.

До того как появились аргументы skip и take проблем небыло, потому что я использовал следующий класс

public abstract class NetworkBoundResource<ResultType, RequestType> {
    private static final String TAG = NetworkBoundResource.class.getSimpleName();
    private final MediatorLiveData<Resource<ResultType>> result = new MediatorLiveData<>();
    // Called to save the result of the API response into the database
    @WorkerThread
    protected abstract void saveCallResult(@NonNull RequestType data);
    // 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<Observable<Response<RequestType>>> createCall();
    // Called when the fetch fails. The child class may want to reset components
    // like rate limiter.
    @MainThread
    protected abstract void onFetchFailed(Throwable throwable);
    private CompositeDisposable compositeDisposable = new CompositeDisposable();

    @MainThread
    protected NetworkBoundResource() {
        result.setValue(Resource.loading(null));
        LiveData<ResultType> dbSource = loadFromDb();
        result.addSource(dbSource, data -> {
            result.removeSource(dbSource);
            if (shouldFetch(data)) {
                fetchFromNetwork(dbSource);
            } else {
                result.addSource(dbSource,
                        newData -> {
                            if (newData == null) {
                                NetworkBoundResource.this.result.setValue(Resource.empty());
                            } else {
                                NetworkBoundResource.this.result.setValue(Resource.success(newData));
                            }
                        });
            }
        });
    }
    private void fetchFromNetwork(final LiveData<ResultType> dbSource) {
        LiveData<Observable<Response<RequestType>>> apiResponse = createCall();
        // we re-attach dbSource as a new source,
        // it will dispatch its latest value quickly
        result.addSource(dbSource, newData -> result.setValue(Resource.loading(newData)));
        result.addSource(apiResponse, observer -> {
            result.removeSource(apiResponse);
            result.removeSource(dbSource);
            //return if observable is null
            if (observer == null) return; 
            observer
                    .subscribeOn(Schedulers.io())
                    .observeOn(AndroidSchedulers.mainThread())
                    .unsubscribeOn(Schedulers.io())
                    .doOnSubscribe(disposable -> compositeDisposable.add(disposable))
                    .subscribe(
                            this::saveResultAndReInit,
                            throwable -> {
                                onFetchFailed(throwable);
                                //put error to result
                                result.setValue(Resource.error(throwable));
                                //put cached data to result if it exist
                                result.addSource(dbSource, newData -> {
                                    if (newData==null){
                                        result.setValue(Resource.empty());
                                    }else {
                                        result.setValue(Resource.success(newData));
                                    }
                                });
                            }
                    );
        });
    }
    @MainThread
    private void saveResultAndReInit(Response<RequestType> response) {
        new UpdateAsync(response).execute();
    }
    public final LiveData<Resource<ResultType>> getAsLiveData() {
        return result;
    }
    @SuppressLint("StaticFieldLeak")
    class UpdateAsync extends AsyncTask<Void, Void, Void> {
        private Response<RequestType> response;
        UpdateAsync(Response<RequestType> response) {
            this.response = response;
        }
        @Override
        protected Void doInBackground(Void... voids) {
            RequestType body = response.body();
            if (body != null) NetworkBoundResource.this.saveCallResult(body);
            return null;
        }
        @Override
        protected void onPostExecute(Void aVoid) {
            // 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.
            //if database value is null just send empty result
            //otherwise return existing value
            LiveData<ResultType> resultTypeLiveData = loadFromDb();
            NetworkBoundResource.this.result.addSource(resultTypeLiveData,
                    newData -> {
                        if (newData == null) {
                            NetworkBoundResource.this.result.setValue(Resource.empty());
                        } else {
                            NetworkBoundResource.this.result.setValue(Resource.success(newData));
                        }
                    });
        }
    }
}

и использовал его следующим образом

public LiveData<Resource<List<MessageObjectView>>> getMessageObjectViews(String userId) {
    return new NetworkBoundResource<List<MessageObjectView>, List<MessageObjectView>>() {
        @Override
        protected void saveCallResult(@NonNull List<MessageObjectView> data) {
            dao.insertAllMessageObjectView(data);
        }
        @Override
        protected boolean shouldFetch(@Nullable List<MessageObjectView> data) {
            return true;
        }
        @NonNull
        @Override
        protected LiveData<List<MessageObjectView>> loadFromDb() {
            return dao.getAllMessageObjectViewAsLiveData();
        }
        @NonNull
        @Override
        protected LiveData<Observable<Response<List<MessageObjectView>>>> createCall() {
            Observable<Response<List<MessageObjectView>>> apiResponse = api.getMessageObjectsObs(userId);
            MutableLiveData<Observable<Response<List<MessageObjectView>>>> liveData = new MutableLiveData<>();
            liveData.setValue(apiResponse);
            return liveData;
        }
        @Override
        protected void onFetchFailed(Throwable throwable) {
            Log.wtf(TAG, "Fetch list " + MessageObjectView.class.getName() + " failed. " + throwable.getMessage());
        }
    }.getAsLiveData();
}

Т.е. таким образом я мог всегда подтянуть актуальные данные из сети, сохранив их в базу данных и вернув в методже уже данные сохраненные в БД.

Но у меня данный способ работает когда я запрашиваю какие то конкретные данные, а когда мне нужно добывать данные через offset, limit - уменя возникаю проблемы.

Пробовал смотреть в сторону разлиных DataSource используя Paging Library но так не не с мог для себя найти решение как это реализовать в случае когда у меня "единственные источник данных" ?

Вопрос, как или с помощью чего можно реализовать нужную для меня схему работы (подрузка из API с offset, limit -> сохранение данных в БД -> вернуть результат для данного запроса из БД)

READ ALSO
Десериализация JSON: нечитаемые символы

Десериализация JSON: нечитаемые символы

Одно приложение стучится в другое и получает REST-ответ в виде JSON

151
как работать с txt с помощью jquery

как работать с txt с помощью jquery

здраствуйте! имеется переменная, так же имеется файл isnotvaluetxt с множеством числовых и буквенных выражений которые недопустимы в переменной...

239
Помогите разобраться с ошибкой D3

Помогите разобраться с ошибкой D3

Пытаюсь написать приложение для построения графиковСкопировал код из примера и все работало

251