5
4

More than 3 years have passed since last update.

Data Bindingのセットアップ&使い方(Kotlin)

Last updated at Posted at 2021-08-25

はじめに

Data Bindingのセットアップ方法と使い方を紹介します。

「Data Binding」とは?

Googleが提供しているJetpackのコンポーネントです。
UIコンポーネントとデータソースを、コードでなく宣言的にバインドできるようになります。

環境

  • OS:macOS Big Sur 11.5.2
  • Android Studio:Arctic Fox | 2020.3.1 Patch 1
  • Kotlin:1.5.21
  • Gradle:7.0.2
  • Gradle plugin:7.0.1

セットアップ

Data Bindingの有効化

appフォルダ配下の「build.gradle」でData Bindingを有効化します。

/app/build.gradle
android {
+   buildFeatures {
+       dataBinding true
+   }
}

これでData Bindingのセットアップは完了です。

使い方

フラグメントでData Bindingする

以下の記事で説明したフラグメントを、View BindingからData Bindingに変更します。

レイアウトファイルの編集

Data Bindingするには、レイアウトファイルのルートタグを layout に変更する必要があります。
忘れがちなので注意しましょう。

monster_detail_fragment.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">

    <androidx.constraintlayout.widget.ConstraintLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical"
        tools:context=".ui.monsterdetail.MonsterDetailFragment">

        <ImageView
            android:id="@+id/icon_imageview"
            android:layout_width="240dp"
            android:layout_height="240dp"
            android:layout_marginTop="56dp"
            android:contentDescription="@string/icon_description"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent"
            app:layout_constraintVertical_bias="0.0"
            app:layout_constraintVertical_chainStyle="packed"
            tools:src="@tools:sample/avatars" />

    </androidx.constraintlayout.widget.ConstraintLayout>
</layout>

ルートタグを変更したら、バインドしたいプロパティを data タグに追加します。
今回は monster プロパティを対象とします。

MonsterDetailFragment.kt
class MonsterDetailFragment : Fragment() {
    private val monster: MonsterItem = ○○
}
monster_detail_fragment.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="monster"
+           type="com.theuhooi.uhooipicbook.ui.monsterlist.entities.MonsterItem" />
+   </data>
+ 
    <androidx.constraintlayout.widget.ConstraintLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical"
        tools:context=".ui.monsterdetail.MonsterDetailFragment">

        <ImageView
            android:id="@+id/icon_imageview"
            android:layout_width="240dp"
            android:layout_height="240dp"
            android:layout_marginTop="56dp"
            android:contentDescription="@string/icon_description"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent"
            app:layout_constraintVertical_bias="0.0"
            app:layout_constraintVertical_chainStyle="packed"
            tools:src="@tools:sample/avatars" />

    </androidx.constraintlayout.widget.ConstraintLayout>
</layout>

ただ iconImageView にバインドしたいのは monster.iconUrlString であり、 ImageView にはURLをレイアウトファイルから紐付ける機能がありません。

バインディングアダプターの実装

そこでバインディングアダプターの出番です。
レイアウトファイルでバインドできるよう、アダプターを用意します。

バインディングアダプターは util/ViewBindingAdapters.kt のように1ファイルにまとめることが多いようです。

util/ViewBindingAdapters.kt
@BindingAdapter("imageUrl")
fun load(imageView: ImageView, imageUrl: String?) {
    imageView.load(imageUrl)
}

メソッドの第1引数に対象のビュー、第2引数に渡したい値を記述します。

@BindingAdapter アノテーションにはレイアウトファイルに記述する名前を付けます。
基本的には第2引数と同名でいいと思います。

レイアウトファイルでバインディング

アダプターを実装したら、レイアウトファイルでバインディングします。

monster_detail_fragment.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="monster"
            type="com.theuhooi.uhooipicbook.ui.monsterlist.entities.MonsterItem" />
    </data>

    <androidx.constraintlayout.widget.ConstraintLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical"
        tools:context=".ui.monsterdetail.MonsterDetailFragment">

        <ImageView
            android:id="@+id/icon_imageview"
            android:layout_width="240dp"
            android:layout_height="240dp"
            android:layout_marginTop="56dp"
            android:contentDescription="@string/icon_description"
+           app:imageUrl="@{monster.iconUrlString}"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent"
            app:layout_constraintVertical_bias="0.0"
            app:layout_constraintVertical_chainStyle="packed"
            tools:src="@tools:sample/avatars" />

    </androidx.constraintlayout.widget.ConstraintLayout>
</layout>

レイアウト式は @{} で括ることで記述できます。
補完が効くので便利です。

レイアウト式では演算子やメソッドを呼び出せますが、単体テストができないため、シンプルにすることが推奨されています。
シンプルにする手段の一つとして、先ほど実装したバインディングアダプターがあります。

コードによるバインディング処理を削除

コードによるバインディング処理は不要になったため削除します。

MonsterDetailFragment.kt
class MonsterDetailFragment : Fragment() {
    private var _binding: MonsterDetailFragmentBinding? = null
    private val binding get() = _binding!!

    private val monster: MonsterItem = ○○

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)

-       binding.iconImageview.load(monster.iconUrlString)
    }
}

おわりに

これでバインディングがレイアウトファイルのみで完結できました!
レイアウトファイルが単体テストできないことを念頭に置きつつ、有効活用していきましょう :relaxed:

今回は紹介しませんでしたが、双方向バインディングという機能も便利です。
私は使ったことがないので、機会があれば使いたいです。

参考リンク

5
4
3

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
4