2010年8月24日火曜日

Android 「The world of ListView」 - Virtualization and adapters -

Google I/O の 「The world of ListView」というセッションを見たので
そのまとめ。

長いので、項目ごとに分けました。
今回は 「Virtualization and adapters」

--------------------------------------

Google I/O の「The world of ListView」のページは こちら

セッションのスライドはこちら

 agenda

  • Virtualization and adapters

  • Item properties

  • Headers and footers

  • List selectors

  • Other features

  • Gotchas and don'ts

--------------------------------------

■ Virtualization and adapters

 ・ Virtualization
  * 問題点 : 巨大なデータセット
   ・メモリ
   ・パフォーマンス
  
  10,000 item くらいの(ってセッションでは言ってた)データを
  比較的速く扱うには?
  普通は、10,000 個のview を view の階層に添付したくはないよね。
  そのために、、、

  * 解決方法
   ・必要に応じでデータを格納
   ・view をリサイクルして、オブジェクトのチャーン(object churn)を減らす
  

 ・ Adapters
  * 用語
   – index: 子要素
   – position: adapter 内のデータ
   – id: データの識別子

  * Stable IDs
   – hasStableIds() == true で調べる
   – 常に同じ値を参照するための ID
   – ListView に役立つ!!

  * getView(int position, View convertView, ViewGroup parent)
   – 全データの表示を制御
   – 最適化
   – はまりやすい!「Shoot yourself in the foot (and the face)」

  ローカルのデータや、データベースのデータや、ネットワークから
  とったデータ、から割り当てたデータソースから、データを取り出す。
  view は単純な TextView だったり、複雑なレイアウトだったりする。
  
 
  * getView の 最適化ポイント
   • ListView is smart
   • convertView
    – ListView で提供される
    – 要素(item)のタイプと一致
    – 再利用すべし!!

   extra view パラメータの呼び出しを convert view に
   渡してしまえばOK。ListView がスクリーン外の view を
   再利用する方法と同じ最適化方法。
   
   ListView はスクリーン外へ移動した全部の extra view を
   keep track して、既存のデータを入れてから返す。
   これが、convert view parameter。
   つまり、自動的に item のタイプを match up している。
   もし、adapter 内に異なるデータによる複数のタイプ
   (例えば、画像と文字)がある場合、ListViewに adapter
   のあるポジションがどのタイプか聞いたとき convert view は
   いつも正しいタイプになっている(必要がある)。
   でもこれはあんまり賢いやりかたじゃない。
   
   だから、
    もし convertView が null じゃないなら、再利用する!
   

   ● getView のダメな使い方 (The Slow Way)


public View getView(int position, View convertView, ViewGroup parent) {
View item = mInflater.inflate(R.layout.list_item_icon_text, null);
((TextView) item.findViewById(R.id.text)).setText(DATA[position]);
((ImageView) item.findViewById(R.id.icon)).setImageBitmap(
(position & 1) == 1 ? mIcon1 : mIcon2);
return item;
}

    getView 内で毎回 view を inflate してはダメ!
    xml を毎回 parse することは、メモリもCPUも使うので
    とっても無駄が多い。


   ● getView の普通の使い方 (The Right Way)


public View getView(int position, View convertView, ViewGroup parent) {
if (convertView == null) {
convertView = mInflater.inflate(R.layout.item, parent, false);
}
((TextView) convertView.findViewById(R.id.text)).setText(DATA[position]);
((ImageView) convertView.findViewById(R.id.icon)).setImageBitmap(
(position & 1) == 1 ? mIcon1 : mIcon2);
return convertView;
}

    最初だけ view を inflate して、それを再利用する


   ● getView の賢い使い方 (The Fast Way)

   ViewHolder を使うべし


static class ViewHolder {
TextView text;
ImageView icon;
}



public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder holder;

if (convertView == null) {
convertView = mInflater.inflate(R.layout.list_item_icon_text, parent, false);
holder = new ViewHolder();
holder.text = (TextView) convertView.findViewById(R.id.text);
holder.icon = (ImageView) convertView.findViewById(R.id.icon);

convertView.setTag(holder);
}
else {
holder = (ViewHolder) convertView.getTag();
}

holder.text.setText(DATA[position]);
holder.icon.setImageBitmap((position & 1) == 1 ? mIcon1 : mIcon2);

return convertView;
}

    最初だけ view を inflate して、holder を介して再利用する


    このくらい違う




   * How to shoot yourself in the foot (どのようにはまりやすいか)
     • ロカールビューのキャッシュ
     • adapter からビューにアクセスする
     • convertView の構造を変える
     • getView の呼び出しについての仮定

   * データの変更を制御する
    • notifyDataSetChanged()
     – データの新規作成 or 更新
    • notifyDataSetInvalidated()
     – アクセスできるデータがないとき

   * 異なるビュータイプを制御する
    • 要素のタイプ (item types) を Built-in にする
    • getItemViewType
     – 与えられたポジションのビューのタイプを取得
     – 正しい convertView を提供するのに使う
    • getViewTypeCount
     – 予測されるタイプの数を取得

   * slow data sources を制御する
    • UIスレッドで adapter の変更 (modification)
    • Fetching data can happen anywhere
    • 別のスレッド上でデータをリクエストする
    • UIスレッドで、adapter の変更をコミットする
    • notifyDataSetChanged() を呼び出す

 書きかけだけど、一旦出します。
 もうちょっと追記するかも。

1 件のコメント: