layoutとLiveDataをbindingする際のはまりどころとチェックポイントをまとめる。
公式ドキュメントや人の解説をしっかり読んでいる人なら、はまらないレベル。
が、たまに新規アプリを作ると、いつもはまる。
FragmentのlayoutにViewModelのメンバLiveDataをbindingする場合を例にする。
Bindingクラスが生成されないんだけど
FragmentXXXBindingが生成されないケース。
build.gradleに以下の記述をしているか?
android {
...
dataBinding {
enabled = true
}
}
layout 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>...</data>
...
</layout>
LiveDataが全くbindされないんだけど
LiveDataに設定した初期値すら、Viewに反映されないケース。
bindingクラスにlifecycleOwnerを設定しているか?
binding = DataBindingUtil.inflate(layoutInflater, R.layout.fragment_xxx, container, false)
binding.viewModel = viewModel
binding.lifecycleOwner = viewLifecycleOwner // Activityならthisを設定
双方向バインディングされないんだけど?
LiveDataの初期値はViewに反映されるが、Viewの変化してもLiveDataの値が変わらないパターン。
"@"の後に"="をつけ忘れていないか?
<!-- NG -->
<EditText
...
android:text="@{viewModel.liveData}" />
<!-- OK -->
<EditText
...
android:text="@={viewModel.liveData}" />
CoroutineのFlowをLiveDataに変換した時、値を取得してもnullなんだけど
こんなケース。
// Model層のIF
val boolChannel = ConflatedBroadcastChannel<Boolean>(false)
val boolFlow: Flow<Boolean> = boolChannel.asFlow()
...
// ViewModelの実装
val boolData = model.boolFlow.asLiveData()
fun foobar() {
println(boolData.value) // null
}
ConflatedBroadcastChannelをasFlowとasLiveDataでLiveDataに変換した場合、そのLiveDataをobserveしないと値が取得できないらしい。
そもそもLiveDataをobserveしないならLiveDataにする意味なし。
LiveDataではなくFlowとして扱い、singleなりcolletなりで値を取得するのが適切。