【发布时间】:2021-12-08 11:00:02
【问题描述】:
我的应用使用“Jetpack Navigation、DataBinding、ViewModel”。
一个 Fragment 有 RecyclerView。
如果我触摸其中一个项目,它会导航到 B 片段。
当我回到 A 片段(通过后退按钮)时,会发生崩溃。
IndexOutOfBoundsException: Inconsistency detected. Invalid view holder adapter
片段是:
@AndroidEntryPoint
class AFragment : Fragment() {
private var _binding: FragmentABinding? = null
private val binding: FragmentABinding
get() = _binding!!
private val viewModel: AViewModel by viewModels()
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View {
_binding = FragmentABinding.inflate(inflater, container, false)
binding.vm = viewModel
binding.lifecycleOwner = viewLifecycleOwner
return binding.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
binding.rvItems.adapter = ItemsAdapter()
viewModel.getItems()
}
}
ViewModel 是:
@HiltViewModel
class AViewModel @Inject constructor(
private val itemRepo: ItemRepo,
private val disposable: CompositeDisposable
) : ViewModel() {
private var _items: MutableLiveData<List<Item>> = MutableLiveData()
val items: LiveData<List<Item>>
get() = _items
override fun onCleared() {
super.onCleared()
disposable.clear()
}
fun getItems() {
itemRepo.getAll()
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe({
_items.postValue(it)
}, { t ->
})
.addTo(disposable)
}
}
XML 布局是:
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/rv_items"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:bind_items="@{vm.items}"
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager" />
绑定适配器是:
@BindingAdapter("bind_items")
fun setItems(view: RecyclerView, list: List<Item>?) {
if (!list.isNullOrEmpty()) {
(view.adapter as? ItemsAdapter)?.update(list)
}
}
ItemsAdapter 是:
class ItemsAdapter : RecyclerView.Adapter<ItemsAdapter.ItemHolder>() {
private val items: MutableList<Item> = mutableListOf()
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ItemHolder {
return ItemHolder (ItemItemBinding.inflate(LayoutInflater.from(parent.context), parent, false))
}
override fun onBindViewHolder(holder: ItemHolder, position: Int) {
holder.bind(items[position])
}
fun update(newItems: List<Item>) {
items.clear()
items.addAll(newItems)
notifyItemRangeInserted(0, newItems.size)
}
class ItemHolder(
private val binding: ItemItemBinding
) : RecyclerView.ViewHolder(binding.root) {
fun bind(item: Item) {
with(binding) {
tvDate.text = item.date
}
}
}
}
我认为这个问题与“Jetpack Navigation”有关。
但我不知道我该怎么做...
【问题讨论】:
-
ItemsAdapter.update是做什么的? -
我也添加了适配器代码
-
这个
notifyItemInsertRange(0, newItems.size)方法有什么作用?据我所知,这不是标准方法 - 这:Adapter::notifyItemRangeInserted(int positionStart, int itemCount)或Adapter::notifyItemRangeChanged(int positionStart, int itemCount)是您通常调用的方法。考虑使用 DiffUtil 类,甚至是使用AsyncListDiffer的ListAdapter来计算和应用更改。 -
只是打错了...我用
notifyItemRangeInserted对。
标签: android android-recyclerview android-databinding android-jetpack-navigation