AdapterDelegates icon indicating copy to clipboard operation
AdapterDelegates copied to clipboard

Jetpack Paging 3 support

Open krossovochkin opened this issue 4 years ago • 5 comments

Hi,

Paging 3 is a complete rework of previous paging solution by Google. Adapter delegates have support for version 2.

Would be good to have support for version 3 as well. Though version 3 is just announced and is currently in alpha, still would be good to have some initial support.

https://developer.android.com/topic/libraries/architecture/paging/v3-overview

Thank you

krossovochkin avatar Jun 13 '20 07:06 krossovochkin

I've tried to make an adapter, similar to what there is for v2 paging. But faced an issue that I couldn't find a way to extract "currentList" data from the PagingDataAdapter (or it's differ). Seems like paging lib goes directly into "1 view type" per whole adapter (with separate implementation for header and footer) and doesn't expose list directly.

So, workarounded that in the following way:

class PagingDataDelegationAdapter<T : Any>(
    diffCallback: DiffUtil.ItemCallback<T>,
    vararg delegates: AdapterDelegate<List<T>>
) : PagingDataAdapter<T, RecyclerView.ViewHolder>(diffCallback) {

    private val delegatesManager: AdapterDelegatesManager<List<T>> = AdapterDelegatesManager()

    init {
        delegates.forEach { delegatesManager.addDelegate(it) }
    }

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
        return delegatesManager.onCreateViewHolder(parent, viewType)
    }

    override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
//// here directly taking item and passing it to onBindViewHolder (wrapping into list to conform the adapterdelegates API)
        val item =
            getItem(position) // Internally triggers loading items around items around the given position
        val delegate = delegatesManager.getDelegateForViewType(holder.itemViewType)
            ?: throw NullPointerException(
                "No delegate found for item at position = "
                        + position
                        + " for viewType = "
                        + holder.itemViewType
            )

        delegate.onBindViewHolder(listOf(item as T), 0, holder, emptyList())
    }

    override fun getItemViewType(position: Int): Int {
///// here just return whatever as multiple view types are not supported
        return 0
    }

    override fun onViewRecycled(holder: RecyclerView.ViewHolder) {
        delegatesManager.onViewRecycled(holder)
    }

    override fun onFailedToRecycleView(holder: RecyclerView.ViewHolder): Boolean {
        return delegatesManager.onFailedToRecycleView(holder)
    }

    override fun onViewAttachedToWindow(holder: RecyclerView.ViewHolder) {
        delegatesManager.onViewAttachedToWindow(holder)
    }

    override fun onViewDetachedFromWindow(holder: RecyclerView.ViewHolder) {
        delegatesManager.onViewDetachedFromWindow(holder)
    }
}

Could be good if someone also took a look at that. Maybe there is something that needs to be updated in the API of adapterdelegates, or maybe something can be incorporated as a feedback to Jetpack team (so they might expose "currentList" or something similar in the public api)

Thank you

krossovochkin avatar Jun 14 '20 08:06 krossovochkin

Do you want to send me a PR for this?

sockeqwe avatar Jun 20 '20 11:06 sockeqwe

Hi @sockeqwe

I'd be happy to help with that, but I have a feeling that it would be not that easy. What I've posted above is definitely a hack and I don't think it should be added like this into lib.

Main issue I see is in AdapterDelegate interface. It is low-level interface in the whole lib, and it defines everything in terms of adapter's underlying list and position.

public abstract class AdapterDelegate<T> {

    protected abstract boolean isForViewType(@NonNull T items, int position);

    protected abstract void onBindViewHolder(@NonNull T items, int position,
                                             @NonNull RecyclerView.ViewHolder holder, @NonNull List<Object> payloads);

Here items are meant as "datasource". Though all of the implementations in library seem to rely on List to be a datasource.

In Paging 3 lists are not exposed and not used inside. There are NullPaddedLists, but it is separate interface which doesn't relate to general List interface.

Instead there are methods to get itemCount and item by position. It is technically possible to create some Provider interface and base solution on AdapterDelegate<Provider<T>>. But this would require to create whole new branch of the classes (including bindings etc)

Another workaround would be to make method "getCurrentList" as in Paging2 adapter based on getItem(position) and getItemCount. But that would have bad performance I guess.

So, I'd be happy to help, but atm I'm a bit stuck on what is the right direction.

krossovochkin avatar Jun 21 '20 12:06 krossovochkin

Hello! @sockeqwe Do you have plans to support the paging 3 officially in the nearest future?

PavelSidyakin avatar Oct 10 '20 09:10 PavelSidyakin

Hello, @sockeqwe I would be very happy if Paging 3 support becomes available in the near future.

suhocki avatar Nov 27 '20 19:11 suhocki