AndroidのデータバインディングとLiveDataを使ってみる
目次
データバインディングとLiveDataの背景
以前、Android Architecture Components(AAC)のViewModelについて紹介しました。 今回は、データバインディングとAACのLiveDataについて紹介したいと思います。
データバインディングを利用することで、表示の更新処理で煩雑にならずにActivityがシンプルに書けます。 また、LiveDataも併用することで、ViewModelの値を更新するだけでViewへ反映されるようにして、各クラスの責務がより明確にできます。
AACのViewModelは導入済みとして説明していきます。
データバインディングとLiveDataの適用手順
Databindingを導入する
build.gradle(project)に下記のようにkotlin-kaptを追加します。
1 2 3 4 5 6 |
[sourcecode lang="java"] apply plugin: 'com.android.application' apply plugin: 'kotlin-kapt' ・・・ [/sourcecode] |
build.gradle(app)に下記のようにdatabindingの項目を追加します。
1 2 3 4 5 6 7 8 9 10 11 |
[sourcecode lang="java"] android { ・・・ buildTypes{ ・・・ } dataBinding { enabled = true } } [/sourcecode] |
以上でDatabindingが使えるようになります。
ViewにDatabindingを適用する
データバインディングするViewのファイル(ここではres/layout/activity_main.xmlとします)にDatabindingを適用していきます。
まだ適用してない状態では、親となるLayoutとしてConstraintLayoutタグが配置されています。
1 2 3 4 5 6 7 8 9 10 11 12 |
[sourcecode lang="html"] <?xml version="1.0" encoding="utf-8"?> <android.support.constraint.ConstraintLayout 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" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".MainActivity"> ・・・ </android.support.constraint.ConstraintLayout> [/sourcecode] |
この状態から、このようにしてlayoutタグで囲って書き換えます。 また、Databindingで使用するデータをdataタグの中に定義しておきます。 今回はViewModelをViewにDatabindingします。 そして、TextViewの「android:text=”@{viewModel.name}”」と記述した箇所で、DatabindingしたViewModelの値を参照させるようにしています。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
[sourcecode lang="html"] <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="com.example.MainViewModel" /> </data> <android.support.constraint.ConstraintLayout android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".MainActivity"> ・・・ <TextView android:id="@+id/textName" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@{viewModel.name}" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toRightOf="parent" app:layout_constraintTop_toTopOf="parent" /> </android.support.constraint.ConstraintLayout> </layout> [/sourcecode] |
この後の手順のために、いったんここまででrebuildしておきましょう。
Activityとlayoutファイルを接続する
ActivityのsetContentViewを行う箇所を書き換えて、layoutとdatabindingのデータを連携させます。
書き換える前のonCreateは、下記のようになっています。
1 2 3 4 5 6 7 |
[sourcecode lang="swift"] override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) ・・・ } [/sourcecode] |
layoutファイル名をパスカルケースに変換して、末尾にBindingとつけたActivityMainBindingというようなクラスが自動生成されているはずです。 これを使用して、下記のようにsetContentViewの箇所を書き換えます。
1 2 3 4 5 6 |
[sourcecode lang="swift"] override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) val binding: ActivityMainBinding = DataBindingUtil.setContentView(this, R.layout.activity_main) } [/sourcecode] |
さらに下記のようにして、bindingインスタンスにviewmodelをセットするとデータが連携されます。 セットする際の名称はlayoutファイルで指定したdataタグの内容から自動生成されています。
1 2 3 4 5 6 7 8 9 10 11 12 |
[sourcecode lang="swift"] override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) val binding: ActivityMainBinding = DataBindingUtil.setContentView(this, R.layout.activity_main) viewmodel = ViewModelProviders.of(this).get(MainViewModel::class.java) binding.viewModel = viewmodel ・・・・ } [/sourcecode] |
エミューレータなどで実行してみると、ViewModelの値がViewに反映されて表示されます。 ただこの状態では、ViewModelの値が更新されてもViewには値が反映されません。
ViewModelからViewへデータ更新を反映する
ViewModelからViewへデータ更新を伝えるための方法はいくつかあります。 今回はAACのLiVeDataを使用してデータ更新を伝える実装をしてみます。
ViewModel導入の際にbuild.gradle (app) に 下記のようにライブラリを追加していれば、LiveDataも使えるようになっています。
1 2 3 4 5 6 7 8 9 10 |
[sourcecode lang="java"] android { ・・・ } dependencies { ・・・ implementation "android.arch.lifecycle:extensions:1.1.1" ・・・ } [/sourcecode] |
LiveDataを導入した状態のViewModelが下記になります。 MutableLiveDataというのが出てきていますが、ざっくり説明するとMutableLiveDataは更新用、LiveDataは参照用という感じになっています。 なので、VIewModelの外へ公開する変数はLiveDataで公開するようにします。
setNameを使用してMutableLiveDataにデータを更新すれば、Viewの方でもDatabindingでデータが反映されます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
[sourcecode lang="swift"] import android.arch.lifecycle.LiveData import android.arch.lifecycle.MutableLiveData import android.arch.lifecycle.ViewModel class MainViewModel : ViewModel() { private var mName: MutableLiveData<String> = MutableLiveData() var name: LiveData<String> = mName fun setName(name: String) { mName.postValue(name) } fun getName(): String { return if (mName.value != null) mName.value!! else "test" } } [/sourcecode] |
まとめ
DatabindignとLiveDataを利用することで、表示の更新処理で煩雑にならずにActivityがシンプルに書けました。 また、ViewModelに値を更新するだけでViewへ反映されるようになるため、各クラスの責務がより明確にできました。