簡體   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