2

我正在尝试将选择(https://developer.android.com/reference/androidx/recyclerview/selection/package-summary)与新的分页库(所以分页3)一起使用

使用 Paging 2 是可行的,因为我们使用的是 PagedListAdapter 并且可以与 Selection 库一起使用,但现在使用新的 PagingDataAdapter 我不能让它工作了。

https://developer.android.com/reference/kotlin/androidx/paging/PagingDataAdapter

我们正在丢失 getCurrentList(),setHasStableIds() 现在将返回 UnsupportedOperationException。

因此,如果有人戴上它,我将不胜感激。

4

3 回答 3

2

在新的 Paging3 库中,您可以通过类的snapShot()方法获取当前列表PagingDataAdapter

我最近遇到了同样的密钥提供者问题,所以我实现了一个这样的自定义问题:

class MyItemKeyProvider(private val adapter: MyPagingAdapter) :
    ItemKeyProvider<String>(SCOPE_CACHED) {
    override fun getKey(position: Int): String = adapter.snapshot().items[position].id
    override fun getPosition(key: String): Int = adapter.snapshot().items.indexOfFirst { it.id == key }
于 2021-04-03T01:51:02.657 回答
0

分页 v3 不适用于开箱即用的 recyclerview-selection,因为选择库确实使用了稳定的 id,但分页 v3 不支持它们。

要使它们相互协作,您需要实现自己的稳定 id 密钥提供程序。一旦绑定到回收站视图,它就会保存项目 ID。

class MyStableIdKeyProvider(
    private val mRecyclerView: RecyclerView
) : ItemKeyProvider<Long>(SCOPE_CACHED) {

    init {
        mRecyclerView.addOnChildAttachStateChangeListener(
            object : RecyclerView.OnChildAttachStateChangeListener {
                override fun onChildViewAttachedToWindow(view: View) {
                    onAttached(view)
                }

                override fun onChildViewDetachedFromWindow(view: View) {
                    onDetached(view)
                }
            }
        )
    }

    private val mPositionToKey = mutableMapOf<Int, Long>()
    private val mKeyToPosition = mutableMapOf<Long, Int>()

    fun  /* synthetic access */onAttached(view: View) {
        val holder = mRecyclerView.findContainingViewHolder(view)
        if (holder == null) {
            Log.w(TAG, "Unable to find ViewHolder for View. Ignoring onAttached event.")
            return
        }
        val position = holder.bindingAdapterPosition
        val myItemId = (holder as ItemVH).myItemId
        if (position != RecyclerView.NO_POSITION && myItemId != null) {
            mPositionToKey[position] = myItemId
            mKeyToPosition[myItemId] = position
        }
    }

    fun  /* synthetic access */onDetached(view: View) {
        val holder = mRecyclerView.findContainingViewHolder(view)
        if (holder == null) {
            Log.w(TAG, "Unable to find ViewHolder for View. Ignoring onDetached event.")
            return
        }
        val position = holder.bindingAdapterPosition
        val myItemId = (holder as ItemVH).myItemId
        if (position != RecyclerView.NO_POSITION && myItemId != null) {
            mPositionToKey.remove(position)
            mKeyToPosition.remove(myItemId)
        }
    }

    override fun getKey(position: Int): Long? = mPositionToKey[position]

    override fun getPosition(key: Long): Int = mKeyToPosition[key] ?: RecyclerView.NO_POSITION

    companion object {
        private const val TAG = "MyKeyProvider"
    }
}

您的 ItemVH 必须提供其 ID。您不能使用 getItemId(),因为它总是返回 NO_ID。

class ItemVH(
    view: View,
    selectionTracker: SelectionTracker<Long>,
) : RecyclerView.ViewHolder(view) {

    protected var myItem: MyItem? = null
    val myItemId: Long? get() = myItem?.id

    fun bind(myItem: MyItem, position: Int) {

        this.myItem = myItem
        
        // Put data to item's views
        // ..
    
        // Update checkmark visibility passing `myItemId` to the selection tracker
        if (selectionTracker.isSelected(myItemId)) {
            selectedView.visibility = View.VISIBLE
        } else {
            selectedView.visibility = View.GONE
        }

    }

    fun getItemDetails() = object: ItemDetailsLookup.ItemDetails<Long>() {

        override fun getPosition() = bindingAdapterPosition

        override fun getSelectionKey() = myItemId
    }

    fun clear() {
        myItem = null
    }
}

适配器很简单

class MyItemListAdapter : PagingDataAdapter<MyItem, ItemVH>(DIFF_CALLBACK) {

    lateinit var selectionTracker: SelectionTracker<Long>

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ItemVH {
        val view = LayoutInflater.from(parent.context).inflate(R.layout.item, parent, false)
        return ItemVH(view, selectionTracker)
    }

    override fun onBindViewHolder(viewHolder: ItemVH, position: Int) {
        val myItem = getItem(position)
        if (myItem == null) {
            viewHolder.clear()
        } else {
            viewHolder.bind(myItem, position)
        }
    }
    
    companion object {
        private val DIFF_CALLBACK = object :
            DiffUtil.ItemCallback<MyItem>() {
                // ...
        }
    }
}

构建选择跟踪器需要项目详细信息查找:

class ItemListLookup(
    private val rv: RecyclerView
) : ItemDetailsLookup<Long>() {

    override fun getItemDetails(e: MotionEvent): ItemDetails<Long>? {
        val view = rv.findChildViewUnder(e.x, e.y)
        if(view != null) {
            return (rv.getChildViewHolder(view) as ItemVH)
                .getItemDetails()
        }
        return null
    }
}

片段联系在一起

class MyFragment : Fragment() {

    private val adapter = MyItemListAdapter()
    
    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)

        view.recyclerView.adapter = adapter

        adapter.selectionTracker = SelectionTracker.Builder<Long>(
            "item_selection",
            view.recyclerView,
            MyStableIdKeyProvider(view.recyclerView),
            ItemListLookup(view.recyclerView),
            StorageStrategy.createLongStorage()
        ).build()

        adapter.selectionTracker.addObserver(object : SelectionTracker.SelectionObserver<Long>() {
            override fun onItemStateChanged(key: Long, selected: Boolean) {
                // handle selection change event
            }

            override fun onSelectionCleared() {
                // clear selection
            }
        })
        
        // ...
    }
}
于 2021-11-23T00:23:38.327 回答
0

如果您已经将它与 Paging 2 一起使用,我建议您从实现自己的ItemKeyProvider<K>. StableIdKeyProvider无法使用打包的,因为它需要启用稳定的 ID,并且正如您所说,稳定的 ID 不支持PagingDataAdapter.

于 2021-03-11T17:44:57.083 回答