У меня есть вот такой метод 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 -> сохранение данных в БД -> вернуть результат для данного запроса из БД)
Айфон мало держит заряд, разбираемся с проблемой вместе с AppLab
Перевод документов на английский язык: Важность и ключевые аспекты
Одно приложение стучится в другое и получает REST-ответ в виде JSON
здраствуйте! имеется переменная, так же имеется файл isnotvaluetxt с множеством числовых и буквенных выражений которые недопустимы в переменной...
Пытаюсь написать приложение для построения графиковСкопировал код из примера и все работало