Android Kotlin开发RecyclerView点击返回绑定位置为-1问题求助
问题根因
最直接的报错来源
在你写的ViewHolder点击逻辑里,这行代码完全错误:
val position: String = CustomViewHolder(it).bindingAdapterPosition.toString()
你把点击事件返回的it(也就是条目根View)作为参数,重新实例化了一个全新的CustomViewHolder对象。这个新建的对象根本没有和RecyclerView完成绑定流程,没有任何位置关联,所以它的bindingAdapterPosition永远返回-1,这就是你拿不到真实条目位置的核心原因。
潜在的次生问题
就算修正了新建对象的错误,直接在ViewHolder的init块里设置点击监听也有隐患:当RecyclerView执行条目更新、动画、布局偏移时,绑定位置类方法会在临时状态下返回-1,容易偶现跳转异常。
修复方案
快速修复版本
直接利用当前ViewHolder实例自身的绑定位置值,删掉多余的对象创建逻辑,加位置有效性判断:
class CustomViewHolder(view: View): RecyclerView.ViewHolder(view){ val titulo = view.findViewById<TextView>(R.id.txtTitle) val localizacao = view.findViewById<TextView>(R.id.txtDescription) val img = view.findViewById<ImageView>(R.id.imageItem) init { view.setOnClickListener{ // 直接取当前Holder的真实绑定位置,不要新建对象 val position = bindingAdapterPosition // 位置失效时直接拦截,避免拿到-1 if (position == RecyclerView.NO_POSITION) return@setOnClickListener val intent = Intent(view.context, NotificationActivity::class.java).apply { putExtra("id", position) } view.context.startActivity(intent) } } }
推荐长期稳定版本
把点击逻辑从ViewHolder移到Adapter的onBindViewHolder阶段,直接传入已经明确的position值,从根源上避免位置失效问题:
- 给MainAdapter增加点击回调接口,绑定点击事件时直接传入position和对应数据:
class MainAdapter( private var listData: List<Notifications>?, private val onItemClick: (position: Int, item: Notifications) -> Unit ) : RecyclerView.Adapter<CustomViewHolder>(){ override fun getItemCount(): Int = listData?.size ?: 0 override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): CustomViewHolder { val cellForRow = LayoutInflater.from(parent.context).inflate(R.layout.inforow, parent, false) return CustomViewHolder(cellForRow) } override fun onBindViewHolder(holder: CustomViewHolder, position: Int) { val ld = listData!![position] holder.titulo.text = ld.titulo holder.localizacao.text = ld.localizacao Picasso.get().load(ld.img).into(holder.img) // 直接把当前已经确定的position绑定到点击事件上 holder.itemView.setOnClickListener { onItemClick(position, ld) } } }
- 在InboxFragment中初始化Adapter时,把详情跳转逻辑写在回调里:
adapter = MainAdapter(listData) { position, item -> val intent = Intent(requireContext(), NotificationActivity::class.java).apply { // 推荐传通知对应的数据库真实ID,不要只传position,数据集变化时position会错位 putExtra("notification_id", item.id) } startActivity(intent) } rv.adapter = adapter
其他优化建议
- 把原来声明的
listData: List<Notifications>改成MutableList<Notifications>,去掉后续循环add时的强制类型转换,避免类型转换异常。 - 传跳转参数时不要只传条目位置,当列表发生增删、排序时,位置会动态变化,容易出现点击条目A打开条目B详情的错位问题,最好传每个通知对应的Firebase数据库主键ID。
内容的提问来源于stack exchange,提问作者Guilherme Faure
相关产品推荐
相关产品推荐

