Android
Kotlin
DataBinding

Android + Kotlin + DataBinding

この前、Kotlin Android Extensionsを使って感動してたら、友達から、DataBinding使うのが昨今のAndroidプロジェクトでは一般的と教わったので、使ってみます。

環境

Android Studio 3.1.2

DataBindingとは

ViewModelを作っておいて、そこの値を変えれば、xml上のプロパティに自動でアクセスしてくれるものらしい。Activityに、Viewへのアクセスをごちゃごちゃ書かなくてスッキリ管理しやすくなる模様。逆にプロパティが変わったらViewModelの値を変えるということもできるらしい。

簡単なサンプルを作ってみる

今回は、ViewであるTextViewtextと、ViewModelnameを紐付けしてみたいと思います。

MyAppAという名前でプロジェクトを作ったら、build.gradleに2箇所追加します。

app/build.gradle
apply plugin: 'kotlin-kapt' // ここを追記

android {
    ...
    // ここを追記
    dataBinding {
        enabled = true
    }
}

続いて、viewmodelフォルダを作成し、その中に MainViewModel クラスを作成。

MainViewModel.kt
package com.funeasysoft.myappa.viewmodel

class MainViewModel {
    var name = "funeasy"
}

紐づけるxmlファイルを編集。

activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools">

    <data>

        <variable
            name="viewModel"
            type="com.funeasysoft.myappa.viewmodel.MainViewModel" />
    </data>

    <android.support.constraint.ConstraintLayout xmlns:app="http://schemas.android.com/apk/res-auto"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context=".MainActivity">

        <TextView
            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>

元々のLayoutを、<Layout> で囲み、<data>を追加し、ViewModelクラスを指定している。また、今回はTextViewtextとdataBindingするために、android:text="@{viewModel.name}"とします。

ここで注意が必要で、元々ConstraintLayoutに付いている
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
は、消しておかないといけない。
消さないと以下のようなエラーになってしまう。

error: duplicate attribute.
Message{kind=ERROR, text=error: duplicate attribute., sources=[/Users/masa/DevAndroid/MyAppA/app/src/main/res/layout/activity_main.xml:13], original message=, tool name=Optional.of(AAPT)}

最後にActivityへ、関連付けします。

MainActivity.kt
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        // setContentView(R.layout.activity_main) // コメントアウト

        val binding = DataBindingUtil.setContentView<ActivityMainBinding>(this, R.layout.activity_main)
        binding.viewModel = MainViewModel()
    }

実行すると、画面に、 MainViewModel クラスの name に入れた funeasy が表示されました。

image.png

ボタンをクリック -> TextViewを変える

buttonClicked()を追加します。また、viewModel.name が変更されたら、表示もかわるように、ObservableField("[初期値]")に変更します。

MainViewModel.kt
package com.funeasysoft.myappa.viewmodel

import android.databinding.ObservableField

class MainViewModel {
    var name = ObservableField("funeasy")

    fun buttonClicked() {
        name.set("Button clicked!")
    }
}

Buttonを追加、android:onClick="@{() -> viewModel.buttonClicked()}"を設定しておく。

activity_main.xml
<?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"
    xmlns:tools="http://schemas.android.com/tools">

    <data>
        <variable
            name="viewModel"
            type="com.funeasysoft.myappa.viewmodel.MainViewModel" />
    </data>

    <android.support.constraint.ConstraintLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context=".MainActivity">

        <TextView
            android:id="@+id/textView"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:text="@{viewModel.name}"
            app:layout_constraintLeft_toLeftOf="parent"
            app:layout_constraintRight_toRightOf="parent"
            app:layout_constraintTop_toTopOf="parent" />

        <Button
            android:id="@+id/button"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_marginTop="20dp"
            android:text="Button"
            android:onClick="@{() -> viewModel.buttonClicked()}"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toBottomOf="@+id/textView" />

    </android.support.constraint.ConstraintLayout>
</layout>

ボタンをタップすると、確かにテキストが変更されました!

image.png

今後色々とMainViewModelをカスタムして、どれだけ楽になるのかみていこうと思います。