[英]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.