プロジェクト

全般

プロフィール

Androidプログラミング-DataBinding

概要

2010年代中頃までのAndroidのアプリケーション構造は、ビューとなるレイアウトXML、コントローラとなるActivity/Fragment、モデルとなる任意のクラス(POJOまたはContentProvider)から構成されていました。画面に表示する内容(文字列、画像、等)は、コントローラが仲立ちし、モデルのデータ構造を文字列等に変換し適切なビューに設定することで実現していました。モデルのデータの変更はオブザーバパターンを作り込み、コントローラで検出してビューに反映していました。このため、コントローラが肥大化する傾向が高く俗にファットコントローラというアンチパターンに陥りがちです。

そこで、モデルとビューを直結し、モデルのデータをビュー側で表示形式に変換し、またデータの変更も自動で反映(LiveDataを中継することで)できるようにしたものが DataBindingです。

コントローラがすることは、データバインディングの初期化とビュー側で参照するモデルの設定だけになります。

ざっと使い方メモ

レイアウトXMLのDataBinding対応

レイアウトXMLのルート要素をlayoutとする

<?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">

    :(中略)

</layout>

参照したいデータ(インスタンス)を定義する

<layout ...>

    <data>
        <variable
            name="viewModel" 
            type="com.torutk.android.temprecorder.jetpackkt.MainViewModel" />
    </data>

</layout>
  • ルート要素layoutの子要素にdata要素を定義、その子要素にvariable要素を定義
  • variable要素のname属性は、レイアウトXMLの中で参照するときのインスタンス名(任意の名前で可)

ActivityにてBindingの生成と参照するデータの設定

class MainActivity : AppCompatActivity() {

    private val temperatureViewModel: MainViewModel by viewModels { MainViewModel.Factory(this.application) }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        val binding: ActivityMainBinding = DataBindingUtil.setContentView(this, R.layout.activity_main)  // (1)
        binding.lifecycleOwner = this  // (2)
        binding.viewModel = temperatureViewModel  // (3)

  • (1) コンパイル時に、DataBinding定義を持つレイアウトXML(ここではactivity_main.xml)の拡張子を除いた名前(activity_main)をパスカル形式に変換して(ActivityMain)末尾にBindingを追加した名前(ActivityMainBinding)のクラスが自動生成されます。
    このクラスのインスタンスは、DataBindingUtilのsetContentViewメソッドを呼び生成します。
  • (2) LiveDataを使う際にデータの更新を自動的に反映させるためにはlifecycleOwnerをセットします。
  • (3) レイアウトXMLで参照するデータを設定します。バインディングのプロパティ名は、variable要素のname属性です。
bindingをローカル変数ではなくプロパティにする場合

onCreateメソッド以外でbindingを使用したい場合は、bindingをプロパティとします。

class MainActivity : AppCompatActivity() {

    private val binding: ActivityMainBinding by lazy {
        DataBindingUtil.setContentView(this, R.layout.activity_main)
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding.lifecycleOwner = this

ビューの表示設定

属性プロパティ形式

variable要素の名前から辿れるプロパティを表示に使うことができます。@{} 構文で属性プロパティ形式で記述します。

       <TextView
            :
            android:text="@{viewModel.submitTitle}" 
        />

android:text属性はString型なので、String型を戻り値型とするviewModelのgetSubmitTitle()メソッド、あるいは submitTitle()メソッドを呼び、その結果を設定します。ただしメソッドの戻り値型がString型でない場合はTextViewのtext属性に設定できないため、変換が必要となります。

式言語

DataBindingではXMLファイル中に「式言語」でデータ参照を記述します。先の属性プロパティ形式は式言語の一つの形式です。
式言語では、Javaのコードを呼び出すことができます。

       <TextView
            :
            android:text="@{String.valueOf(viewModel.index + 1)}" 
       />

他のビューの参照、リソースの参照なども可能です。
他のビューの属性を参照するときは、式言語中にビューのID名をキャメルケースにした名称を使用します。

イベントの対応付け(ボタン押下時の処理)

       <Button
            :
            android:onClick="@{() -> viewModel.incrementMeasurementAt(10)}" 
       />

ボタン押下時に、ラムダ式でviewModelのincrementMeasurementAtメソッドを呼び出します。