[英]How to provide an implementation of the click listener interface for the recycler adapter?
假设我们在片段中有一个回收器视图,我们需要向适配器添加一个点击处理程序。 以下哪种方法更好? 请告诉我每一种的优缺点:
在这种方法中,我们在片段class MyFragment: Fragment(), MyAdapter.OnItemClickListener
中实现 OnItemClickListener 并使用this
关键字将其传递给适配器:
class MyFragment : Fragment() , MyAdapter.OnItemClickListener {
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
// Inflate the layout for this fragment
myRecyclerView.adapter = MyAdapter(it , this) // here we pass the fragment
return view
}
override fun onCLick(item: MyItem) {
Log.d("test","item name = " + item.Name)
}
}
class MyAdapter(val data: List<MyItem> , val onItemClickListener: OnItemClickListener) :
RecyclerView.Adapter<MyFragment.MyViewHolder>() {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyViewHolder {
val view = LayoutInflater.from(parent.context)
.inflate(R.layout.support_simple_spinner_dropdown_item, parent, false)
return MyViewHolder(view)
}
override fun getItemCount() = data.size
override fun onBindViewHolder(holder: MyViewHolder, position: Int) {
holder.itemView.setOnClickListener{
onItemClickListener.onCLick(data[position])
}
with(holder) {
textView1?.let {
it.text = data[position].Name
}
}
}
interface OnItemClickListener{
fun onCLick(item: MyItem)
}
}
在这种方法中,我们使用object:
语法来创建匿名 object,就像 java 中的内联接口实现一样:
class MyFragment : Fragment(){
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
// Inflate the layout for this fragment
myRecyclerView.adapter = MyAdapter(it ,object : MyAdapter.OnItemClickListener{
override fun onCLick(item: MyItem) {
Log.d("test","name = " + item.Name)
}
})
return view
}
class MyAdapter(val data: List<MyItem> , val onItemClickListener: OnItemClickListener) :
RecyclerView.Adapter<MyViewHolder>() {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyViewHolder {
val view = LayoutInflater.from(parent.context)
.inflate(R.layout.support_simple_spinner_dropdown_item, parent, false)
return MyViewHolder(view)
}
override fun getItemCount() = data.size
override fun onBindViewHolder(holder: MyViewHolder, position: Int) {
holder.itemView.setOnClickListener{
onItemClickListener.onCLick(data[position])
}
with(holder) {
textView1?.let {
it.text = data[position].Name
}
}
}
interface OnItemClickListener{
fun onCLick(item: MyItem)
}
}
简单的回答:没关系。 方法 2 只是在堆上分配一个额外的 object,这没什么大不了的。 我更喜欢 2 而不是 1,因为 1 公开了MyFragment
实现MyAdapter.OnItemClickListener
:这应该是实现细节,而不是片段合同的一部分。
但是,您的代码中有些东西会影响性能。 每当调用onBindViewHolder()
() 时,您的setOnClickListener()
调用都会分配新的侦听器,如果您滚动得足够快,这通常会发生。 它增加了垃圾收集器的工作。
您始终可以使用getBindingAdapterPosition() (如果您使用的是旧版本的 RecyclerView 则使用其已弃用的对应物getAdapterPosition())在适配器中获取ViewHolder
的 position。 正如您从文档中看到的那样,在边缘情况下,它可能与您使用的position
不一致,并且是处理用户操作的更正确方法。
话虽如此,只需在onCreateViewHolder()
中设置一次监听器就足够了:
override fun onCreateViewHolder(
parent: ViewGroup,
viewType: Int
): MyViewHolder {
val view = LayoutInflater.from(parent.context)
.inflate(R.layout.support_simple_spinner_dropdown_item, parent, false)
val holder = MyViewHolder(view)
holder.itemView.setOnClickListener {
holder
.bindingAdapterPosition
.takeUnless { it == RecyclerView.NO_POSITION }
?.let { position ->
onItemClickListener.onClick(data[position])
}
}
return holder
}
在这里你可以使用Callback
,它是 Google 的 Android 团队的推荐选择。 您将其实现为:
class MyFragment : Fragment(){
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
// Inflate the layout for this fragment
myRecyclerView.adapter = MyAdapter(it) { item ->
// You can use your item here.
}
return view
}
class MyAdapter(val data: List<MyItem> ,
private val callback: (MyItem) -> Unit) :
RecyclerView.Adapter<MyViewHolder>() {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyViewHolder {
val view = LayoutInflater.from(parent.context)
.inflate(R.layout.support_simple_spinner_dropdown_item, parent, false)
return MyViewHolder(view)
}
override fun getItemCount() = data.size
override fun onBindViewHolder(holder: MyViewHolder, position: Int) {
holder.itemView.setOnClickListener{
callback.invoke(data[position])
}
with(holder) {
textView1?.let {
it.text = data[position].Name
}
}
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.