So i've been reading on Android's new paging library. Specifically, I'm trying load a list of never-ending images (with Glide) using a recyclerview with adapter, viewmodel, and data source (backed by retrofit network calls).
Here's the base code:
// inside my activity
PhotosListAdapter adapter = new PhotosListAdapter(getApplicationContext());
PhotosViewModel viewModel = ViewModelProviders.of(this).get(PhotosViewModel.class);
viewModel.getPhotosList().observe(this, adapter::submitList);
RecyclerView recyclerView = findViewById(R.id.main_recycler_view);
recyclerView.setLayoutManager(new LinearLayoutManager(this));
recyclerView.setHasFixedSize(true);
recyclerView.setAdapter(adapter);
...
// My adapter code:
@Override
public void onBindViewHolder(@NonNull PhotoViewHolder photoViewHolder, int i) {
Photo photo = getItem(i);
if (photo != null) {
mGlide.load(photo.previewURL).into(photoViewHolder.mPhotoImageView);
}
}
private static final DiffUtil.ItemCallback<Photo> DIFF_CALLBACK = new DiffUtil.ItemCallback<Photo>() {
@Override
public boolean areItemsTheSame(@NonNull Photo photo, @NonNull Photo other) {
return photo.id == other.id; // these are just ints
}
@Override
public boolean areContentsTheSame(@NonNull Photo photo, @NonNull Photo other) {
return photo.previewURL.equals(other.previewURL); // this is just a string
}
};
...
// My View Model code:
private LiveData<PagedList<Photo>> mData;
public PhotosViewModel() {
PhotosDataSource photosDataSource = new PhotosDataSource();
mData = new LivePagedListBuilder<>(new DataSource.Factory<Integer, Photo>() {
@Override
public DataSource<Integer, Photo> create() {
return photosDataSource;
}
}, 25).build();
}
public LiveData<PagedList<Photo>> getPhotosList() {
return mData;
}
// My Data Source:
Call<SearchResult> search = mPixabayService.search(PixabayApi.api_key, "photo", 1, params.requestedLoadSize, true);
search.enqueue(new Callback<SearchResult>() {
@Override
public void onResponse(Call<SearchResult> call, Response<SearchResult> response) {
if (response.isSuccessful()) {
SearchResult body = response.body();
callback.onResult(body.hits, null, 2);
}
// TODO add error cases
}
@Override
public void onFailure(Call<SearchResult> call, Throwable t) {
}
});
@Override
public void loadAfter(@NonNull LoadParams params, @NonNull LoadCallback callback) {
Call<SearchResult> result = mPixabayService.search(PixabayApi.api_key, "photo", (Integer)params.key, params.requestedLoadSize, true);
result.enqueue(new Callback<SearchResult>() {
@Override
public void onResponse(Call<SearchResult> call, Response<SearchResult> response) {
if (response.isSuccessful()) {
List<Photo> hits = response.body().hits;
callback.onResult(hits, (Integer)params.key + 1);
}
}
@Override
public void onFailure(Call<SearchResult> call, Throwable t) {
}
});
}
However, I've built the same example just using an adapter of static list of items, and that seems to scroll much smoother on my emulator. Is there something i'm missing in my code?
Here are my suspicions for the factors behind what could be making it worse:
- does
recyclerview.setHasFixedSize(true)
make sense in this case? (i did also notice images are different sizes when i scroll down and then come back to the original image - is there a way to prevent this?) - is this because of something weird in
DIFF_CALLBACK
? i actually don't really know the purpose of this class that well viewModel.getPhotosList().observe(this, adapter::submitList);
is expected to be slower because it should invalidate the list (vs a static list); however, is this expected to cause like a 5x lag??!- i notice that i'm flinging quite quickly on the emulator, which doesn't seem to be a problem on a static recyclerview; however, does LivePage do something different for their fling detection? the screen seems to go crazy when i fling. In other words, is my perceived "jagged performance from paging library" only because i'm flinging up and down (as opposed just slow scrolling up and down) ?
- Am i just flat out missing a key config setting somewhere?