うさがにっき

読書感想文とプログラムのこと書いてきます

DataBindingを使ったLayoutの実装(xml編)

概要

DataBindingを使えばjava側でviewの操作などをxmlで完結することができる
ButterKnifeなどを使えばある程度は簡略化できるが、よりプレゼンテーションとロジックを切り離して考えられる様子
その他にも色々できるみたいだが、とりあえずlayout xml内でできることをまとめてみた

詳細

準備

実行環境

  • AndroidStudio 2.1 preview 3
  • Android 6.0.1

DataBindingを有効にするには、build.gradleに以下を追記する

android {
    ....
    dataBinding {
        enabled = true
    }
}

実装

  1. Layout XMLを作成し、Data Binding用の記述
  2. Data Bindingに利用するデータとなるクラスを作成
  3. 生成されたBindingクラスを確認
  4. DataBindingUtilクラスを使ってレイアウトを初期化
  5. Bindingクラスに対してバインドするデータをセット
Layout XMLを作成し、Data Binding用の記述
<?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="article"
            type="com.example.a01011818.canalytest.Article" />
    </data>

    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context="com.example.a01011818.canalytest.MainActivity">

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@{article.title}" />
    </RelativeLayout>
</layout>

以下がData Bindingのために追加された要素

layout Data Binding Libraryで処理をするレイアウトであることを示す要素
data レイアウトないで利用する変数を宣言するための親要素
variable 変数を宣言する要素、name属性で変数名、type属性で型を定義

variableタグを入力するだけでname, typeがオートフィルされていい感じ

以下のようにvariable要素で宣言した変数はレイアウト上の属性値で利用できる

android:text="@{article.title}"
Data Bindingに利用するデータとなるクラスを作成

次にvariable要素、type属性で宣言していたcom.example.a01011818.canalytest.Articleクラスを作成
ここはオートフィルきいてくれなくて、めんどくさかった

package com.example.a01011818.canalytest;

public class Article {
    public String title;

    public Article(String title) {
        this.title = title;
    }

    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {
        this.title = title;
    }
}

プロパティはpublicであるか、getter, setterを持っている必要がある
この時点で、activity_main.xmlに対応するBindingクラスが生成されている

DataBindingUtilクラスを使ってレイアウトを初期化
Bindingクラスに対してバインドするデータをセット
public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        // DataBindingUtilクラスを使ってレイアウトを初期化する
        ActivityMainBinding binding = DataBindingUtil.setContentView(this, R.layout.activity_main);

        Article article = new Article("Hello Main!!");

        // ここでデータをバインド
        binding.setArticle(article);
    }
}

実行結果

f:id:tiro105:20160319225853p:plain

Data Binding Layout XMLでできること

import

importしておくとクラスを簡単に参照できる

<data>
    <import type="com.example.a01011818.canalytest.Article" />
    <variable
        name="article"
        type="Article" />
</data>

別名をつけることもできる

<data>
    <import type="com.example.a01011818.canalytest.Article" 
        alias="MyArticle"/>
    <variable
        name="article"
        type="MyArticle" />
</data>
Bindingクラスに別名をつける

Bindingクラス名は次の規則に沿って決まる

  1. パッケージ名はアプリケーションID.databinding(でもAndroidStudioからは見えない)
  2. Layout XMLのファイル名をキャメルケースに
  3. suffixにBindingを付ける

これを変更することができる

<data class=".binding.Mainbinding">
</data>

というように属性で指定するとBindingクラス名を指定できる

式を利用する

Layout XMLは式の利用を一部サポートしている
android.text.TextUtilsを使って三項演算子を使ってみる

<layout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools">
    <data>
        <import type="com.example.a01011818.canalytest.Article" />
        <import type="android.text.TextUtils" />
        <variable
            name="article"
            type="Article" />
    </data>

    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context="com.example.a01011818.canalytest.MainActivity">

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text='@{TextUtils.isEmpty(article.title) ? "empty" : article.title}' />
    </RelativeLayout>
</layout>
NULL合体演算子

Layout XMLではNULL合体演算子というものが使える
次のように左辺がnullでなければ左辺、nullだったら右辺値を返却する

android:text="@{article.title ?? String.valueOf(article.id)}"
条件に合わせてリソースを変更

プロパティの値や定数だけでなく、リソースも式の返却値にできる

android:padding="@{large ? (int)@dimen/large_margin : (int)@dimen/small_margin}"
引数を持つリソース

stringリソースの引数をとってformatする場合にも対応している

string.xml

<string name="title">Title:%1$s</string>

Layout XML

<TextView
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text='@{@string/title(article.title)}' />

感想

かなりXMLでいろいろなことができるようになり、ViewとLogicをわけられそう
だけどLogic書きすぎると一昔前のJSP地獄になりそうで、さじ加減が大切