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 で自作したものへ置き換え可能