Android Binding
前回に引き続き、ListViewをAndroid Bindingで使ってみます。元ネタはこちら。
Displaying multiple lists in one single ListView (with Android Binding)
一通り読んでもいまいちピンと来ないので、コードを自分起こしながら試しました。なのでオリジナルのコードと違うので注意して下さい。
まず、Applicationクラスに関しては、これまでとまったく同じでAndroid Bindingフレームワークを初期化するだけです。
public class ListViewTutorialApplication extends Application { @Override public void onCreate() { super.onCreate(); Binder.init(this); } }
ここまでは今まで通りです。それでは次にListViewとView Modelをバインドします。まずはリストに表示するコンテンツを準備します。今回はチュートリアルなので静的な情報を使います。
public class ListViewTutorial extends Activity { private static final String[] Asia = new String[] { "China", "Thailand", "Japan", "Korea", }; private static final String[] NAmerica = new String[] { "U.S.A.", "Canada", }; private static final String[] Europe = new String[] { "U.K.", "Italy", "France", "Spain", "Netherlands", }; // ...
次にこれらのデータ (Model) に対応するView Modelを定義します。
public class ListViewTutorialViewModel { public ArrayListObservable<String> AsiaList = new ArrayListObservable<String>(String.class); public ArrayListObservable<String> NAmericaList = new ArrayListObservable<String>(String.class); public ArrayListObservable<String> EuropeList = new ArrayListObservable<String>(String.class); }
ArrayListObservableという配列やリストのオブザーバブルオブジェクトを定義します。でもこれだけではModelとView Modelが関連付いていません。この関連付けはやっぱりActivityでやるべきでしょう。
public class ListViewTutorial extends Activity { // ... @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); ListViewTutorialViewModel model = new ListViewTutorialViewModel(); model.AsiaList.setArray(Asia); // ← ここと model.NAmericaList.setArray(NAmerica); // ← ここと model.EuropeList.setArray(Europe); // ← ここ! Binder.setAndBindContentView(this, R.layout.main, model); } // ...
先ほどのArrayListObservableオブジェクトのsetArrayメソッドで関連付けを行っています。最後にレイアウト定義 (View) とView Modelを関連付けておしまい。
最後にレイアウト定義を見てみます。
... <ListView ... binding:itemSource="AsiaList" binding:itemTemplate="@layout/list_item" /> ...
binding:itemSource属性とbinding:itemTemplate属性で文字通りバインドしているわけですが、問題はこの先。res/layout/list_item.xmlです。
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:binding="http://www.gueei.com/android-binding/" android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent"> <TextView android:textSize="16sp" android:textColor="#FEFEFE" android:layout_margin="5dp" android:layout_width="fill_parent" android:layout_height="wrap_content" binding:text="." /> </LinearLayout>
ここで重要なのが次の箇所。
binding:text="."
という属性指定。これがないとリストが表示されませんでした。・・・ていうかこのことに関して何にも書いてないんですよね、チュートリアルに。ここが一番重要だと思うんですけど。
一番気になる箇所を棚上げにして、Convertersという新しい機能を使っていきます。
<ListView android:layout_width="fill_parent" android:layout_height="wrap_content" binding:itemSource="STITCH( SECTION('Asia Countries', @layout/section_name), ADAPTER({source=AsiaList, template=@layout/list_item}), SECTION('N.America Countries', @layout/section_name), ADAPTER({source=NAmericaList, template=@layout/list_item}), SECTION('Europe Countries', @layout/section_name), ADAPTER({source=EuropeList, template=@layout/list_item}))" />
この中でConvertersは以下の3つです。
- STITCH
- SECTION
- ADAPTER
Stitchとは「縫う、縫い閉じる」という意味です。一つにまとめる、的なニュアンスでしょうかね。SECTIONはその名の通りセクション。「章」とか「節」の意味。今回はリストのコンテンツを分類するために使っています。最後のADAPTER。これが一番大事なところです。でも内容を見ると何となく役割は分かりますよね。
ADAPTER({source=AsiaList, template=@layout/list_item}) ADAPTER({source=NAmericaList, template=@layout/list_item}) ADAPTER({source=EuropeList, template=@layout/list_item})
sourceはリストの行とバインドするモデル、templateはバインドしたモデルの見栄えを定義するレイアウト定義。この二つが
binding:text="."
という指定だけで関連づいているのです (この指定の意味は今のところ棚上げ) 。
実行結果はこんな感じ。
まぁ、意図通りの結果といえばそうですが、疑問点などが残ります。
- リストの項目がもっと複雑な場合、どのようにバインドするのか?
- リスト表示までにえらい時間がかかる
そして、今のところ致命的だなぁ、と感じるのが以下の点。
- デバッグしにくい
たとえばバインド先のView Modelの指定が間違っていても、それは実行するまで分かりません。ビルドでエラーが出ないのです。慣れの問題でしょうかね。
いつものように今回使用したプロジェクトはこちらに上げておきます。ご参考にどうぞ。
そもそもリストコンテンツとView Modelとの関連付けが分かっていないのと、最初の疑問点が気になるので、もう少し掘り下げようと思います。
ここで一つ目標を設けます。
今私は恥ずかしながら一つAndroidアプリを公開しています。それはこちら。
こいつをAndroid Bindingを使って作り直そうと思います。手始めにAndroid BindingのダウンロードサイトにあるAndroidBindingMarkupDemoを調べていきます。