SONICMOOV Googleページ

AndroidのデータバインディングとLiveDataを使ってみる

AndroidのデータバインディングとLiveDataを使ってみる

  • このエントリーをはてなブックマークに追加

目次

データバインディングと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へ反映されるようになるため、各クラスの責務がより明確にできました。

  • このエントリーをはてなブックマークに追加

記事作成者の紹介

カワニシ(フロントエンドエンジニア)

悶絶ブラックなシステムエンジニアからジョブチェンジして、島根でゆるふわにお仕事をしています。 島根でエンストしてるオープンカーがいたら私です。

フロントエンドエンジニア募集中!

×

SNSでも情報配信中!ぜひご登録ください。

×

SNSでも
情報配信中!
SONICMOOV Facebookページ SONICMOOV Twitter SONICMOOV Googleページ
フロントエンドエンジニア募集中!

新着の記事

mautic is open source marketing automation