使用 RecyclerView 中的自定义 ListUpdateCallback 和 PagedList

Kay*_*rnt 5 android android-room android-architecture-components

我正在使用

android.arch.paging:runtime:1.0.0-rc1
android.arch.persistence.room:runtime:1.1.0-rc1
Run Code Online (Sandbox Code Playgroud)

通过 LiveData 从一个由简单 select ( SELECT * FROM data where isOn = 1)构建的 DataSource 中检索 PagedList

观察此数据源并将其 PagedList 提交给以下自定义适配器,该适配器专用于使用当前的“isOn”列表更新抽屉:

data class Data(@PrimaryKey(autoGenerate = true)
                    var id: Int = 0,
                    var name: String? = null,
                    var isOn: Boolean? = null)

class ApiDrawerAdapter(drawer: Drawer) {

    private val lastItemPositionOffset = drawer.drawerItems.size

    val drawerItems = arrayListOf<PrimaryDrawerItem>()

    private val listUpdateCallback = object : ListUpdateCallback {
        override fun onChanged(position: Int, count: Int, payload: Any?) {
            for (i in position until position + count) {
                val name = getItem(i)?.name ?: "Unnamed data"
                val primaryDrawerItemOpt: PrimaryDrawerItem? = drawerItems.getOrNull(i)
                primaryDrawerItemOpt?.let { pdi -> drawerItems.remove(pdi) }
                primaryDrawerItemOpt?.identifier?.let { id -> drawer.removeItem(id) }
                val primaryDrawerItem = (primaryDrawerItemOpt ?: PrimaryDrawerItem()).withName(name)
                drawer.setItemAtPosition(primaryDrawerItem, i + lastItemPositionOffset)
                drawerItems.set(i, primaryDrawerItem)
            }
        }

        override fun onMoved(fromPosition: Int, toPosition: Int) {
            throw Exception("Not implemented")
        }

        override fun onInserted(position: Int, count: Int) {
                for (i in position until position + count) {
                    val name = getItem(i)?.name ?: "Unnamed data"
                    val primaryDrawerItem = PrimaryDrawerItem().withName(name)
                    drawer.setItemAtPosition(primaryDrawerItem, i + lastItemPositionOffset)
                    drawerItems.add(i, primaryDrawerItem)
                }
        }

        override fun onRemoved(position: Int, count: Int) {
            for (i in position until position + count) {
                val primaryDrawerItemOpt: PrimaryDrawerItem? = drawerItems.getOrNull(position)
                primaryDrawerItemOpt?.let { pdi -> drawerItems.remove(pdi) }
                primaryDrawerItemOpt?.identifier?.let { id -> drawer.removeItem(id) }
            }
        }
    }

    private val itemCallback: DiffUtil.ItemCallback<Data> = object : DiffUtil.ItemCallback<Data>() {
        override fun areItemsTheSame(oldItem: Data, newItem: Data): Boolean {
            return oldItem.id == newItem.id
        }

        override fun areContentsTheSame(oldItem: Data, newItem: Data): Boolean {
            return oldItem == newItem
        }
    }
    private val asyncDifferConfig = AsyncDifferConfig.Builder<Data>(itemCallback).build()

    private val mDiffer = AsyncPagedListDiffer(listUpdateCallback, asyncDifferConfig)

    init {
        val mListener = AsyncPagedListDiffer.PagedListListener<Data> { }

        mDiffer.mListener = mListener
    }

    fun submitList(pagedList: PagedList<Data>) {

        mDiffer.submitList(pagedList)
    }

    protected fun getItem(position: Int): Data? {
        return mDiffer.getItem(position)
    }

}
Run Code Online (Sandbox Code Playgroud)

它在大多数情况下运行良好,但我无法确定具体情况:当我有

1 - A
2 - B
3 - C
4 - D
5 - E
6 - F
Run Code Online (Sandbox Code Playgroud)

假设我当前的状态(isOn 为 true 的状态)是:

2 - B
3 - C
4 - D
Run Code Online (Sandbox Code Playgroud)

我正在将状态更改为:

1 - A
4 - D
5 - E
Run Code Online (Sandbox Code Playgroud)

这样做,自定义接收 ListUpdateCallback (此时我正在捕获错误):

I/onInserted: position 3 and count 1
I/onRemoved: position 0 and count 2
I/onInserted: position 0 and count 1
Run Code Online (Sandbox Code Playgroud)

逻辑可能应该这样做:

Insert E at offset 3
Delete 2 items (B C) at offset 0
Insert A at offset 0
Run Code Online (Sandbox Code Playgroud)

如您所见,调用参数与该逻辑匹配。然而,迭代到支持 AsyncPagedListDiffer.getItem 的 PagedStorage 实例的 getItem 依赖于预期的列表:

1 - A
4 - D
5 - E
Run Code Online (Sandbox Code Playgroud)

因此 getItem(3) 将抛出 IndexOutOfBoundsException。

所以我的问题是:在这种情况下,我怎么知道我需要将项目 2 添加到位置 3?我想我遗漏了一些东西,但我不知道这是设计问题还是我在插入逻辑中犯了错误。我试图查看似乎管理该案例的 RecyclerView 代码,但审查时间太长了,我在这里询问是否有人设法完成它或知道它是否可以通过这种方式(或其他方式)完成。