如果计算的是从上一次更改以来的更改,则根本不会报这个错误,报这个错误是因为计算的差异不是从上一次更改以来的更改
把datas.add(temp)注释就会报这个错误
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_diff_util_test001)
val btnChange = findViewById<Button>(R.id.btn_change)
val recyclerView = findViewById<RecyclerView>(R.id.recycler_view)
val datas = mutableListOf<String>()
for(i in 1..3){
datas.add("item $i")
}
val adapter = DiffUtilsTest001Adapter(datas, this)
recyclerView.adapter = adapter
recyclerView.layoutManager = LinearLayoutManager(this)
val newDatas = mutableListOf<String>()
datas.forEach { str ->
newDatas.add(str)
}
var index = 1000
btnChange.setOnClickListener {
val temp = "new item ${index++}"
newDatas.add(temp)
adapter.datas = newDatas
//理论上应该计算从上一次更改以来的更改
//如果计算的不是从上一次更改以来的更改,则将dispatchUpdatesTo()发送到adapter,会有问题
//比如报Inconsistency detected Invalid view holder adapter position这个错误
val res = DiffUtil.calculateDiff(MyDiffCallback(datas, newDatas), false)
res.dispatchUpdatesTo(adapter)
//也加入到datas,免得下次点击时,datas和newDatas差距过大,刷新的内容过大
//不加进去还会造成 Inconsistency detected Invalid view holder adapter position这个bug
//新旧内容的差距过大会造成 Inconsistency detected Invalid view holder adapter position这个bug
datas.add(temp)
}
}
一种处理方法(就算计算的不是从上次更改以来的更改,也不会报错)。思路就是自定义一个LayoutManager,然后把异常吃掉
class WrapContentLinearLayoutManager : LinearLayoutManager {
constructor(context: Context?) : super(context)
constructor(context: Context?, orientation: Int, reverseLayout: Boolean) : super(
context,
orientation,
reverseLayout
)
constructor(
context: Context?,
attrs: AttributeSet?,
defStyleAttr: Int,
defStyleRes: Int
) : super(context, attrs, defStyleAttr, defStyleRes) {
}
override fun onLayoutChildren(recycler: RecyclerView.Recycler, state: RecyclerView.State) {
try {
super.onLayoutChildren(recycler, state)
} catch (e: IndexOutOfBoundsException) {
Log.e("Error", "IndexOutOfBoundsException in RecyclerView happens")
}
}
}