Android DataBinding導入の第一歩: ButterKnife+ViewHolderパターンを置き換える

仕事で関わっているアプリのmasterブランチに Android Data Binding が導入されたのを見届けたので、自分でもちょっと使ってみました*1

DataBidingのメリットや導入にあたってのハマりどころは以下のsys1yagiさんのエントリから:

さっそく個人アプリでも導入してみたところ、ドキュメントそのままだとGoogle Daggerとの相性が悪くてコンパイルが通りませんでした。これはstackoverflowで同じ問題が報告されていました。それによればDataBinding compilerを自分でdependenciesに書かなければならないとのこと。これでコンパイルは無事に通ります。

DataBinding自体は非常に多彩な機能があるのですが、ひとまずButterKnife+ViewHolderパターンの代替として使うと差分が非常に少なくてすみます

差分はこちら: Introduce DataBinding by gfx · Pull Request #13 · gfx/Android-Helium · GitHub

このPRは以下のことをやっただけです。

  • layout XML<layout> タグで囲んで xmlns:*<layout> に移動させる
  • ViewHolderクラスを消して *Binding に置き換える

*Binding はlayout XMLから生成されるクラスで、普通のViewHolderとほぼ等しい機能を持ちます。たとえば ListViewの Adapter#getView() の ButterKnife+ViewHolder な実装を DataBinding にする差分は以下のようになります。

         @Override
         public View getView(int position, @Nullable View convertView, @Nullable ViewGroup parent) {
             if (convertView == null) {
-                convertView = LayoutInflater.from(getActivity())
-                        .inflate(R.layout.card_hatebu_entry, parent, false);
-                convertView.setTag(new ViewHolder());
+                LayoutInflater inflater = LayoutInflater.from(getActivity());
+                CardHatebuEntryBinding binding = DataBindingUtil.inflate(inflater, R.layout.card_hatebu_entry, parent, false);
+                convertView = binding.getRoot();
             }
 
-            ViewHolder viewHolder = (ViewHolder) convertView.getTag();
-            ButterKnife.inject(viewHolder, convertView);
+            CardHatebuEntryBinding binding = DataBindingUtil.getBinding(convertView);```

DataBindingUtil.inflate()LayoutInflater#inflate() をしてViewと *Binding を結びつける(bindする)メソッドで、 View#getTag() で ViewHolder インスタンスを取得するかわりに DataBinding.getBinding()*Binding インスタンスを取得します。 DataBinding は内部で View#setTag() をつかってbindingインスタンスを結びつけているので、実装的にもほとんどかわりありません。

一度ButterKnife+ViewHolderパターンとの対応がわかるとほとんど機械的に作業できるので、作業量的にも学習コスト的にも、DataBindingの導入コストは非常に低いといえます。

*1:ちなみにDataBindingはAndroid Mの新機能ではなく、コード生成を行うライブラリにすぎないため、既存のプロジェクトへすぐ導入できます