[英]How to provide an implementation of the click listener interface for the recycler adapter?
Suppose we have a recycler view in a fragment, and we need to add a click handler to the adapter.假设我们在片段中有一个回收器视图,我们需要向适配器添加一个点击处理程序。 Which one of the following approaches are better?以下哪种方法更好? Please tell me the pros and cons each one:请告诉我每一种的优缺点:
In this approach we implement the OnItemClickListener in the fragment class MyFragment: Fragment(), MyAdapter.OnItemClickListener
and pass it to the adapter using this
keyword:在这种方法中,我们在片段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)
}
}
In this approach we use object:
syntax to create an anonymous object, like inline interface implementation in java:在这种方法中,我们使用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)
}
}
Simple answer: it doesn't matter.简单的回答:没关系。 Approach 2 simply allocates one extra object on the heap which is not a big deal.方法 2 只是在堆上分配一个额外的 object,这没什么大不了的。 I would prefer 2 over 1 because 1 exposes that MyFragment
implements MyAdapter.OnItemClickListener
: that should remain an implementation detail, not a part of your fragment's contract.我更喜欢 2 而不是 1,因为 1 公开了MyFragment
实现MyAdapter.OnItemClickListener
:这应该是实现细节,而不是片段合同的一部分。
However, there is something in your code that can affect performance.但是,您的代码中有些东西会影响性能。 Your setOnClickListener()
call allocates new listener whenever onBindViewHolder()
is called, which is pretty often if you scroll fast enough.每当调用onBindViewHolder()
() 时,您的setOnClickListener()
调用都会分配新的侦听器,如果您滚动得足够快,这通常会发生。 It adds to the work of your garbage collector.它增加了垃圾收集器的工作。
You can always get ViewHolder
's position in adapter with getBindingAdapterPosition() (or its deprecated counterpart getAdapterPosition() if you're using an older version of RecyclerView).您始终可以使用getBindingAdapterPosition() (如果您使用的是旧版本的 RecyclerView 则使用其已弃用的对应物getAdapterPosition())在适配器中获取ViewHolder
的 position。 As you can see from the docs, in marginal cases it may not be consistent with the position
you use and is a more correct approach to handling user actions.正如您从文档中看到的那样,在边缘情况下,它可能与您使用的position
不一致,并且是处理用户操作的更正确方法。
With that said, it is sufficient to set your listener only once, in onCreateViewHolder()
:话虽如此,只需在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
}
Here you can use Callback
, it is the recommended choice of Google's Android team.在这里你可以使用Callback
,它是 Google 的 Android 团队的推荐选择。 You implement that as:您将其实现为:
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.