【Android】DataBinding+LiveData + ViewModelのHello World
概要
前回の記事では、LiveData
とViewModel
を使った基本的な数字カウントアップの実装を試しました。
今回は、前回のコードをベースにレイアウトにUIコンポーネントを直接紐付ける仕組みである DataBinding
を追加してみます。
環境
- compileSdkVersion: 29
- Kotlin: v1.3.72
- lifecycle-viewmodel-ktx: v2.2.0
- lifecycle-livedata-ktx: v2.2.0
プロジェクトのセットアップ
まずは、DataBindingを使うためのプロジェクトのセットアップをします。
appディレクトリ配下のbuild.gradleに次の設定を追加します。
android { ・・・ dataBinding { enabled true } ・・・ }
appディレクトリ配下の build.gradle
にdataBindingについてのenable設定を記述します。
画面のレイアウト
前回の構成と同じ、数値を表示するTextViewとカウントアップするためのボタンを用意します。
(xmlについては、前回の記事を参照ください)
ViewModelとLiveDataの準備
ViewModelクラスについても前回の記事と変わりません。
(xmlについては、前回の記事を参照ください)
DataBindingのセットアップ①(レイアウトxml)
xmlで宣言しているレイアウトファイルにViewModelのデータをDataBindingを使って関連付けていきます。
<?xml version="1.0" encoding="utf-8"?> <layout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto"> <data> <variable name="viewModel" type="com.inon.apps.viewmodelsample.CountViewModel"/> </data> <androidx.constraintlayout.widget.ConstraintLayout android:layout_width="match_parent" android:layout_height="match_parent"> <TextView android:id="@+id/textView" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@{viewModel.text}" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toRightOf="parent" app:layout_constraintTop_toTopOf="parent" /> <Button android:id="@+id/button" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Count up" android:onClick="@{() -> viewModel.countUp()}" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@+id/textView" /> </androidx.constraintlayout.widget.ConstraintLayout> </layout>
基本的な、画面構成は変わりませんが、ルートのタグが ConstraintLayout
ではなく layout
に変わっています。
このDataBindingを適用するためのxml構成については、Android Studioの機能で自動生成できます。
(alt + Enterで出てくるメニューから「Convert to data binding layout」を選択する)
詳しくは、Codelabsのサンプルがわかりやすいです。
<data> <variable name="viewModel" type="com.inon.apps.viewmodelsample.CountViewModel"/> </data>
まずは、data
タグを使って作成したViewModelクラスをxml上に宣言します。
<TextView ... android:text="@{viewModel.text}" ...
次に、TextViewに対して、ViewModelのプロパティで宣言しているLiveDataのtextを紐付けます。
<Button ... android:onClick="@{() -> viewModel.countUp()}" ...
最後に、カウントアップのアクションをButtonに紐付けます。
DataBindingのセットアップ②(Activity)
最後にActivityにDataBindingを使うための準備処理を実装します。
import android.os.Bundle import androidx.appcompat.app.AppCompatActivity import androidx.databinding.DataBindingUtil import androidx.lifecycle.ViewModelProvider import com.inon.apps.viewmodelsample.databinding.ActivityMainBinding class MainActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) // NOTE: DataBindingUtilからBindingインスタンスを生成 val binding = DataBindingUtil.setContentView<ActivityMainBinding>(this, R.layout.activity_main) // NOTE: ライフサイクルオーナにActivityを指定しないとデータの管理が始まらない binding.lifecycleOwner = this val viewModel = ViewModelProvider(this).get(CountViewModel::class.java) binding.viewModel = viewModel } }
通常レイアウトを適用するには、 setContentView
メソッドを使うかと思いますが、これを DataBindingUtil
クラスが提供する setContentView
に置き換えます。
このメソッドは戻り値としてDataBindingのインスタンスを返すのですが、ActivityMainBinding
という今回作成していないクラスのインスタンスが返っています。
これは、xmlから自動生成されるDataBindingインスタンスです。(activity_main.xmlのためActivityMainBindingになっている)
DataBindingのインスタンスに対して、ライフサイクルのオーナーのインスタンス(Activityのインスタンス)を渡します。
そして、関連付けていたViewModelのインスタンスもDataBindingに紐付けます。
まとめ
DataBindingを使うと、LiveDataやそれに伴うイベントをxmlに宣言できるためActivityのコードは大分スッキリします。
基本的には、LiveData, ViewModel, DataBindingはセットで使うと良さそうです。