目次
データバインディングとLiveDataの背景
以前、Android Architecture Components(AAC)のViewModelについて紹介しました。
今回は、データバインディングとAACのLiveDataについて紹介したいと思います。
データバインディングを利用することで、表示の更新処理で煩雑にならずにActivityがシンプルに書けます。
また、LiveDataも併用することで、ViewModelの値を更新するだけでViewへ反映されるようにして、各クラスの責務がより明確にできます。
AACのViewModelは導入済みとして説明していきます。
データバインディングとLiveDataの適用手順
Databindingを導入する
build.gradle(project)に下記のようにkotlin-kaptを追加します。
apply plugin: 'com.android.application' apply plugin: 'kotlin-kapt' ・・・
build.gradle(app)に下記のようにdatabindingの項目を追加します。
android { ・・・ buildTypes{ ・・・ } dataBinding { enabled = true } }
以上でDatabindingが使えるようになります。
ViewにDatabindingを適用する
データバインディングするViewのファイル(ここではres/layout/activity_main.xmlとします)にDatabindingを適用していきます。
まだ適用してない状態では、親となるLayoutとしてConstraintLayoutタグが配置されています。
<?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>
この状態から、このようにしてlayoutタグで囲って書き換えます。
また、Databindingで使用するデータをdataタグの中に定義しておきます。
今回はViewModelをViewにDatabindingします。
そして、TextViewの「android:text=”@{viewModel.name}”」と記述した箇所で、DatabindingしたViewModelの値を参照させるようにしています。
<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>
この後の手順のために、いったんここまででrebuildしておきましょう。
Activityとlayoutファイルを接続する
ActivityのsetContentViewを行う箇所を書き換えて、layoutとdatabindingのデータを連携させます。
書き換える前のonCreateは、下記のようになっています。
override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) ・・・ }
layoutファイル名をパスカルケースに変換して、末尾にBindingとつけたActivityMainBindingというようなクラスが自動生成されているはずです。
これを使用して、下記のようにsetContentViewの箇所を書き換えます。
override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) val binding: ActivityMainBinding = DataBindingUtil.setContentView(this, R.layout.activity_main) }
さらに下記のようにして、bindingインスタンスにviewmodelをセットするとデータが連携されます。
セットする際の名称はlayoutファイルで指定したdataタグの内容から自動生成されています。
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 ・・・・ }
エミューレータなどで実行してみると、ViewModelの値がViewに反映されて表示されます。
ただこの状態では、ViewModelの値が更新されてもViewには値が反映されません。
ViewModelからViewへデータ更新を反映する
ViewModelからViewへデータ更新を伝えるための方法はいくつかあります。
今回はAACのLiVeDataを使用してデータ更新を伝える実装をしてみます。
ViewModel導入の際にbuild.gradle (app) に 下記のようにライブラリを追加していれば、LiveDataも使えるようになっています。
android { ・・・ } dependencies { ・・・ implementation "android.arch.lifecycle:extensions:1.1.1" ・・・ }
LiveDataを導入した状態のViewModelが下記になります。
MutableLiveDataというのが出てきていますが、ざっくり説明するとMutableLiveDataは更新用、LiveDataは参照用という感じになっています。
なので、VIewModelの外へ公開する変数はLiveDataで公開するようにします。
setNameを使用してMutableLiveDataにデータを更新すれば、Viewの方でもDatabindingでデータが反映されます。
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" } }
まとめ
DatabindignとLiveDataを利用することで、表示の更新処理で煩雑にならずにActivityがシンプルに書けました。
また、ViewModelに値を更新するだけでViewへ反映されるようになるため、各クラスの責務がより明確にできました。