【Android】はじめてのDataBinding

[前回の記事：【Android】分かった気になれる！アーキテクチャ・MVVM概説](https://qiita.com/iTakahiro/items/6b1b22efa69e55cea3fa) では
アーキテクチャの概要をコードを記述せずに概念のみ説明してみました。
今後は各ライブラリを実際にコードを書いて導入してみることで
アーキテクチャと各種ライブラリを理解し、身につけていきたいと思っています。

このアーキテクチャシリーズ実践編第一回目として
今回は、Googleが提供するJetPackに含まれるDataBindingライブラリを
実践しながら簡単に説明していきたいと思います。

だらだらと書くのも楽しくないので、
今回は私が愛して止まないアメリカンフットボールのルール・魅力を
間に挟みながらDataBindingを説明していきたいと思います。

気になったワードがあれば、ぜひ調べてみてくださいね

# はじめに
本記事では、DataBindingとLiveDataを用いて添付のGIF画像のような挙動を実装しようと思います。

この画面の特徴は以下の通りです。

- Buttonタップ時
  - EditTextに入力されたテキストがTextViewに表示される
- EditTextに何も入力されていないとき
  - Buttonは押せない
  - テキストは「Ready」
- EditTextにテキストが入力されているとき
  - Buttonは押せる
  - テキストは「Set!!!」

本記事では、Buttonに関するDataBindingに注目していきます。

**実装したいこと**
![data_binding.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/296819/8cb6948e-ce7e-7252-a15a-ad8b8c182a2a.gif)

これに似た画面には以下のようなものが挙げられます。

- ユーザーIDとパスワードが入力されている場合のみボタンを押せるようなログイン画面
- 利用規約にチェックされている場合のみ次に進めるような画面

### 簡単な環境

AndroidXを導入したプロジェクトで実装を行いました。
これは、プロジェクトを作成するときに`Use androidx.* artifacts`にチェックを入れるか
`Refactor > Migrate to AndroidX...`することで対応できると思います。

AndroidXについてはこちらを参照：
[AndroidX の概要](https://developer.android.com/jetpack/androidx?hl=ja) : Google公式

今回の実装ではそれほど影響はないと思われますが
ハマってしまうかもしれないので。
（おおよそデフォルトになっていると思いますが、念のため）

## 元のコード

今回はDataBindingの使い方を分かりやすくするために
ごく簡単なレイアウトを用いて説明したいと思います。

`MainActivity`は、FrameLayoutを載せただけのシンプルなレイアウトです。
そのFrameLayoutに`FootballFragment`と言うFragmentを表示することにします。

（
ちなみに、アメフトはAmerican Footballの略です。
Footballといえば、
多くの国ではSoccerのことを指しますが
アメリカではAmerican Footballのことを指すのが一般的です。
日本開催で大いに盛り上がったラグビーも実は
正式名称Rugby Footballなので、Footballの一種です。
）

```kotlin:MainActivity.kt
class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        supportFragmentManager.beginTransaction()
            .replace(R.id.frameLayout, FootballFragment())
            .commit()
    }
}
```
```xml:activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <FrameLayout
        android:id="@+id/frameLayout"
        android:layout_width="match_parent"
        android:layout_height="match_parent">

    </FrameLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
```

`FootballFragment`は以下のコードのように
LinearLayoutにTextView・EditText・Buttonを配置したシンプルなレイアウトです。
ところどころ見た目を改善する処理は記述していますが。

```xml:fragment_football.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:gravity="center"
    android:orientation="vertical"
    android:padding="32dp">

    <TextView
        android:id="@+id/textView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="ここに出力されます" />

    <EditText
        android:id="@+id/editText"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="32dp"
        android:layout_marginBottom="32dp"
        android:hint="アメフトのルールや魅力は?"
        android:textAlignment="center" />

        <Button
            android:id="@+id/button"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            tools:text="Ready" />
</LinearLayout>
```
textをstringで定義していないなど細かいことは置いといて
DataBindingだけに集中してもらえればと思います。

# DataBindingの導入

さて、いよいよDataBindingを導入します。
以下の項目の順に実装していきます。

- appレベルのbuild.gradle
- fragment_football.xml

### build.gradle(Module:app)に関して

appレベルの`build.gradle`にて、
以下のコードを記述しDataBindingを有効にします。

```gradle:build.gradle(app)
android {
    // 略
    dataBinding {
        enabled true
    }
}
```

さらに、Kotlinで開発しているのであれば下図で示されるようなサジェストが出るので
トップレベルに`apply plugin: 'kotlin-kapt'` を追加した上で
`Sync Now`で同期し対応しておきます。
<img width="684" alt="スクリーンショット 2019-11-04 18.51.11.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/296819/2f36eb3c-0bae-8b36-9610-0a0c58cf6b62.png">

これで、DataBindingの導入は終わりです。簡単ですね。
アメフトで言えば、キックオフリターンが終了しリターンチームが攻撃を開始する頃でしょうか。

さて次は、レイアウトファイルをDataBindingで使える形に変換していきます。

### レイアウトファイルに関して

DataBindingを有効化した後
レイアウトファイルを、DataBindingを使用できる状態にします。

**元のレイアウトファイル**

```xml:fragment_football.xml
<LinearLayout xmlns:android="http://schemas.androidd.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:gravity="center"
    android:orientation="vertical">
    <!--略-->
</LinearLayout>
```

レイアウトファイルにおいて
親のView(ここではLinearLayout)にカーソルを当て
`option + Enter`を押すと下図のようなダイアログが表示されます。

<img width="524" alt="convert_to_databinding.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/296819/9bd611be-8196-422f-ad8a-0c3dfe6b43e5.png">

この`Convert to data binding layout`を選択すると
レイアウトがDataBinding用に変換されます。

**DataBinding用に変換したレイアウトファイル**

```xml:fragment_football.xml
<layout xmlns:android="http://schemas.android.com/apk/res/android">

    <data>

    </data>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:gravity="center"
        android:orientation="vertical">
        <!--略-->
    </LinearLayout>
</layout>
```

元のレイアウトファイルと変換後のレイアウトファイルの比較をまとめると以下のようになります。

||元のレイアウトファイル|変換後のレイアウトファイル|
|---|---|---|
|親View|LinearLayout|layout|
|dataタグ|なし|layoutとLinearLayoutの間|

これでDataBindingの基本的な導入は完了しました。

本当に完了でしょうか？
いいえ、まだ残っています。アメフトで言えば1Q残り2分ですね。
最後にビルドを実行し、DataBinding用を自動生成して完了です。

これでひとまず、1Qは終了です。
CMです。

(アメフトの試合は　1Q: 15分で4Qまで、計60分で行われます。
が、ゲーム中時間は止まるため実際は3,4時間かかります。長丁場なんですね。)


# レイアウトファイルとコードの結びつけ

次は実際に、レイアウトファイルとコードを紐づけていきます。
まず、レイアウトファイルに関して。

### レイアウトファイルに関して

先ほどのレイアウトファイルにおいて
dataタグ内にDataBindingしたい変数を定義していきます。

name: 変数名
type: 型
となっており、typeにはStringやIntなどはもちろん
独自で作成したクラスも入れることができます。
その場合は階層からクラス名を指定する必要があります。：
e.g. `type="com.hoge.QB"`, `type="com.hoge.Audible"`, ...

```xml:fragment_football.xml
    <data>

        <variable
            name="buttonText"
            type="String" />
    </data>
```

このように定義された変数は、以下の役割を担うことができるようになります。

- 外部ファイルから対象の値を取得
- 外部ファイルに対象の値を渡す
- レイアウトファイルから対象の値を取得
- レイアウトファイルに対象の値を渡す

つまり、別ファイルとこのレイアウトファイルの両方からアクセスできるようになります。
通常は、外部ファイルから取得した値をレイアウトファイルに単一方向に渡すことが多いです。
レイアウトファイルから外部ファイルに値を渡す場合のDataBindingは双方向DataBindingと呼ばれ
処理が異なったり、追加で処理が必要になったりします。
ちなみに今回は、双方向DataBindingは行いません。

次に、定義した変数を代入します。
`@{name}`のように記述するだけでDataBindingを実装できます。
例えば、`android:text="@{buttonText}"`と言った具合です。

```xml:fragment_football.xml
        <Button
            android:id="@+id/button"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="@{buttonText}"
            tools:text="Ready" />
```

これで、`button`の`android:text`と`buttonText`が結びつきました。

つまり、`button`の`android:text`の値の設定を
`buttonText`を通すことで別ファイルのコード上でも設定できるようになりました。

ここで、こんな疑問を持った方はいるのではないでしょうか？
**そんなことしなくても、適当なKotlinファイル内で`button.text = "Ready, Set Hut!!!"`のように記述すれば値をセットできるのではないか**、と。

その通りです。
こんなことしなくても別ファイルからコード上で値をセットすることは可能です。
しかし、こうすることで格段と値の管理が簡単になる場合があるのです。

それはユーザー操作などにより変更された値を
即座に`View`に反映させたい場合などです。
変更された値の反映をコード上で実装しようとすると
記述量が増えコードが煩雑になってしまう可能性があります。

それが、後述するLiveDataとともにDataBindingを利用することで
より簡潔にスマートにコードを書けるようになるのです。

その実装は後ほど、後半戦で実装します。

### 別ファイルのFragmentクラスにおいて

次に、DataBindingを適用したレイアウトファイルをFragmentクラスに結びつけます。
onCreateViewでレイアウトファイルと結びつけます。

**DataBindingを実装しない場合**

```kotlin:FootballFragment.kt
class FootballFragment : Fragment() {
    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        return inflater.inflate(R.layout.fragment_football, container, false)
    }
}
```
DataBindingを実装しない場合、通常であれば上記のように実装すると思われます。
`inflater`でレイアウトファイルを指定し`inflate`することで
レイアウトファイルとFragmentクラスのコードを結びつけています。

一方、DataBindingを用いた場合の実装例は下記の通りです。

**DataBindingを実装する場合**

```kotlin:FootballFragment.kt
class FootballFragment : Fragment() {

    private lateinit var binding: FragmentFootballBinding

    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        binding = FragmentFootballBinding.inflate(inflater, container, false)
        return binding.root
    }
}
```

上記で示される`FragmentFootballBinding`クラスは
`ViewDataBinding`クラスを継承したクラスで、
実は、レイアウトファイルでDataBindingを実装しビルドした際に作られていました。
それをここでは`binding`として定義し、
`FragmentFootballBinding`の`inflate`メソッドを用いてインスタンス化しています。

そして、onCreateViewの戻り値に`binding.root`を指定することで
`FootballFragment`のレイアウトを設定することができます。
詳しくは、こちらを参照：
[Generated binding classes](https://developer.android.com/topic/libraries/data-binding/generated-binding.html) : Google公式ガイド

これで、ひとまずレイアウトを設定することができました。

アメフトで言えば、前半残り2分：2 minutes warning
あたりでしょうか。

### DataBindingしてみよう!
ここで、`binding`を使ってテキストをセットしてみましょう!

```kotlin:FootballFragment.kt
    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)

        binding.buttonText = "Crouch, Bind, Set!!"  // これはラグビー
    }
```
このように`binding.buttonText`とすることで
レイアウトファイルで定義した`String`クラスの`buttonText`を呼び出し、値をセットできます。
それにより、レイアウトファイルの`button`における`android:text`に
`buttonText`の値`Crouch, Bind, Set!!`がセットされます。
（ただ、この程度の実装では、前述の通り`button.text`を呼び出すだけでいいと思います）

以下の実行結果では、Buttonに`Crouch, Bind, Set!`のテキストが表示されていることが確認できます。
(Buttonのテキストがデフォルトで大文字なので大文字にはなっていますが)

**実行結果**
![databinding_without_livedata.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/296819/5ef6048e-01df-0da1-3c03-abce247bfa7d.gif)


# LiveDataを実装

後半戦キックオフ。

次にお待ちかね(かどうかは分かりませんが)、LiveDataを実装します。
以下の順で実装していきます。

- ViewModelの作成
- 各種LiveDataの作成
- レイアウトファイルにViewModelを導入
- LiveDataの更新メソッドを作成
- FragmentクラスにViewModelを導入

ViewModelとは? LiveDataとは? MVVMとは? と言う方はこれらを参照してみてください

- [【Android】分かった気になれる！アーキテクチャ・MVVM概説](https://qiita.com/iTakahiro/items/6b1b22efa69e55cea3fa) : 過去の記事
- [Android Architecture Components](https://developer.android.com/topic/libraries/architecture?hl=ja) : Google公式ガイド
- [ViewModel](https://developer.android.com/topic/libraries/architecture/viewmodel?hl=ja) : Google公式ガイド
- [LiveData](https://developer.android.com/topic/libraries/architecture/livedata?hl=ja) : Google公式ガイド
- [MVVM](https://developer.android.com/jetpack/docs/guide?hl=ja) : Google公式ガイド

### ViewModelの作成・LiveDataの作成

早速、`FootballViewModel`を作成します。
（今回は、`ViewModel()`を継承しないLiveDataを保持するだけのViewModelを作成します。
`ViewModel()`を継承する場合はViewModel生成の際に別途処理が必要になります。）

その後、変更を検知したいデータに対して、MutableLiveData、およびLiveDataを作成します。

**LiveData**は、値がセットされたときに値がセットされたことを検知できるクラスです。
実際に値をセットされるのはMutableLiveDataで、
LiveDataに直接値をセットされることはありません。

**MutableLiveData**は、その名の通り値の変更が可能なLiveDataで、
LiveDataの値を取得するとMutableLiveDataの値が返されるよう実装します。
また、ここでは下記のコードのようにスコープ関数を用いて初期値を設定しています。

下記コードは`FootballViewModel`の一部を抜粋したものです

```kotlin:FootballViewModel.kt
class FootballViewModel {
    // 略
    private val _buttonText: MutableLiveData<String> =
        MutableLiveData<String>().also { mutableLiveData ->
            mutableLiveData.value = "Ready"
        }
    val buttonText: LiveData<String>
        get() = _buttonText
}
```

### レイアウトファイルにViewModelを導入

レイアウトファイルのdataタグで定義した変数`buttonText`を削除し、`vm`(ViewModel)を変数に設定します。
また、`button`にて設定していた`@{buttonText}`は`@{vm.buttonText}`に変更し、
ViewModelを経由して`buttonText`の値を取得するよう変更します。

（少し疲れてきました。頭を整理するため、タイムアウトを取ります。。）

**変更前**

```xml:fragment_football.xml
    <data>

        <variable
            name="buttonText"
            type="String" />
    </data>

    <LinearLayout>
　　　　　<!--略--> 
        <Button
            android:id="@+id/button"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="@{buttonText}"
            tools:text="Ready" />
    </LinearLayout>
```

**変更後**

```xml:fragment_football.xml
    <data>

        <variable
            name="vm"
            type="io.github.itakahiro.databindingfootball.FootballViewModel" />
    </data>

    <LinearLayout>
　　　　　<!--略--> 
        <Button
            android:id="@+id/button"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="@{vm.buttonText}"
            tools:text="Ready" />
    </LinearLayout>
```

### LiveDataの更新メソッドを作成

次に、LiveDataの値を更新するメソッドを作成します。

```kotlin:FootballViewModel.kt
    fun updateButton(isBlank: Boolean) {
        _isEnabled.value = !isBlank

        if (!isBlank) {
            _buttonText.value = "Set!!!"
        } else {
            _buttonText.value = "Ready"
        }
    } 
```
このメソッドでは、buttonの状態を以下の2項目に関して更新しています。

- `buttonText`: ボタンのテキスト
- `isEnabled`: ボタンを押下できるかどうか(`Button.isEnabled`)

`buttonText`に関して。
`_buttonText`の値(間接的には`buttonText`の値でもある)を
EditTextにテキストが入力されているかどうか(メソッドの引数:`isBlank`)によって変更しています。

`isEnabled`に関して。
記載しておりませんでしたが
`_isEnabled`, `isEnabled`をViewModel内で定義しています。
これはButtonがenableかどうかと言う情報を持つ
MutableLive、およびDataLiveDataです。

（
LiveDataのsetterには
setValue(Kotlinでは、.value)とpostValueが用意されています。
setValueはメインスレッド(UIスレッド)のみでしかセットされず、
もし、別スレッドでLiveDataの値がセットされたとしても
検知できないと言うことらしいです。
参照：[LiveData](https://developer.android.com/reference/android/arch/lifecycle/LiveData#postvalue) : Google公式リファレンス
）

### FragmentクラスにViewModelを導入

さて、3Qも終わりいよいよ4Qです。
時間運びがより一層大事になってきますね。

`FootballFragment`に`FootballViewModel`を導入します。

下記コードは、`FootballFragment`のコードです。

```kotlin:FootballFragment.kt
class FootballFragment : Fragment() {

    private lateinit var binding: FragmentFootballBinding

    private val viewModel = FootballViewModel()

    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        binding = FragmentFootballBinding.inflate(inflater, container, false)
        binding.vm = viewModel
        binding.lifecycleOwner = this
        return binding.root
    }

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

        viewModel.isEnabled.observe(viewLifecycleOwner, Observer { isEnabled ->
            binding.button.isEnabled = isEnabled
        })

        binding.editText.addTextChangedListener { text ->
            viewModel.updateButton(text.isNullOrBlank())
        }
    }
```

まず、プロパティに`viewModel`を定義します
今回作成したViewModelは`ViewModel()`を継承していないため
`FootballViewModel()`でインスタンス化できます。
（ViewModel()を継承する場合の実装はこちらを参照：
[Implement a ViewModel](https://developer.android.com/topic/libraries/architecture/viewmodel#implement): Google公式ガイド）

```kotlin:FootballFragment.kt
private val viewModel = FootballViewModel()
```

次に、`onCreateView()`にて`binding`の設定を追加します。
追加したのは下記の部分です。

```kotlin:FootballFragment.kt
        binding.vm = viewModel
        binding.lifecycleOwner = this
```

まず1行目について。
`binding`: FragmentFootballBinding の`vm`、
つまりレイアウトファイルにてdataタグ内に設定した`vm`に
インスタンス化したViewModelを代入してあげます。

次に2行目について。
これを追加して`lifecycleOwner`を設定しておかないと
LiveDataが値の更新を検知することはできません。
コメントアウトして実行してみると挙動が分かると思います。

-- 後半4Q, 2 minutes warning

最後に、`onViewCreated`にて、
`Observer`とEditTextのリスナーを設定します。

まず、`Observer`について。
以下に添付のコードのように、`viewModel`内のLivedataを指定することで
LiveDataの値が更新された際に検知することができます。
これは、同じ値がセットされたとしても検知されます。

今回の場合、`viewModel`で定義した
`isEnabled`というLiveDataの値が更新された時に呼び出され、
`Button.isEnabled`の値に代入されます。

つまり、**データの更新とViewの更新が同期されます**

また、この`Observer`の処理はDataBindingでできますが
実装方法を記載するために実装しています。

```kotlin:FootballFragment.kt
        viewModel.isEnabled.observe(viewLifecycleOwner, Observer { isEnabled ->
            binding.button.isEnabled = isEnabled
        })
```

次に、EditTextのリスナーを設定します。
以下の添付のリスナーは、`editText`のテキストが変更されたとき
つまりテキストを入力・削除したときに呼ばれます。
このときの`editText`にテキストが入力されているかどうかを取得し
`viewModel`のメソッドに引数として渡します。

前述のこのメソッド内でボタンに関するデータの更新を行います。

```kotlin:FootballFragment.kt
        binding.editText.addTextChangedListener { text ->
            viewModel.updateButton(text.isNullOrBlank())
        }
```

#### これで試合終了です。

最後に、全体のコードを添付して終わりにしたいと思います。
記事内では記載していなかった部分もあります。

```xml:fragment_football.xml
<layout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools">

    <data>

        <variable
            name="vm"
            type="io.github.itakahiro.databindingfootball.FootballViewModel" />
    </data>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:gravity="center"
        android:orientation="vertical"
        android:padding="32dp">

        <TextView
            android:id="@+id/textView"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="@{vm.submittedText}"
            tools:text="ここに出力されます" />

        <EditText
            android:id="@+id/editText"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginTop="32dp"
            android:layout_marginBottom="32dp"
            android:hint="アメフトのルールや魅力は?" />

        <Button
            android:id="@+id/button"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:enabled="@{vm.isEnabled}"
            android:text="@{vm.buttonText}"
            tools:text="Ready" />
    </LinearLayout>
</layout>
```

```kotlin:FootballFragment.kt
class FootballFragment : Fragment() {

    private lateinit var binding: FragmentFootballBinding

    private val viewModel = FootballViewModel()

    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        binding = FragmentFootballBinding.inflate(inflater, container, false)
        // このようにしても良い
//        binding = DataBindingUtil.inflate(
//            inflater, R.layout.fragment_football, container, false
//        )
        binding.vm = viewModel
        binding.lifecycleOwner = this
        return binding.root
    }

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

        binding.editText.addTextChangedListener { text ->
            viewModel.updateButton(text.isNullOrBlank())
        }
        binding.button.setOnClickListener {
            val text = binding.editText.text.toString()
            viewModel.submitText(text)
        }
        
        // この部分はDataBindingで実装. 
        // 代わりに、レイアウトファイルのandroid:enabled="@{vm.isEnabled}"の行で実装できる！
//        viewModel.isEnabled.observe(viewLifecycleOwner, Observer { isEnabled ->
//            binding.button.isEnabled = isEnabled
//        })
    }
}
```

```kotlin:FootballViewModel.kt
class FootballViewModel {
    private val _submittedText = MutableLiveData<String>().also { mutableLiveData ->
        mutableLiveData.value = "ここに、出力されます"
    }
    val submittedText: LiveData<String>
        get() = _submittedText

    private val _isEnabled: MutableLiveData<Boolean> =
        MutableLiveData<Boolean>().also { mutableLiveData ->
            mutableLiveData.value = false
        }
    val isEnabled: LiveData<Boolean>
        get() = _isEnabled

    private val _buttonText: MutableLiveData<String> =
        MutableLiveData<String>().also { mutableLiveData ->
            mutableLiveData.value = "Ready"
        }
    val buttonText: LiveData<String>
        get() = _buttonText


    fun updateButton(isBlank: Boolean) {
        _isEnabled.value = !isBlank

        if (!isBlank) {
            _buttonText.value = "Set!!!"
        } else {
            _buttonText.value = "Ready"
        }
    }

    fun submitText(text: String) {
        _submittedText.value = text
    }
}
```

# まとめ

1ヶ月ほど前からDataBindingに触れる機会があったので
今回記事にしてまとめてみました。

コードを記事にまとめることは不慣れで、
予想以上に時間を要してしまいました。
今後もアウトプットを続けて、自分のものにしていきたいです。

また、ご指摘あればコメントいただけると幸いです。

### 参考にした資料
- [Android Data Binding codelab](https://codelabs.developers.google.com/codelabs/android-databinding/index.html?index=..%2F..index#0)
- [LiveData](https://developer.android.com/reference/android/arch/lifecycle/LiveData#postvalue) : Google公式リファレンス
- [Generated binding classes](https://developer.android.com/topic/libraries/data-binding/generated-binding.html) : Google公式ガイド
- [AndroidX の概要](https://developer.android.com/jetpack/androidx?hl=ja) : Google公式