java.lang.IndexOutOfBoundsException:检测到不一致。使用 DiffUtil 时视图持有者适配器无效
java.lang.IndexOutOfBoundsException: Inconsistency detected. Invalid view holder adapter when using DiffUtil
下面是一个适配器 class,用于在回收站视图中加载所有图书项目。使用 DiffUtils 以便整个列表不会收到通知。
class BooksAdapter(var mContext: Context) : RecyclerView.Adapter<BooksAdapter.BooksViewHolder>() {
var books: List<BookTable> = ArrayList()
set(value) {
val result = DiffUtil.calculateDiff(BookListDiffCallBacks(ArrayList(value), ArrayList(books)))
field = value
result.dispatchUpdatesTo(this)
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): BooksViewHolder {
val binding = DataBindingUtil.inflate<ItemBookBinding>(LayoutInflater.from(mContext), R.layout.item_book, parent, false)
return BooksViewHolder(binding)
}
override fun getItemCount(): Int {
return books.size
}
override fun onBindViewHolder(holder: BooksViewHolder, position: Int) {
holder.setData(books[position])
}
inner class BooksViewHolder(var binding: ItemBookBinding) : RecyclerView.ViewHolder(binding.root) {
fun setData(bookTable: BookTable) {
binding.book = bookTable
}
}
}
我的 DiffUtil class 如下。我扩展了 DiffUtil class 并检查了项目是否相同,如果不相同,那么 DiffUtil 将处理 updatin
class BookListDiffCallBacks(var oldBooks: ArrayList<BookTable>, var newBooks: ArrayList<BookTable>) : DiffUtil.Callback() {
override fun areItemsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean {
return oldBooks[oldItemPosition].bookId == newBooks[newItemPosition].bookId
}
override fun getOldListSize(): Int {
return oldBooks.size
}
override fun getNewListSize(): Int {
return newBooks.size
}
override fun areContentsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean {
return oldBooks[oldItemPosition] == newBooks[newItemPosition]// == means structural equality checks in kotlin
}
override fun getChangePayload(oldItemPosition: Int, newItemPosition: Int): Any? {
return super.getChangePayload(oldItemPosition, newItemPosition)
}
}
型号class
@Entity(
tableName = "book_table"//,
// foreignKeys = [ForeignKey(entity = CategoryTable::class, parentColumns = arrayOf("categoryId"), childColumns = arrayOf("categoryId"), onDelete = ForeignKey.CASCADE)]
)
class BookTable : BaseObservable() {
@Bindable
@PrimaryKey(autoGenerate = true)
@ColumnInfo(name = "bookId")
var bookId: Int = 0
set(value) {
field = value
notifyPropertyChanged(BR.bookId)
}
@Bindable
var name: String? = null
set(value) {
field = value
notifyPropertyChanged(BR.name)
}
@Bindable
var categoryId: Int? = null
set(value) {
field = value
notifyPropertyChanged(BR.categoryId)
}
override fun equals(other: Any?): Boolean {
if (other === this) return true // means same reference
if (other !is BookTable) return false// is not of same class
// other is now Booktable instance as above condition false if you remove that condition then it will show error in below condition
// as it has passed above condition means it is of type BookTable
return (bookId == other.bookId
&& categoryId == other.categoryId
&& name == other.name)
}
override fun hashCode(): Int {
var result = bookId
result = 31 * result + (name?.hashCode() ?: 0)
result = 31 * result + (categoryId ?: 0)
return result
}
}
我的应用崩溃了,我收到了这个错误:
java.lang.IndexOutOfBoundsException:检测到不一致。无效的视图持有者适配器 positionBooksViewHolder
我已经实施了 DiffUtil class,这样整个 recycleview 视图项目都不会收到通知。
参考:https://developer.android.com/reference/kotlin/androidx/recyclerview/widget/DiffUtil
BookListDiffCallBacks
构造函数的参数是反向的:
val result = DiffUtil.calculateDiff(BookListDiffCallBacks(ArrayList(value), ArrayList(books)))
您正在传递 new, old
,但构造函数期望 old, new
。
如果我找到了解决方法,有时该错误仍然存在。谢谢,@Ryan 付出了宝贵的努力。其实你的解决方案解决了我的问题,下面给出预防措施。
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: Recycler, state: RecyclerView.State) {
try {
super.onLayoutChildren(recycler, state)
} catch (e: IndexOutOfBoundsException) {
Log.e("Error", "IndexOutOfBoundsException in RecyclerView happens")
}
}
}
下面是一个适配器 class,用于在回收站视图中加载所有图书项目。使用 DiffUtils 以便整个列表不会收到通知。
class BooksAdapter(var mContext: Context) : RecyclerView.Adapter<BooksAdapter.BooksViewHolder>() {
var books: List<BookTable> = ArrayList()
set(value) {
val result = DiffUtil.calculateDiff(BookListDiffCallBacks(ArrayList(value), ArrayList(books)))
field = value
result.dispatchUpdatesTo(this)
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): BooksViewHolder {
val binding = DataBindingUtil.inflate<ItemBookBinding>(LayoutInflater.from(mContext), R.layout.item_book, parent, false)
return BooksViewHolder(binding)
}
override fun getItemCount(): Int {
return books.size
}
override fun onBindViewHolder(holder: BooksViewHolder, position: Int) {
holder.setData(books[position])
}
inner class BooksViewHolder(var binding: ItemBookBinding) : RecyclerView.ViewHolder(binding.root) {
fun setData(bookTable: BookTable) {
binding.book = bookTable
}
}
}
我的 DiffUtil class 如下。我扩展了 DiffUtil class 并检查了项目是否相同,如果不相同,那么 DiffUtil 将处理 updatin
class BookListDiffCallBacks(var oldBooks: ArrayList<BookTable>, var newBooks: ArrayList<BookTable>) : DiffUtil.Callback() {
override fun areItemsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean {
return oldBooks[oldItemPosition].bookId == newBooks[newItemPosition].bookId
}
override fun getOldListSize(): Int {
return oldBooks.size
}
override fun getNewListSize(): Int {
return newBooks.size
}
override fun areContentsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean {
return oldBooks[oldItemPosition] == newBooks[newItemPosition]// == means structural equality checks in kotlin
}
override fun getChangePayload(oldItemPosition: Int, newItemPosition: Int): Any? {
return super.getChangePayload(oldItemPosition, newItemPosition)
}
}
型号class
@Entity(
tableName = "book_table"//,
// foreignKeys = [ForeignKey(entity = CategoryTable::class, parentColumns = arrayOf("categoryId"), childColumns = arrayOf("categoryId"), onDelete = ForeignKey.CASCADE)]
)
class BookTable : BaseObservable() {
@Bindable
@PrimaryKey(autoGenerate = true)
@ColumnInfo(name = "bookId")
var bookId: Int = 0
set(value) {
field = value
notifyPropertyChanged(BR.bookId)
}
@Bindable
var name: String? = null
set(value) {
field = value
notifyPropertyChanged(BR.name)
}
@Bindable
var categoryId: Int? = null
set(value) {
field = value
notifyPropertyChanged(BR.categoryId)
}
override fun equals(other: Any?): Boolean {
if (other === this) return true // means same reference
if (other !is BookTable) return false// is not of same class
// other is now Booktable instance as above condition false if you remove that condition then it will show error in below condition
// as it has passed above condition means it is of type BookTable
return (bookId == other.bookId
&& categoryId == other.categoryId
&& name == other.name)
}
override fun hashCode(): Int {
var result = bookId
result = 31 * result + (name?.hashCode() ?: 0)
result = 31 * result + (categoryId ?: 0)
return result
}
}
我的应用崩溃了,我收到了这个错误:
java.lang.IndexOutOfBoundsException:检测到不一致。无效的视图持有者适配器 positionBooksViewHolder
我已经实施了 DiffUtil class,这样整个 recycleview 视图项目都不会收到通知。
参考:https://developer.android.com/reference/kotlin/androidx/recyclerview/widget/DiffUtil
BookListDiffCallBacks
构造函数的参数是反向的:
val result = DiffUtil.calculateDiff(BookListDiffCallBacks(ArrayList(value), ArrayList(books)))
您正在传递 new, old
,但构造函数期望 old, new
。
如果我找到了解决方法,有时该错误仍然存在。谢谢,@Ryan 付出了宝贵的努力。其实你的解决方案解决了我的问题,下面给出预防措施。
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: Recycler, state: RecyclerView.State) {
try {
super.onLayoutChildren(recycler, state)
} catch (e: IndexOutOfBoundsException) {
Log.e("Error", "IndexOutOfBoundsException in RecyclerView happens")
}
}
}