在 RecyclerView 适配器中初始化 viewHolder 时出错
Posted
技术标签:
【中文标题】在 RecyclerView 适配器中初始化 viewHolder 时出错【英文标题】:Error when initialize viewHolder in RecyclerView adapter 【发布时间】:2022-01-14 09:58:52 【问题描述】:我应该如何初始化 viewHolder?我有这个错误: 我需要做的是在 recyclerView 中获取所选项目,但不使用 onClick 方法。当我得到这个选定的项目时,我需要显示 Toast 消息。项目是数据类。是否可以将一些值从适配器传递给活动?就像我需要从数据类中传递实际项目一样。
进程:com.pors.coopreaderlast,PID:7862 kotlin.UninitializedPropertyAccessException:lateinit 属性 viewHolder 尚未初始化 在 com.pors.coopreaderlast.features.polozka.PolozkaAdapter.getViewHolder(PolozkaAdapter.kt:18) 在 com.pors.coopreaderlast.features.polozka.PolozkaAdapter.getCurrentItem(PolozkaAdapter.kt:46) 在 com.pors.coopreaderlast.features.polozka.PolozkaActivity.onStart(PolozkaActivity.kt:213)
这是针对在适配器中设置 viewHolder 的行: lateinit var viewHolder: PolozkaViewHolder
这是适配器
class PolozkaAdapter(val chosen_item: Int, private val listener: OnItemClickListener): ListAdapter<Polozka, PolozkaAdapter.PolozkaViewHolder>(DiffCallback())
var selectedItemPosition: Int = chosen_item
lateinit var viewHolder: PolozkaViewHolder
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): PolozkaViewHolder
val binding = PolozkyItemBinding.inflate(LayoutInflater.from(parent.context), parent, false)
//return PolozkaViewHolder(binding)
viewHolder = PolozkaViewHolder(binding)
return viewHolder
override fun onBindViewHolder(holder: PolozkaViewHolder, position: Int)
val currentItem = getItem(position)
holder.bind(currentItem)
if (selectedItemPosition == position)
holder.itemView.setBackgroundColor(Color.parseColor("#DA745A"))
else
holder.itemView.setBackgroundColor(Color.TRANSPARENT)
fun getCurrentItem(): Polozka = super.getItem(viewHolder.bindingAdapterPosition)
override fun getItemId(position: Int): Long
return super.getItemId(position)
override fun getItemCount(): Int
return super.getItemCount()
inner class PolozkaViewHolder(private val binding: PolozkyItemBinding): RecyclerView.ViewHolder(binding.root)
init
binding.root.setOnClickListener
val position = bindingAdapterPosition
if (position != RecyclerView.NO_POSITION)
val item = getItem(position)
if (item != null)
listener.onItemClick(item, position)
notifyItemChanged(selectedItemPosition)
selectedItemPosition = bindingAdapterPosition
notifyItemChanged(selectedItemPosition)
fun bind(polozkaPolozka: Polozka)
binding.apply
tvREG.text = polozkaPolozka.reg
tvVB.text = polozkaPolozka.veb.toString()
interface OnItemClickListener
fun onItemClick(polozkaDoklad: Polozka, position: Int)
class DiffCallback: DiffUtil.ItemCallback<Polozka>()
override fun areItemsTheSame(oldItem: Polozka, newItem: Polozka) =
oldItem.pvp06pk == newItem.pvp06pk
override fun areContentsTheSame(oldItem: Polozka, newItem: Polozka) =
oldItem == newItem
这是 onCreate 方法,但也可以在 onCreate 方法中。
override fun onCreate(savedInstanceState: Bundle?)
super.onCreate(savedInstanceState)
val binding = ActivityPolozkaBinding.inflate(layoutInflater)
idPositionItem = intent.getIntExtra("positionItem",0)
val itemAdapter = PolozkaAdapter(idPositionItem, this)
binding.apply
recyclerView.apply
adapter = itemAdapter
layoutManager = LinearLayoutManager(this@ItemActivity)
itemViewModel.getall(index,idExp.toString() ).observe(this@PolozkaActivity)
itemAdapter.submitList(it)
val selectedItem = itemAdapter.getCurrentItem()
Toast.makeText(this, "Reg vybrane polozky je $selectedItem.reg", Toast.LENGTH_LONG).show()
我在这里有类似的问题:Similar question 但我在这里使用绑定。
【问题讨论】:
【参考方案1】:您收到此异常的原因是 viewHolder
在您想要访问它的那一刻尚未初始化。由于它是lateinit var
,因此每次访问它时都会对其进行初始化。 (见https://kotlinlang.org/docs/properties.html#late-initialized-properties-and-variables)
您可以返回您在onCreateViewHolder()
中创建的实例,而不是使用lateinit var
来代替viewHolder
,因此无需在适配器中为其添加额外的字段。
我相信您使用viewHolder
来查找所选项目。在这种情况下,我建议在模型对象Polozka
中使用布尔值(例如,您可以将其命名为selected
)来指示该项目是否被选中。在你的getCurrentItem()
方法中,我会写getCurrentList().find it.selected
来查找当前选定的项目。在这种情况下,您需要在每次选择新项目时更新您的列表,并仅将其标记为已选择。
class PolozkaAdapter(private val listener: OnItemClickListener): ListAdapter<Polozka, PolozkaAdapter.PolozkaViewHolder>(DiffCallback())
lateinit var viewHolder: PolozkaViewHolder
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): PolozkaViewHolder
val binding = PolozkyItemBinding.inflate(LayoutInflater.from(parent.context), parent, false)
return PolozkaViewHolder(binding)
override fun onBindViewHolder(holder: PolozkaViewHolder, position: Int)
val currentItem = getItem(position)
holder.bind(currentItem)
if (currentItem.selected)
holder.itemView.setBackgroundColor(Color.parseColor("#DA745A"))
else
holder.itemView.setBackgroundColor(Color.TRANSPARENT)
fun getCurrentItem(): Polozka = currentList.find it.selected
override fun getItemId(position: Int): Long
return super.getItemId(position)
override fun getItemCount(): Int
return super.getItemCount()
//Model object would look like
data class Polozka(
val selected: Boolean,
//rest of the fields
)
在观察中你应该这样做。
itemViewModel.getall(index,idExp.toString() ).observe(this@PolozkaActivity)
// mark the item selected
val updatedList = it.mapIndexed index, item ->
if (index == idPositionItem)
item.copy(selected = true)
else
item
itemAdapter.submitList(updatedList)
val selectedItem = itemAdapter.getCurrentItem()
Toast.makeText(this, "Reg vybrane polozky je $selectedItem.reg", Toast.LENGTH_LONG).show()
每次选择新项目时,您都需要更新列表。
【讨论】:
这看起来很棒。但是如何更新我的列表以使未选择的项目为 false?以上是关于在 RecyclerView 适配器中初始化 viewHolder 时出错的主要内容,如果未能解决你的问题,请参考以下文章
片段中的recyclerview的“RecyclerView:没有附加适配器;跳过布局”[重复]
E/RecyclerView:没有附加适配器;跳过布局。尽管初始化适配器
从 Viewholder 通知 RecyclerView 适配器的最佳方式?
lateinit 属性适配器尚未初始化设置 RecyclerView 与 Fragment