ButterKnife を捨てて Data Binding を使えるのか?
概要
先日、会社の Android アプリの師匠に「ButterKnife と Data Binding はどちらが良いですか?」と伺ったところ、「Data Binding です」との即答を頂いたので、試しに採用してみる。
それって何するものなの?
まず、Android ではレイアウトをXMLで記述し、Activity という Java のクラスでそれらに定義した View を find して利用する。 この find の記述が面倒くさいので、自動で関連付けてくれないかという要望に応えてくれるのが ButterKnife と Data Binding である。 View 専用の Dependency Injection だという話をどこかで見たような気がするが詳しくは知らない。
ButterKnife が先発で、 Data Binding が後から Google によって提供されるようになった。 なので ButterKnife を Data Binding に置き換える、という話が多い。
導入
app/build.gradle に3行追記するだけで有効になる。
app/build.gradle android { //... dataBinding { enabled = true }
ButterKnife からの置き換え
ButterKnife を利用しているコードを置き換えていく。
layout.xml の修正
次に、対象の layout.xml に対し、全体を <layout> というタグで囲う。ここでもうこれまでの Layout ファイルと互換性がなくなるので、 気持ち悪さを禁じえなかった。もうちょっとましにできなかったのかなと思う。
layoutタグで囲う <?xml version="1.0" encoding="utf-8"?> <layout xmlns:android="http://schemas.android.com/apk/res/android"> <LinearLayout ... </layout>
コードの修正
すると、Binding クラスが自動生成される。クラス名は layout.xml の名前に応じて変わり、例えば acitivy_main.xml という名前だった場合は、 ActivityMainBinding という名前になる。Android のレイアウトファイル名は activity_具象名.xml で付けることが多いので、 それに合わせてほしかった気持ちが強い。
Binding オブジェクト は DataBindingUtil#setContentView で取得する。
Bindingオブジェクトの取得public class SettingsActivity extends AppCompatActicity { /** Binding instance. */ private ActivitySettingsBinding binding; @Override public void onCreate(Bundle b) { super.onCreate(b); setContentView(R.layout.activity_settings); binding = DataBindingUtil.setContentView(this, R.layout.activity_settings);
id を振った View のオブジェクトは Binding オブジェクトのフィールドとしてすべて保持されている。 id の snake_case を camelCase にした名前が自動で付けられる。 これによりインスタンスのインジェクションコードが不要になるので、コードは ButterKnife 使用時よりもすっきりする(ように思える)。
View Action の実装
onClick 等の挙動を実装するのは ButterKnife よりも手間がかかる感じで、Layout ファイルに Activity の依存を書かなくてはいけない。 デザインを記述する Layout ファイルにロジック関連の記述を入れ込むことに違和感や嫌悪感を感じるので、ここを我慢するか、 あるいは使わないで純粋に View のインジェクションにのみ用いるか、要はやりようである。 Activity のコードが簡潔になるだけでも利点は十分と言える。
クリックアクションを指定するためだけに Activity の依存を追記 <?xml version="1.0" encoding="utf-8"?> <layout> <data> <variable name="activity" type="jp.toastkid.calendar.settings.SettingsActivity" /> </data> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/settings_color" android:layout_width="match_parent" android:layout_height="@dimen/settings_item_height" android:onClick="@{activity.color}" >
そして Activity のコードからインスタンスを渡してやる。
Activity インスタンスを渡すsetContentView(R.layout.activity_settings); binding = Data BindingUtil.setContentView(this, R.layout.activity_settings); binding.setActivity(this);
ついでに、 ButterKnife と違って、 android:onClick で指定するメソッドは OnClickListener.onClick とシグネチャを合わせなければならない。
ButterKnifeの頃@OnClick(R.id.settings_color) public void color() { //... }
と書けていた箇所は、 Data Binding では必ず View を引数に取るようにしなければならない。
Data Bindingでの変更public void color(final View view) { //... }
うーん、Retrolambda 入れているなら Lambda 式で書いてしまった方がコードとしてはわかりやすくなるのではないか?
include での問題
include する Layout ファイルでも同じように <layout> タグで囲めば Binding オブジェクトが生成されていく。 あまり深い構造にし過ぎると、ひたすら . で連なって見づらいコードになるので考え物ではある。
感想
今日軽く使った感じでは、ButterKnife で満足できているなら、わざわざ乗り換えるほどのものでもないのではという見解である。 Binding オブジェクトにすべての View がぶら下がる形になるので.が2つ続くコードを書くことになるし、 自動で付けられる名前を強制させられるので採用している命名規則によっては長ったらしい記述を強いられることになる。 Activity と Layout が密結合する欠陥も見逃し難い。
ButterKnife は Jake Wharton 氏が書いたライブラリだし、現在もメンテナンスされているので、ButterKnife で満足できているなら別に急いで乗り換える必要はまったくない。 Data Binding でしかできないことというのも、そんなにはないようだ。なお、置き換えによってリリースビルドのAPKサイズは2KBだけ小さくなったが、 影響があったのか全然わからない。
まあ、全然使い方を知らないよりはましなので、この取り組みは無駄ではなかった。もうちょっと使ってみる。
どうでもいいこと
私が ButterKnife に執着するのは、下記の理由からだ。
楽しかった開発プロジェクトの思い出と共にあるライブラリだから
layout と Activity の距離を従来通り保ちつつ書き方だけを便利にできるから
Jake Wharton 氏のライブラリだから
トーストに Butter Knife は欠かせない道具(バターを塗るための切れないナイフ)だから
はい、御察しの通り3点目を書きたかっただけである。
References
Data Binding through Plaid……ベトナムで聞いてきたセッションの資料
Butter Knife、今までありがとう。 Data Binding、これからよろしく。……こちらの記事でも ButterKnife を使ったコードを Data Binding に置き換えていた。














