今更だけど初DataBinding！

前からMVVMを意識した開発をしないとなあと思いつつ、、今まで来てしまったので勉強をかねて備忘録。

## やりたいこと
- ViewModelを使ってデータの操作がしたい！

- レイアウトからもDataBindingしたい！ 

- Fragmentからも操作したい！

**完成イメージ**
![イメージ.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/678917/85eeb853-8a2a-0562-6e10-39a08a5a65e5.gif)

二つのタブを用意して、それぞれの画面でメッセージや背景色を変更させてます。
右下のFloatingActionButtonを押すとカウント処理が実行され、カウントがボタンに反映されるようにしました。（Snackbarでもカウント数を表示してますが、、邪魔でしたね:sweat:笑）
ViewModelを使ってるので、画面を回転しても数字は初期化されません！なんて便利なんでしょう。

## さっそく
**1. Androidプロジェクトを新規作成**
ここではDataBindingを中心にやりたかったので、Tabbed Activityテンプレートを使用しました！
![スクリーンショット 2021-01-06 18.12.41.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/678917/b9351070-e710-d04d-a07f-ec72c0a391b6.png)

**2. ViewModelに必要な部品を用意する**
テンプレートで必要なViewModelは用意されてるので、ちょいとViewModelの中をいじっていきます。
メッセージ用の変数と背景色用の変数とカウント用の変数を用意する。あってるかわかんないけど、こんな感じ。。

```Kotlin:PageViewModel.kt
class PageViewModel : ViewModel() {

    private var count = 0
    private val _index = MutableLiveData<Int>().also {
        mutableLiveData -> mutableLiveData.value = 0
    }
    val index: LiveData<Int>
        get() = _index

    private val _colorIndex = MutableLiveData<String>()
    val colorIndex: LiveData<String>
        get() = _colorIndex

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

    fun setIndex(index: Int) {
        if(index == 1) {
            _messageText.value = "おはようううう"
            _colorIndex.value = "#e6e6fa"
        } else {
            _messageText.value = "こんにちわああ"
            _colorIndex.value = "#fff0f5"
        }
    }

    fun count() {
        _index.value = count++
    }
}
```
`setIndex`はFragmentを構成する時に呼ばれる。タブ1の時は`index`が`1`
なので`おはようううう`と背景色は`#e6e6fa`がセットされるように設定しています。
※いや正確には`0`だけど`SectionsPagerAdapter`で`position + 1`してるから`1`なんだなあ〜:rolling_eyes:

```kotlin:SectionsPagerAdapter.kt
override fun getItem(position: Int): Fragment {
        // getItem is called to instantiate the fragment for the given page.
        // Return a PlaceholderFragment (defined as a static inner class below).
        return PlaceholderFragment.newInstance(position + 1)
    }
```

**3. Fragmentをいじるよ**
上で追加した`messegeText`と`colorIndex`を監視してタブが切り替わるたびに値がセットされるように修正する。

```kotlin:PlaceholderFragment.kt
override fun onCreateView(
            inflater: LayoutInflater, container: ViewGroup?,
            savedInstanceState: Bundle?
    ): View? {
        val root = inflater.inflate(R.layout.fragment_main, container, false)
        val textView: TextView = root.findViewById(R.id.section_label)
        val layout: ConstraintLayout = root.findViewById(R.id.constraintLayout)
        pageViewModel.messageText.observe(this, Observer<String> {
            textView.text = it
        })
        pageViewModel.colorIndex.observe(this, Observer<String> {
            layout.setBackgroundColor(Color.parseColor(it))
        })
        return root
    }
```
ここまでで、タブの切り替えで文字と背景色が変わるように実装が完了！
カウントはまだだよ。

**4. Activityをいじるよ**
まずレイアウトから値がすぐ反映できるようにDataBindingを有効にする。
以下を追記したら、`Sync Now`！

```kotlin:build.gradle(app)
plugins {
    ・・・略・・・
    id 'kotlin-kapt'
}
    ・・・略・・・

android {
    ・・・略・・・
    dataBinding {
        enabled true
    }
}
```
続いて、レイアウトに適用させるよ！
ここでは、`MainActivity`のレイアウトにバインドさせたいから`activity_main`を開いて、レイアウトにカーソルを合わせたとこで、`option + command`を押すよ。(はい、macです)
そうすると、以下みたいな`Convert to data binding layout`っていうのがでてくるのでそれを選択すると簡単にDataBinding用に変換してくれるんですね。
![スクリーンショット 2021-01-07 16.16.54.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/678917/33ee89eb-829d-24cb-4057-bde953231d13.png)

dataタグ内にDataBindingしたい変数を定義して、こんな感じにカウントボタンを用意しました！

```XML: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="vm"
            type="jp.co.test.tabapp.ui.main.PageViewModel" />
    </data>

    <androidx.coordinatorlayout.widget.CoordinatorLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context=".MainActivity">

        <com.google.android.material.appbar.AppBarLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:theme="@style/Theme.TabApp.AppBarOverlay">

            <TextView
                android:id="@+id/title"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:gravity="center"
                android:minHeight="?actionBarSize"
                android:padding="@dimen/appbar_padding"
                android:text="@string/app_name"
                android:textAppearance="@style/TextAppearance.Widget.AppCompat.Toolbar.Title" />

            <com.google.android.material.tabs.TabLayout
                android:id="@+id/tabs"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:background="?attr/colorPrimary"
                app:tabSelectedTextColor="@color/teal_700"
                app:tabTextColor="@color/white" />
        </com.google.android.material.appbar.AppBarLayout>

        <androidx.viewpager.widget.ViewPager
            android:id="@+id/view_pager"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            app:layout_behavior="@string/appbar_scrolling_view_behavior" />

        <FrameLayout
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="bottom|end">


            <com.google.android.material.floatingactionbutton.FloatingActionButton
                android:id="@+id/fab"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_margin="@dimen/fab_margin" />

            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_gravity="center"
                android:text="@{String.valueOf(vm.index)}"
                android:elevation="16dp"
                android:textColor="@color/white"
                android:textAppearance="?android:attr/textAppearanceMedium" />
        </FrameLayout>
    </androidx.coordinatorlayout.widget.CoordinatorLayout>
</layout>
```
この一番下にある`TextView`のとこがカウント数を表示する部分です。
`android:text="@{String.valueOf(vm.index)}"`
カウントが増えていくたびに自動的に数字が変わるように`ViewModel`の`index`を読み込みます。

続いてMainActivityの修正！
DataBindingするときは以下のように設定するみたい。
（なんで`ActivityMainBinding`かというと、レイアウトファイル名をキャメル記法にして末尾に`Binding`をつけた名前だから。（※レイアウト名がactivity_main.xml））

```kotlin
val binding : ActivityMainBinding = DataBindingUtil.setContentView(this, R.layout.activity_main)
```

通常はこれですよね。

```kotlin
setContentView(R.layout.activity_main)
```

全体ではこんな感じ。

```kotlin:MainActivity.kt
class MainActivity : AppCompatActivity() {

    private lateinit var pageViewModel: PageViewModel

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        pageViewModel = ViewModelProvider(this).get(PageViewModel::class.java)
        val binding : ActivityMainBinding = DataBindingUtil.setContentView(this, R.layout.activity_main)
        binding.vm = pageViewModel
        binding.lifecycleOwner = this

        val sectionsPagerAdapter = SectionsPagerAdapter(this, supportFragmentManager)
        binding.viewPager.adapter = sectionsPagerAdapter
        binding.tabs.setupWithViewPager(binding.viewPager)

        binding.fab.setOnClickListener { view ->
            pageViewModel.count()
            Snackbar.make(view, "count = " + pageViewModel.index.value, Snackbar.LENGTH_LONG)
                .setAction("Action", null).show()
        }
    }
}
```
これ重要です。
`binding.lifecycleOwner = this`
これがなかったせいで、カウントボタン押してるのに数字がUIに反映されなくて詰まってました〜。笑

## おわり
まだまだ流れが理解できず混乱したりするし、
本当にこのやり方でいいのかわかりませんが、とりあえずDataBindingできました:relaxed: