MVVM 完全に理解した - 3
今回は Data Binding について。
といってもなかなか一筋縄ではいかないので、本記事ではデータをバインドするところまで。
ちょっと長いので目次付けてみる。
- Data Binding Library の概要
- ライブラリの導入
- レイアウトファイルへの記述
- データをバインドする
- ダメ押しで Fragment, ListView, RecyclerView adapter の場合
- とりあえずまとめ
Data Binding Library の概要
https://developer.android.com/topic/libraries/data-binding/?hl=endeveloper.android.com
The Data Binding Library is a support library that allows you to bind UI components in your layouts to data sources in your app using a declarative format rather than programmatically.
うーん、一文が長い←
実例で見てみます。
findViewById<TextView>(R.id.sample_text).apply { text = viewModel.userName }
よくある UI ( TextView ) への値のセットですね。Kotlin だからスコープ関数( apply
)使ってますが。
これが Data Binding を使うと───
<TextView android:text="@{viewmodel.userName}" />
こう書けるよと。むむ。
@{ }
構文で ViewModel オブジェクトを参照できる、みたいな感じ。
Binding components in the layout file lets you remove many UI framework calls in your activities, making them simpler and easier to maintain.
レイアウトファイルにコンポーネントをバインドさせることで、Activity から UI に関係するメソッドコールを除外することができ、簡潔かつメンテもしやすくなるよと。すごい。
ライブラリの導入
app モジュールの build.gradle
を開き、次の項目を追記します。
android { ... dataBinding { enabled = true } }
たったこれだけ。
レイアウトファイルへの記述
ここからはこっちのページ。
https://developer.android.com/topic/libraries/data-binding/expressionsdeveloper.android.com
バインドする場合、レイアウトファイルの書き方が通常のそれとは異なってきます。
<?xml version="1.0" encoding="utf-8"?> <layout xmlns:android="http://schemas.android.com/apk/res/android"> <data> <variable name="user" type="com.example.User"/> </data> <LinearLayout ... <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@{user.firstName}"/> ... </LinearLayout> </layout>
Data binding layout files are slightly different and start with a root tag of layout followed by a data element and a view root element. This view element is what your root would be in a non-binding layout file.
ポイントは次のとおり。
- ルートタグは
layout
layout
の直下にdata
要素を記述。name
が xml 内で使う名称、type
がバインドするクラスdata
要素の次に通常のLayout
を記述@{ }
構文を用いて、プロパティ参照みたいな書き方で値を取得
上記の例では User という Data Class をバインドしているようです。
"Data binding layout file" と "non-binding layout file" とで、そもそもレイアウトファイルが区別されてるっぽい。
生成後は通常不変なクラスである Data Class をバインドしていることに違和感を禁じえませんが、とりあえずここは次へ行きます。
データをバインドする
では Activity
側の記述を見てみます。
override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) val binding: ActivityMainBinding = DataBindingUtil.setContentView(this, R.layout.activity_main) //または次の書き方も可 val binding: ActivityMainBinding = DataBindingUtil.inflate(getLayoutInflater()) binding.user = User("Test", "User") }
まず急に出てきた ActivityMainBinding
クラスは、"Data binding layout file" を作ると自動生成されます。layout
と data
要素もった xml ね。
場所はココ↓
もし作られてなかったらリビルドしてみてください。
Data Binding file を扱う場合、この DataBindingUtil.setContentView
または inflate
を使って View を生成します。
そしてこの返り値である xxxBindig
は、name
で定義したプロパティ*1をもっており、上記では user
というプロパティが参照できます!天才かこれ!
これで xml ファイルで定義したデータと実際の処理の記述が紐付けられました。
生成方法からして、もし data
要素を修正した場合はリビルド必須ですね。バインディングでバグったらとりあえずやってみましょう。
ダメ押しで Fragment, ListView, RecyclerView adapter の場合
Fragment, ListView, RecyclerView のアイテムにデータバインディングを使う場合は、次のように記述します。
val listItemBinding = ListItemBinding.inflate(layoutInflater, viewGroup, false) // or val listItemBinding = DataBindingUtil.inflate(layoutInflater, R.layout.list_item, viewGroup, false)
バインディングクラスの inflate
か、DataBindingUtil.inflate
か。お好みでどうぞ。
とりあえずまとめ
不変なデータクラスの Binding がメインでしたが、表面だけ Data Binding 理解した!
次は双方向データバインディングと、そろそろアプリ考え始める。
*1:正確には getUser/setUser メソッドです。Kotlinだとプロパティっぽく呼べる