RecyclerView + Databinding + ViewModel + LiveData で RecyclerViewのitemの値を変更する

# はじめに
recyclerViewのitemの要素をliveDataで管理したくて色々試した結果です。
今回はrecyclerViewのitemのテキストをボタンをクリックしたら変わるようにしてみたいと思います。

僕もあまり理解が深いわけではないので、間違っているところがあったらご指摘していただけると嬉しいです。

android studioのバージョンは以下です。
android Studio : 3.4.1



# 実装
### build.gradleはこんな感じ(追加したのだけ)
``` build.gradle
android {
    // ・・・
    dataBinding {
        enabled = true
    }
}

dependencies {
    // ・・・
    implementation 'androidx.recyclerview:recyclerview:1.0.0'
    implementation "android.arch.lifecycle:extensions:1.1.1"
    // ・・・
}
```
databindingをtrueにしてlifecycle:extensionを入れただけです。

###xml(constraintLayoutの制約は省略)
```php:item_recycler_view.xml
<layout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools">

    <data>
        <variable name="viewModel" type="MyViewModel"/>
        <variable name="position" type="Integer"/>
    </data>

    <androidx.constraintlayout.widget.ConstraintLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content">

        <TextView
            android:text="@{viewModel.list[position]}"
            android:layout_width="wrap_content"
            android:layout_height="30dp"
            android:id="@+id/textView" />

        <View
            android:layout_width="0dp" 
            android:layout_height="1dp"
            android:background="@android:color/background_dark"/>

    </androidx.constraintlayout.widget.ConstraintLayout>

</layout>
```
main_activityのxmlは省略しますがボタンとrecyclerViewがおいてあるだけです。

###続いてviewModel
```php:MyViewModel.kt
class MyViewModel : ViewModel() {

    val list = mutableListOf<MutableLiveData<String>>()
    init {
        for (i in 0..3) {
            list.add(MutableLiveData<String>().apply { value = "Item$i" })
        }
    }

    fun buttonClick(view: View) {
        list[1].value = "Success!!"
    }
}
```
ボタンをクリックしたらrecyclerViewで使っているlistの中の一つをSuccess!!に変えてみます。
まあ普通にliveDataを更新しているだけです。

### 続いてMainActivity
```php:MainActivity.kt
class MainActivity : AppCompatActivity() {

    lateinit var mViewModel: MyViewModel

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        mViewModel = ViewModelProviders.of(this).get(MyViewModel().javaClass)
        val binding = DataBindingUtil.setContentView<ActivityMainBinding>(this, R.layout.activity_main)
        binding.viewModel = mViewModel
        binding.lifecycleOwner = this
//ここまではよくあるdataBindingと同じです

//ここでadapterを作成するときにlifecycleOwnerを渡す！
        val adapter = MyAdapter(mViewModel, this)
        recyclerView.layoutManager = LinearLayoutManager(this)
        recyclerView.adapter = adapter
    }
}
```
adapterにactivityのlifecycleOwnerを渡しました。

###AdapterとViewHolder
```php:MyAdapter.kt
//引数としてrecyclerViewを使っているactivity,fragmentのlifecycleOwnerをもらいます
class MyAdapter(private val viewModel: MyViewModel, private val parentLifecycleOwner: LifecycleOwner) :
    RecyclerView.Adapter<MyAdapter.MyHolder>() {

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyHolder {
        val binding = DataBindingUtil.inflate<ItemRecyclerViewBinding>(
            LayoutInflater.from(parent.context),
            R.layout.item_recycler_view,
            parent,
            false
        )
        return MyHolder(binding)
    }

    override fun getItemCount(): Int {
        return viewModel.list.size
    }

    override fun onBindViewHolder(holder: MyHolder, position: Int) {
        holder.binding.viewModel = viewModel
        holder.binding.position = position
//ここでviewholderのlifecycleOwnerにセットする！
        holder.binding.lifecycleOwner = parentLifecycleOwner
    }

    class MyHolder(val binding: ItemRecyclerViewBinding) : RecyclerView.ViewHolder(binding.root)
}
```
先ほどactivityからもらったlifecycleOwnerを
`holder.binding.lifecycleOwner = parentLifecycleOwner`
という感じでセットしてあげます。

やることは以上！
これでrecyclerViewの中のitemもliveDataの変更が反映されるようになります。

activityやfragmentでは
`binding.lifecycleOwner = lifecycleOwner`という感じで書きますよね。
ただそれをadapterの方で生成したbindingでもしてあげるだけでした。

#おわりに
結果的にはとても簡単なことでしたが、気づくまでに時間がかかってしまいました。
もっとandroidについて学習しなきゃと思わされた出来事でした。

またこの記事ではlifecycleOwnerにthisを使っていますが、fragmentでやる場合はviewLifecycleOwnerを使った方がいいらしいです。以下の記事が参考になるのでお時間のある方はどうぞ
[5 common mistakes when using Architecture Components](https://proandroiddev.com/5-common-mistakes-when-using-architecture-components-403e9899f4cb)

何か間違いやさらに良い方法があればコメントで教えていただけると嬉しいです。
ありがとうございました。