简体   繁体   中英

Why does this example of paging library perform much worse than just a recycler view?

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:

  1. 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?)
  2. is this because of something weird in DIFF_CALLBACK ? i actually don't really know the purpose of this class that well
  3. 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??!
  4. 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) ?
  5. Am i just flat out missing a key config setting somewhere?

Of course a static list is going to be smoother- far less overhead. If its an actual possibility, go with that. You use a paged list when either holding the entire list in memory is not feasible, or when requesting the entire list from the data source (especially remote ones) would be too time consuming/costly.

1)Depends on your UI. The fixed size is the size it takes on screen, not the size of the list. Generally this is true for full sized lists or lists that don't grow/shrink with contents.

2)DiffUtil and its callback have nothing to do with paging, they pre-existed the paging library. They diff lists around changes to make the most efficient calls to the adapter possible, rather than doing an entire notifyDataSetChanged. But they do take up some time in doing so. Its important that this be correct, otherwise you'll either miss notifications, or use less efficient ones.

3)Expected to be slower vs what? But anywhere you're using an observable you will see a slow down, you're posting messages between threads potentially. That's one of the reasons they're horribly misused a lot of the time, people don't understand what they actually do. Yes, a 5x slowdown doesn't seem unlikely, especially if you end up using the less efficent notifyDataSetChanged rather than more exact notifies.

4)When you fling, you load a lot more items more quickly. Which could cause more remote loads. So if you're going to have an issue, it will be when you fling. Generally you want to preload on a separate thread far enough in advance it isn't an issue. Have your tried playing with the page size and prefetch distance?

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM