LoginSignup
17

More than 3 years have passed since last update.

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

Last updated at Posted at 2019-08-12

はじめに

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の制約は省略)

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

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

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

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

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

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
17