You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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值,从根源上避免位置失效问题:

  1. 给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)
        }
    }
}
  1. 在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.30 06:24:02