RecyclerView ViewHolder中TextView点击事件始终返回首次点击参数问题排查
问题根本原因
1. 核心原因:Xamarin.Android JNI绑定机制的特性
你自定义的DeleteOnClickListener继承了Java.Lang.Object,当该类的实例首次被传递到Java层、赋值给DeleteButton的点击监听器后,JNI会对该实例持有全局引用。后续因为RecyclerView的ViewHolder复用机制,你给同一个复用的ViewHolder的DeleteButton重复设置新的DeleteOnClickListener实例时,JNI桥接层没有正确替换Java端已经绑定的监听器引用,导致点击事件始终触发首次绑定的监听器,因此拿到的永远是第一次传入的id和position参数。
2. 次要逻辑缺陷
你之前的实现将position和id作为固定值,在监听器初始化时就写入成员变量,就算监听器能正常更新,一旦列表发生插入、删除、移动等操作导致item位置变化,监听器中存储的旧position也会出现偏移,最终拿到错误的数据。
最终方案生效的原因
你改用AdapterPosition获取位置的方案之所以有效,是因为:AdapterPosition是RecyclerView.ViewHolder的动态属性,每次调用时都会返回当前ViewHolder最新的实际绑定位置,不需要每次OnBindViewHolder时重复创建和设置新的监听器实例,只需要在ViewHolder构造时设置一次监听器即可,从根源上避开了JNI层监听器替换失败的坑,同时动态获取的位置也能保证就算列表数据变动,参数也永远是最新的。
最佳实践建议
- 不要在
OnBindViewHolder中重复创建、设置监听器,统一在ViewHolder构造函数中完成点击事件的绑定,点击时动态获取AdapterPosition,再用该位置从数据源中查询对应id和其他数据,性能更高也不会出现参数错误问题。 - 如果确实需要在绑定阶段更新监听器的关联参数,可以给自定义监听器新增参数更新方法,每次绑定时直接更新现有监听器的成员变量即可,避免频繁创建新的
Java.Lang.Object实例带来的JNI开销和替换异常问题。
内容的提问来源于stack exchange,提问作者Ali
相关产品推荐
相关产品推荐

