Kotlin中RecyclerView Adapter如何将位置数据回传给MainActivity(含lazy初始化问题)
问题修复方案
你代码的核心问题有两个:一是同时定义了两种回调逻辑但没有实际触发点击事件,二是注释里的代码是Java语法不适用Kotlin,所以编译失败。以下是完整的修复步骤:
1. 核心问题说明
- 你当前
ItemAdapter同时设置了构造函数Lambda回调和OnItemClickListener接口回调,但是没有在item的点击事件里调用任何回调逻辑,所以即使编译通过也收不到位置回传 - 注释里的代码是Java的Lambda写法,Kotlin不支持该语法,所以编译报错,你原本用
by lazy初始化的写法语法是正确的,只需要对齐ItemAdapter的构造函数参数即可 - 你用了无限滚动逻辑(
getItemCount返回Int.MAX_VALUE),回传位置的时候要记得返回取模后的真实item位置,而不是滚动的绝对位置
2. 修复后的代码
方案一:用接口回调(匹配你原本实现OnItemClickListener的写法)
ItemAdapter.kt 修改点:
- 移除构造函数里冗余的Lambda参数
- 在
ViewHolder绑定数据时给item设置点击事件,触发接口回调
class ItemAdapter : RecyclerView.Adapter<ItemViewHolder>() { private var items: List<Item> = listOf() lateinit var listener: OnItemClickListener public interface OnItemClickListener { fun getAdapterPosition(position : Int ) } public fun setOnItemClickListener(listener: OnItemClickListener) { this.listener= listener } override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ItemViewHolder = ItemViewHolder(LayoutInflater.from(parent.context).inflate(R.layout.list_item, parent, false)) override fun onBindViewHolder(holder: ItemViewHolder, position: Int) { val realPos = position % items.size holder.bind(items[realPos]) // 新增点击事件触发回调 holder.itemView.setOnClickListener { if (::listener.isInitialized) { listener.getAdapterPosition(realPos) } } Log.d("xx position= ", realPos.toString()) } override fun getItemCount(): Int = Int.MAX_VALUE fun setItems(newItems: List<Item>) { items = newItems notifyDataSetChanged() } } class ItemViewHolder(private val view: View) : RecyclerView.ViewHolder(view) { fun bind(item: Item) { view.list_item_text.text = "${item.title}" view.list_item_icon.setImageResource(item.icon) } }
MainActivity.kt 修改点:
- 调整
by lazy初始化逻辑,匹配修改后的无参构造函数 - 移除注释里错误的Java语法代码
class MainActivity : AppCompatActivity(), ItemAdapter.OnItemClickListener { // 调整by lazy初始化,匹配ItemAdapter无参构造 private val itemAdapter by lazy { ItemAdapter() } private val possibleItems = listOf( Item("Plane 1", R.drawable.ic_airplane), Item("Car 2", R.drawable.ic_car), Item("Meals 3", R.drawable.ic_food), Item("Fuel 4", R.drawable.ic_gas), Item("Home 5 ", R.drawable.ic_home) ) fun onImageClick(imageData: String?) { // handle image data } override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) // 移除原来错误的Java语法注释代码即可 item_list.initialize(itemAdapter) itemAdapter.setOnItemClickListener(this) ItemSnapHelper().attachToRecyclerView(item_list) item_list.setViewsToChangeColor(listOf(R.id.list_item_background, R.id.list_item_text)) item_list.scrollToPosition(Int.MAX_VALUE/2) itemAdapter.setItems(possibleItems) } override fun getAdapterPosition(position : Int ){ // 这里已经能拿到回传的真实位置 Toast.makeText(this,"当前点击位置:$position",Toast.LENGTH_SHORT).show() // 需要滚动的话也可以在这里处理 // item_list.smoothScrollToPosition(position) } private fun getLargeListOfItems(): List<Item> { val items = mutableListOf<Item>() (0..40).map { items.add(possibleItems.random()) } return items } } data class Item( val title: String, @DrawableRes val icon: Int )
方案二:用构造函数Lambda回调(更简洁的Kotlin写法)
如果你不想用接口,也可以直接用构造函数的Lambda,不需要再实现OnItemClickListener,修改如下:
ItemAdapter.kt 修改点:
- 移除冗余的接口定义,在点击事件里触发构造传入的Lambda
class ItemAdapter(val itemClick: (position:Int,item:Item) -> Unit) : RecyclerView.Adapter<ItemViewHolder>() { private var items: List<Item> = listOf() override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ItemViewHolder = ItemViewHolder(LayoutInflater.from(parent.context).inflate(R.layout.list_item, parent, false)) override fun onBindViewHolder(holder: ItemViewHolder, position: Int) { val realPos = position % items.size val currentItem = items[realPos] holder.bind(currentItem) // 点击触发Lambda回调 holder.itemView.setOnClickListener { itemClick.invoke(realPos, currentItem) } Log.d("xx position= ", realPos.toString()) } override fun getItemCount(): Int = Int.MAX_VALUE fun setItems(newItems: List<Item>) { items = newItems notifyDataSetChanged() } } // 其余ViewHolder代码不变
MainActivity.kt 修改点:
- 移除
OnItemClickListener实现,你原本的by lazy写法直接可用
class MainActivity : AppCompatActivity() { // 你原本的by lazy写法完全正确,直接用就行 private val itemAdapter by lazy { ItemAdapter { position: Int, item: Item -> Toast.makeText(this@MainActivity, "点击位置:${position}, 内容:${item.title}", Toast.LENGTH_LONG).show() item_list.smoothScrollToPosition(position) } } // 其余代码不变,onCreate里也不需要再调用setOnItemClickListener }
内容的提问来源于stack exchange,提问作者NFI
相关产品推荐
相关产品推荐

