Android L Developer Preview、Material Design で追加された新ウィジェット(※1)である RecyclerView を使用してみました。
RecyclerView を使用すると、アイテムのサイズが固定長の場合に、従来よりも良いパフォーマンスが得られる(※2)ほか、
アイテムの追加、削除時などのアニメーション(※3)についても、デフォルトで利用することができます。
ちなみに RecyclerView のコードは、現時点(2014/7/11)では見れなかったのですが、前身のコード?っぽいのは、
sdk / sources / android-20 / android / support / v7 / widget / RecyclerView.java
にありました(約5,700行)。
(ソースコード読んで、notifyItemInserted() や notifyItemRemoved() の存在に気づくなど。。。)
以下、
従来の ListView & BaseAdapter で実装した場合のソースコードと、
RecyvlerView & RecyvlerView.Adapter で実装した場合のソースコードを貼っておきました。
文章で書くよりもコードを見た方が分かり易いと思いますので、コード内の番号をヒントに比較してみてください。
BaseAdapter(従来)のコード
public class SampleAdapter1 extends BaseAdapter {
private LayoutInflater mLayoutInflater;
private ArrayList<String> mDataList;
// コンストラクタは、RecyclerView.Adapter でも変更なし
public SampleAdapter1(Context context, ArrayList<String> dataList) {
super();
mLayoutInflater = LayoutInflater.from(context);
mDataList = dataList;
}
// 4.RecyclerView.Adapter の場合、getItemCount() に書き換える
@Override
public int getCount() {
return mDataList.size();
}
// RecyclerView.Adapter では不要
@Override
public Object getItem(int position) {
return mDataList.get(position);
}
// RecyclerView.Adapter では不要
@Override
public long getItemId(int position) {
return position;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder viewHolder;
if (convertView == null) {
// 1.RecyclerView.Adapter の場合、この部分を onCreateViewHolder() で実装する
// ViewHolder の引数には、インフレートしたビューを渡すように変更する
convertView = mLayoutInflater.inflate(R.layout.list_item, parent, false);
viewHolder = new ViewHolder();
// 2.RecyclerView.Adapter の場合、この部分を ViewHolder のコンストラクタ内で実装する
viewHolder.text = (TextView) convertView.findViewById(R.id.text);
convertView.setTag(viewHolder);
} else {
viewHolder = (ViewHolder) convertView.getTag();
}
// 3.RecyclerView.Adapter の場合、この部分を onBindViewHolder() で実装する
String data = (String) getItem(position);
viewHolder.text.setText(data);
return convertView;
}
static class ViewHolder {
TextView text;
}
}
RecyvlerView.Adapter に書き換えた場合のコード
public class SampleAdapter2 extends RecyclerView.Adapter<SampleAdapter2.ViewHolder> {
private LayoutInflater mLayoutInflater;
private ArrayList<String> mDataList;
public SampleAdapter2(Context context, ArrayList<String> dataList) {
super();
mLayoutInflater = LayoutInflater.from(context);
mDataList = dataList;
}
@Override
public SampleAdapter2.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
// 1
View v = mLayoutInflater.inflate(R.layout.list_item, parent, false);
ViewHolder viewHolder = new ViewHolder(v);
return viewHolder;
}
// 4
@Override
public int getItemCount() {
return mDataList.size();
}
@Override
public void onBindViewHolder(ViewHolder holder, int position) {
// 3
String data = (String) mDataList.get(position);
holder.text.setText(data);
}
static class ViewHolder extends RecyclerView.ViewHolder {
TextView text;
public ViewHolder(View v) {
super(v);
// 2
text = (TextView) v.findViewById(R.id.text);
}
}
}
ListView(従来)のコード
ListView listView = (ListView) view.findViewById(R.id.listview); // アダプターの設定(mDataList は、ここでは ArrayList<String>) listView.setAdapter(new SampleAdapter1(getActivity(), mDataList));
RecyvlerView に書き換えた場合のコード
RecyclerView recyclerView = (RecyclerView) view.findViewById(R.id.recyclerview); // コンテキスト:Activity内ではthis、Fragment内ではgetActivity()など recyclerView.setLayoutManager(new LinearLayoutManager(コンテキスト)); recyclerView.setHasFixedSize(true); // アイテムは固定サイズ // アダプターの設定(mDataList は、ここでは ArrayList<String>) recyclerView.setAdapter(new SampleAdapter2(getActivity(), mDataList));
ListView(従来)のリソース
<ListView
android:id="@+id/listview"
android:layout_width="match_parent"
android:layout_height="match_parent" />
RecyvlerView に書き換えた場合のリソース
<android.support.v7.widget.RecyclerView
android:id="@+id/recyclerview"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scrollbars="vertical" />
RecyvlerView.Adapter でデフォルトアニメーションを使用する例
// アイテム追加後、notifyItemInserted(index)を呼び出す(ここでは最後に追加) recyclerView.getAdapter().notifyItemInserted(mDataList.size() - 1); // アイテム削除後、notifyItemRemoved(index)を呼び出す(ここでは先頭を削除) recyclerView.getAdapter().notifyItemRemoved(0);
備考
※1:N5だと、従来のListView と動作比較してみたところ、目に見えてわかるような差は体感できませんでした
※2:Material Design の追加ウィジェットは2つだけで、もう一方は以前紹介した CardView
※3:アニメーションは RecyclerView.ItemAnimator で自作したものへ置き換え可能