【问题标题】:Error when initialize viewHolder in RecyclerView adapter在 RecyclerView 适配器中初始化 viewHolder 时出错
【发布时间】: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 但我在这里使用绑定。

【问题讨论】:

    标签: android kotlin android-recyclerview android-adapter


    【解决方案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?
    猜你喜欢
    • 2022-01-13
    • 1970-01-01
    • 2023-02-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-06-06
    • 1970-01-01
    • 2020-04-12
    相关资源
    最近更新 更多