How to know when to request the server for more items using the new android Paging Library of Architecture Components? For example, if I want to implement an endless scrolling where the data is loaded from server how do I know when I have to request more items.
Asked
Active
Viewed 2,898 times
1 Answers
1
I use next class for implementing this feature:
package com.mlsdev.enjoymusic.data.repository;
import android.arch.paging.DataSource;
import android.arch.paging.TiledDataSource;
import android.arch.persistence.room.InvalidationTracker;
import android.support.annotation.NonNull;
import android.support.annotation.WorkerThread;
import android.util.Log;
import com.mlsdev.enjoymusic.data.local.DeezerDatabase;
import com.mlsdev.enjoymusic.data.local.Table;
import java.io.IOException;
import java.util.List;
import java.util.Set;
import retrofit2.Call;
import retrofit2.Response;
/**
* Created by stafievsky on 09.10.17.
*/
public abstract class PagedNetworkBoundResource<ResultType, RequestType> extends TiledDataSource<ResultType> {
private final InvalidationTracker.Observer mObserver;
private DeezerDatabase db;
public PagedNetworkBoundResource(DeezerDatabase db) {
this.db = db;
mObserver = new InvalidationTracker.Observer(Table.States.PLAY_STATE) {
public void onInvalidated(@NonNull Set<String> tables) {
invalidate();
}
};
this.db.getInvalidationTracker().addWeakObserver(mObserver);
}
@Override
public boolean isInvalid() {
db.getInvalidationTracker().refreshVersionsSync();
return super.isInvalid();
}
@Override
public int countItems() {
return DataSource.COUNT_UNDEFINED;
}
@Override
public List<ResultType> loadRange(int startPosition, int count) {
if (startPosition == 0 && count == 20) {
clearDB();
}
fetchFromNetwork(startPosition, count);
return loadFromDb(startPosition, count);
}
public abstract void clearDB();
@WorkerThread
private void fetchFromNetwork(int startPosition, int count) {
if (createCall(startPosition, count) != null)
try {
Response<RequestType> response = createCall(startPosition, count).execute();
if (response.isSuccessful() && response.code() == 200) {
saveCallResult(response.body());
}
} catch (IOException e) {
e.printStackTrace();
}
}
@WorkerThread
protected abstract void saveCallResult(@NonNull RequestType item);
@WorkerThread
protected abstract List<ResultType> loadFromDb(int startPosition, int count);
@WorkerThread
protected abstract Call<RequestType> createCall(int startPosition, int count);
}
And this implementation of this class:
public LiveData<PagedList<ChartAlbumDao.Album>> getAlbums() {
return new LivePagedListProvider<Integer, ChartAlbumDao.Album>() {
@Override
protected DataSource<Integer, ChartAlbumDao.Album> createDataSource() {
return new PagedNetworkBoundResource<ChartAlbumDao.Album, ModelList<ChartAlbumEntity>>(db) {
@Override
public void clearDB() {
}
@Override
protected void saveCallResult(@NonNull ModelList<ChartAlbumEntity> item) {
if (item != null) {
chartAlbumDao.saveAlbums(item.getItems());
}
}
@NonNull
@Override
protected List<ChartAlbumDao.Album> loadFromDb(int startPosition, int count) {
return chartAlbumDao.loadAlbums(count, startPosition);
}
@NonNull
@Override
protected Call<ModelList<ChartAlbumEntity>> createCall(int startPosition, int count) {
return deezerService.getChartAlbums(startPosition, count);
}
};
}
}.create(0, new PagedList.Config.Builder()
.setEnablePlaceholders(false)
.setPageSize(20)
.setInitialLoadSizeHint(20)
.build());
}

Alex
- 138
- 8
-
When data is invalidated, is loadRange called again? If it is the case how do you control that data is not fetched again? If it is not the case how does TiledDataSource know which items to update? – Damia Fuentes Nov 16 '17 at 19:21
-
And in the loadFromDb method, what happens when the database doesn't have the items yet because it's the first time and you are fetching it from network? If loadRange method receive less items than count, paged list understand that is the end of the list. – Damia Fuentes Nov 16 '17 at 19:32
-
Hi, in my implementation I download items from server, save them into local database and after that load range from database. If I don't have network connection - step with remote server will be ignored and data will be loaded from db immediately. In my observer I check if data not null. When DataSource will be invalidated - LivePagedListProvided call `createDataSource()` method, and after that `loadRange(int,int)` will be called again but with saved state of your recyclerView (if you use Adapter from paging library). And Paging library know when we gone to the end of our data source. – Alex Nov 17 '17 at 08:54
-
But once loadRange is called again, the request to server is called again. Do you know if there is any way to handle this using Paging Library methods? (I know I can create a variable handling this but maybe pagin library can do it for me) – Damia Fuentes Nov 19 '17 at 21:49
-
@DamiaFuentes Paging can't do it from the box. Because Paging works only with the abstraction of `DataSource`, so that's why you should create your custom `DataSource` with handling functionality (like cache depend on timestamp). – Alex Nov 20 '17 at 07:17