概要
一般的なListViewの高速化手法としてViewHolder
というものがあります。
これはAdapter#getView()でアイテムのfindViewById()
の回数を減らす(生成済みのものを使いまわす)ことで速度を改善するというもの。
今回はこのViewHolderを使わないでListViewを高速化する方法を書きます。
その方法はズバリ、Custom View
を使う方法です!!
順に説明していきます。
コードはGitHubに上げていますので、参考にしてみてください。
アイテムをカスタムViewにする
ListViewのアイテムのレイアウトファイルと実装を書いていきます。
アイテムのルートレイアウトの名前はItemLayout.java
としています。
レイアウトファイル
タイトル、概要、アイコンを持ったアイテムを想定しています。
<?xml version="1.0" encoding="utf-8"?>
<com.example.nonviewholder.ItemLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<TextView
android:id="@+id/titleView"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
/>
<TextView
android:id="@+id/descriptionView"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
/>
<ImageView
android:id="@+id/iconView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@android:drawable/ic_dialog_alert"
/>
</com.example.nonviewholder.ItemLayout>
ItemLayoutの実装
アイテムのレイアウトはLinearLayoutを継承して実装しています。
ここでのポイントはonFinishInflate()
が呼ばれた時にfindViewById()
することです。
こうすることでAdapterで新しくアイテムのレイアウトを生成するときにだけfindViewById()
されます。
まさにViewHolderと同様の効果が得られます。
public class ItemLayout extends LinearLayout {
// タイトル
TextView mTitleView;
// 概要
TextView mDescriptionView;
// アイコン
ImageView mIconView;
public ItemLayout(Context context, AttributeSet attrs) {
super(context, attrs);
}
@Override
protected void onFinishInflate() {
super.onFinishInflate();
mTitleView = (TextView) findViewById(R.id.titleView);
mDescriptionView = (TextView) findViewById(R.id.descriptionView);
mIconView = (ImageView) findViewById(R.id.iconView);
}
public void bindView(Item item) {
mTitleView.setText(item.title);
mDescriptionView.setText(item.description);
mIconView.setImageResource(item.icon);
}
}
Adapterの処理
アダプターの処理はViewHolderを利用する時よりも簡単にかけます。
getView()
の動きはほぼ一緒ですがViewHolderと同様の処理を
Custom Viewの方で行っているため、レイアウトの生成(or 再利用)とアイテムをレイアウトに渡すだけで済みます。
public class CustomItemAdapter extends ArrayAdapter<Item> {
private LayoutInflater mFactory;
private int mItemLayoutResource;
public CustomItemAdapter(Context context, int resource, List<Item> objects) {
super(context, resource, objects);
mFactory = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
mItemLayoutResource = resource;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
final ItemLayout view;
if (convertView == null) {
// Viewがなかったら生成
view = (ItemLayout) mFactory.inflate(mItemLayoutResource, null);
} else {
view = (ItemLayout) convertView;
}
view.bindView(getItem(position));
return view;
}
}
ViewHolderとの比較
ViewHolderを利用した時のAdapterはこちら。
Viewに対する処理がAdapterに依存するので、見通しが悪いです。(工夫の余地はあるかもしれません)
AdapterにViewの処理を書くよりもCustom Viewにアイテムだけ渡しそちらでViewの処理を任せたほうが
Adapterの肥大化が防げます。
public class ItemAdapter extends ArrayAdapter<Item> {
private LayoutInflater mFactory;
private int mItemLayoutResource;
public ItemAdapter(Context context, int resource, List<Item> objects) {
super(context, resource, objects);
mFactory = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
mItemLayoutResource = resource;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
final ViewHolder holder;
if (convertView == null) {
convertView = mFactory.inflate(mItemLayoutResource, null);
holder = new ViewHolder();
holder.title = (TextView) convertView.findViewById(R.id.titleView);
holder.desc = (TextView) convertView.findViewById(R.id.descriptionView);
holder.icon = (ImageView) convertView.findViewById(R.id.iconView);
convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
}
final Item item = getItem(position);
holder.title.setText(item.title);
holder.desc.setText(item.description);
holder.icon.setImageResource(item.icon);
return convertView;
}
class ViewHolder {
TextView title;
TextView desc;
ImageView icon;
}
}
まとめ
ViewHolderを使わないでListViewを高速化する方法を書いてみました。
個人的にはTextViewに文字をセットする等のViewを操作する処理をCustom Viewに任せられ、
Adapterの見通しもよくなるため、ViewHolderよりもCustom Viewの方が好きです。
ViewHolderでもっと良い書き方あるよ!と言う方がいらっしゃいましたら、
ぜひコメントに書いて下さい。
あと、個人的なことですがQiitaに3日連続で投稿しています。
そろそろ投稿するネタが尽きてきました。。