繁体   English   中英

如何为回收器适配器提供点击监听接口的实现?

[英]How to provide an implementation of the click listener interface for the recycler adapter?

假设我们在片段中有一个回收器视图,我们需要向适配器添加一个点击处理程序。 以下哪种方法更好? 请告诉我每一种的优缺点:

方法一:在片段中实现 OnItemClickListener:

在这种方法中,我们在片段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 实现 OnItemClickListener:

在这种方法中,我们使用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)
    }
}
  1. 哪个更现代?
  2. 哪一个提供更好的性能? (如果有任何区别)
  3. 为什么在大多数教程和视频课程中他们使用第一种方法,而第二种方法需要更少的代码行?

简单的回答:没关系。 方法 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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM