Работа с пользовательскими ListUpdateCallback и PagedList из RecyclerView - PullRequest
0 голосов
/ 08 мая 2018

Я использую

android.arch.paging:runtime:1.0.0-rc1
android.arch.persistence.room:runtime:1.1.0-rc1

для извлечения PagedList через LiveData из источника данных, созданного простым выбором (SELECT * FROM data where isOn = 1)

Этот источник данных наблюдается и отправляет свой 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)
    }

}

В большинстве случаев работает хорошо, но я не могу понять конкретный случай: Когда у меня

1 - A
2 - B
3 - C
4 - D
5 - E
6 - F

Допустим, мое текущее состояние (состояние с isOn в true):

2 - B
3 - C
4 - D

Я меняю состояние на:

1 - A
4 - D
5 - E

При этом пользователь получает ListUpdateCallback (на данный момент я улавливаю ошибки):

I/onInserted: position 3 and count 1
I/onRemoved: position 0 and count 2
I/onInserted: position 0 and count 1

Логика, вероятно, должна делать:

Insert E at offset 3
Delete 2 items (B C) at offset 0
Insert A at offset 0

Как видите, параметры вызова соответствуют этой логике. Однако getItem, выполняющий итерацию в экземпляр PagedStorage, который поддерживает AsyncPagedListDiffer.getItem, полагается на ожидаемый список:

1 - A
4 - D
5 - E

Поэтому getItem (3) сгенерирует исключение IndexOutOfBoundsException.

Итак, моя проблема: откуда мне знать, что мне нужно добавить пункт 2 в позицию 3 в этом случае? Я думаю, что что-то упустил, но я не знаю, является ли это проблемой дизайна или я допустил ошибку в моей логике вставки. Я пытался заглянуть в код RecyclerView, который, кажется, управляет этим делом, но он так долго пересматривается, что я спрашиваю здесь, удалось ли кому-то это сделать или узнать, можно ли это сделать таким или другим способом.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...