Search code examples
androidgoogle-cloud-firestorepaginationfirebaseui

FirestorePagingAdapter with additional/different list items crashes due to reuse of keys


I am using the FirestorePagingAdapter to load data using paging from my backend.

My RecyclerView not only hosts the result of the paging request but also data that is displayed depending on the result of the paging (Imagine a Chat/message app where on each new day a label is added to the dataset that the user sees while scrolling).

I am accomplishing like so

  • Use the FirestorePagingAdapter as normal but instead of using its list of items I
  • Implemented a SortedList that takes care of adding "labels" where needed
  • Override the onBindViewHolder so that it still calls super.getItem() to get new items through the paging adapter
  • As there are now labels included we need to find the correct position for the super call. I am doing this just by counting all non paged items and deduction that from the requested position
  • Adding items loaded through the PagingAdapter using addLoadStateListener()

The problem is, that since the Adapter is using Paging 3 I receive an error saying I am reusing keys in my paging. After this, the app just crashes.

The same value was passed as the nextKey in two sequential Pages loaded from a PagingSource

Here is some code. I can include more if needed, but this should be the part where the error is happening

@Override
public void onBindViewHolder(@NonNull RecyclerViewHolder<T, ? extends ViewBinding> holder, int position) {
    try {
        //Needed to page the list, although we use the item from our own list
        super.getItem(getPagingPosition(position));
    } catch (Exception ignore) {
        //If this fails, because there are less items in the list, do not crash, this is fine
        Log.d(TAG, "This is an expected exception");
    } finally {
        holder.bind(getList().get(position));
    }
}

protected int getPagingPosition(int requestedPosition) {
    /* TODO: This  could be optimized, it is used A LOT (on every viewholder bind) and has linear runtime */
    int count = 0;
    for (int i = 0; i < requestedPosition; i++) {
        if (!getPagedClass().isInstance(getList().get(i))) count++;
    }
    Log.d(TAG, "getPagingPosition: "+requestedPosition+" maps to "+(requestedPosition-count));
    return requestedPosition - count;
}

Solution

  • I found the answer. It had nothing to do with my code, but with a bug within firebaseUI. Version 8.0.0 still works where 8.0.1 breaks the paging. There already is an open issue here