Я использую
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, который, кажется, управляет этим делом, но он так долго пересматривается, что я спрашиваю здесь, удалось ли кому-то это сделать или узнать, можно ли это сделать таким или другим способом.