0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【Android】RecyclerViewのイベントの実装

Posted at

はじめに

RecyclerViewで表示しているリストのタップイベントを実装しようとした時に、イベントの実装をどこに置くのがいいのか迷うことがありました。
今まではViewModelに処理を持たせてListAdapterにViewModelを渡し、ListAdapter→ViewModelにアクセスするように作っていたのですが、公式サイト(UI イベント)を見てみると、その方法は推奨されないとのこと。

警告: ViewModel を RecyclerView アダプターに渡すことは、アダプターと ViewModel クラスを密結合させることになるため、おすすめしません。

公式では、ListAdapterに渡すリストデータにイベントの実装を含めるという方法が推奨されていました。

今回は公式サイトの例を参考にRecyclerViewを使い、リストタップ → ViewModelの処理を呼び出す方法をまとめたいと思います。

実装

今回は「RecyclerViewのリストをタップ → ViewModelで実装しているログ出力を実行」となる処理を作ります。
サンプルで作ったソースはこちらになります。
そもそものRecyclerViewやViewModelの実装についてはこの記事では触れませんので、ご留意ください🙇‍♂️

リストのデータモデルを作成する

以下のようなデータクラスを作成します。
ここで重要になるのがclickActionの定義です。
リストとして渡すデータに、クリックしたときの処理を含めるようにします。

LinkItemModel.kt
data class LinkItemModel(
    val title: String,
    val url: String,
    val clickAction: () -> Unit // ここが大事
)

ViewModelで、タップ時の処理を含めたリストデータを作成

ViewModelにて、先ほど作成したLinkItemModelを使用し、ListAdapter渡すデータを作成します。
clickActionの箇所には、リストタップ時に実行したい処理を含めてデータの作成を行います。

MainViewModel.kt
class MainViewModel : ViewModel() {
    private val _items: MutableStateFlow<List<LinkItemModel>> = MutableStateFlow(emptyList())
    val items = _items.asStateFlow()

    init {
        val linkList = listOf(
            arrayOf("https://www.google.com", "Google"),
            arrayOf("https://www.yahoo.com", "Yahoo"),
            arrayOf("https://www.bing.com", "Bing"),
            arrayOf("https://www.duckduckgo.com", "DuckDuckGo"),
            arrayOf("https://www.ask.com", "Ask"),
            arrayOf("https://www.aol.com", "AOL"),
            arrayOf("https://www.wolframalpha.com", "Wolfram Alpha"),
            arrayOf("https://www.yandex.com", "Yandex"),
            arrayOf("https://www.baidu.com", "Baidu"),
        )

        _items.value = linkList.map {
            LinkItemModel(
                it[1],
                it[0]
            ) {
                // リストタップ時の処理を定義
                printLog("Clicked on ${it[1]}:${it[0]}") 
            }
        }
    }

    private fun printLog(message: String) {
        println("MainViewModel: $message")
    }
}

Adapterにクリックイベントを設定

Adapterにリストがタップされたときのイベントを設定します。
この時、実行される処理としては**linkItemModel.clickAction()**を設定します。
こうすることで項目タップ時には、先ほどViewModelでclickActionに設定した処理が実行されるようになります。

LinkListAdapter.kt
class LinkListAdapter :
    ListAdapter<LinkItemModel, LinkListAdapter.ViewHolder>(DIFF_UTIL_ITEM_CALLBACK) {

    class ViewHolder(
        private val binding: ListItemBinding,
    ) : RecyclerView.ViewHolder(binding.root) {
        fun bind(linkItemModel: LinkItemModel) {
            binding.textView.text = linkItemModel.title
            binding.root.setOnClickListener {
                linkItemModel.clickAction()
            }
        }
    }
                
                
                
}

このような実装にすることで、ListAdapterにViewModelを渡すことなく、ViewModelの処理を実行できるようになります。

おわりに

ListAdapterからViewModelの処理を実行する方法についてまとめました。
ListAdapterがViewModel全体にアクセスするのではなく、一部のアクセスに限られるので、実装の安全性も増すかと思います。
今回作成したサンプルアプリでは、タップしたらログ出力するだけですので、特に意味がありませんが、タップした時にDB操作やAPI通信を行う、といったこともできるかと思います。

どこか参考になるところがあれば幸いです!

参考

UI イベント
RecyclerViewSample

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?