batchのブログ

知見の備忘録

RecyclerViewのAdapterにClickListenerのいい感じの渡し方とKotlinのラムダ式がチョットわかったはなし

f:id:batch08:20210201144322p:plain

みなさん、Itemの中にボタンがあるRecyclerViewのAdapterを実装するとき、そのボタンの押されたときの処理はどのように書いてますか。

自分は今までこんな感じで書いてました。

class MyAdapter(private val listener: ClickButtonListener) {
 override fun  onBindViewHolder(holder: FriendListViewHolder, position: Int) {
   holder.view.button.setOnClickListener { listener.onClick("data") }
 }
}

interface ClickButtonListener {
  fun onClick(data: String)
}
class ListFragment : Fragment(), Adapter.ClickButtonListener {
  val adapter = MyAdapter(this)

  override fun onClick(data: String) {
    /** ~~~~~ **/
  }
}

おそらく、どこかの記事を参考に意味もわからずコピペしたものです。

これは以下ように書き換えることができます。

class MyAdapter(private val listener: ClickButtonListener) {
 override fun  onBindViewHolder(holder: FriendListViewHolder, position: Int) {
   holder.view.button.setOnClickListener { listener.onClick("data") }
 }
}

interface ClickButtonListener {
  fun onClick(data: String)
}
class ListFragment : Fragment() {
  val adapter = MyAdapter(object : ClickButtonListener {
    override onIconClick(data: String) {
      /** ~~~~~ **/
    }
  })
}

Fragmentに interface ClickButtonListenerの実装を渡してましたが、Adapterのインスタンス化時に同時に objectとしてinterfaceの実装を渡せるようになり、すっきり書くことができるようになりました。

さらにこれは、以下のように書き換えることができるようになります。

class MyAdapter(private val onClick: (data: String) -> Unit) {
 override fun  onBindViewHolder(holder: FriendListViewHolder, position: Int) {
   holder.view.button.setOnClickListener { onClick.invoke("data") }
 }
}
class ListFragment : Fragment() {
  val adapter = MyAdapter { data -> // itで省略可
        /** ~~~~~ **/
  }
}

さらにすっきりしました。

MyAdapterでは (data: String) -> Unitの関数型を受け取るようにして、 ListFragmentではadapterのインスタンス化時にラムダ式を渡すようにしました。

参考