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() を呼び出す
書きかけだけど、一旦出します。
もうちょっと追記するかも。