RecyclerViewの処理の流れ
アダプタクラスを実装する前に、RecyclerView内での各アイテムはどのように生成され、データが割り当てられるのか見ておきましょう。
アダプタとビューホルダ
処理は下図の通り行われます。
アダプタクラス(図7中の(1))そのものはRecyclerView.Adapterを継承して作成します。このクラスは抽象クラスであるため、onCreateViewHolder()、onBindViewHolder()、getItemCount()の3メソッドを必ず実装する必要があります。
また、各アイテムの画面部品を保持するオブジェクトとしてビューホルダというものがあります(図7中の(2))。こちらはRecyclerView.ViewHolderクラスを継承して作ります。
RecyclerView本体は、まずonCreateViewHolder()を呼び出します。その中で、各アイテムの画面部品が記述されたレイアウトxmlファイルを元にこのビューホルダを生成する処理を行い、生成したビューホルダをRecyclerView本体に戻します(図7の(3))。
次に、RecyclerViewはonBindViewHolder()を呼び出し、先に生成されたビューホルダを渡します。ここでは渡されたビューホルダ内の各画面部品にデータを割り当てる処理を行います(図7の(4))。この手順を行うことで、データが割り当てられた各アイテムをリストや格子状に表示することが可能になるのです。
なお、getItemCount()メソッドはデータの件数、つまり必要なアイテムの件数を返すメソッドです。
ここまで解説してきた、アダプタクラスに必要な3メソッドの処理をまとめると、以下のようになります。
-
onCreateViewHolder():ビューホルダオブジェクトを生成するメソッド -
onBindViewHolder():ビューホルダ内の各画面部品に表示データを割り当てるメソッド -
getItemCount():データ件数を返すメソッド
アダプタとビューホルダの記述
では、実際にアダプタクラスとビューホルダクラスを作成していきましょう。まずはビューホルダクラスを作成します。以下のRecyclerListViewHolderクラスをScrollListActivity内にメンバクラスとして追記してください。
public class ScrollListActivity extends AppCompatActivity {
~省略~
private class RecyclerListViewHolder extends RecyclerView.ViewHolder {
public TextView _tvItem; // (1)
public RecyclerListViewHolder(View itemView) { // (2)
super(itemView); // (2)
_tvItem = (TextView) itemView.findViewById(android.R.id.text1); // (3)
}
}
}
ビューホルダは各アイテムのレイアウトに合わせて作成する必要があります。今回のサンプルでは、各アイテムのレイアウトとしてListViewのサンプルでおなじみの「android.R.layout.simple_list_item_1」を使用します。TextViewがひとつだけのレイアウトであるため、RecyclerListViewHolderではpublicフィールドとして、このTextViewを保持するようにしています。それが(1)です。
なお、親クラスであるRecyclerView.ViewHolderにはView型の引数を必要とするコンストラクタが記述されているので、継承先クラスでも必ずコンストラクタを作成して親クラスのコンストラクタを呼び出す必要があります。それが(2)です。引数は各アイテムの画面部品を表すViewオブジェクトです。さらにここでは引数で受け取ったitemViewから実際にデータを表示するTextViewオブジェクトを取得し、フィールドに格納する処理も記述しています。それが(3)です。
さて、ビューホルダが準備できたので、いよいよRecyclerListAdapterを作成しましょう。ScrollListActivity内にメンバクラスとして以下のコードを追記してください。
public class ScrollListActivity extends AppCompatActivity {
~省略~
private class RecyclerListAdapter extends RecyclerView.Adapter<RecyclerListViewHolder> { // (1)
private List<String> _listData; // (2)
public RecyclerListAdapter(List<String> listData) { // (2)
_listData = listData; // (2)
}
@Override
public RecyclerListViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
LayoutInflater inflater = LayoutInflater.from(ScrollListActivity.this); // (3)
View view = inflater.inflate(android.R.layout.simple_list_item_1, parent, false); // (4)
RecyclerListViewHolder holder = new RecyclerListViewHolder(view); // (5)
return holder; // (5)
}
@Override
public void onBindViewHolder(RecyclerListViewHolder holder, int position) {
String item = _listData.get(position); // (6)
holder._tvItem.setText(item); // (7)
}
@Override
public int getItemCount() {
return _listData.size();
}
}
}
先述の通り、アダプタクラスを作成する場合は、RecyclerView.Adapterクラスを継承します。その際、ジェネリクスとしてビューホルダクラスを指定します。ここでは先に作成したRecyclerListViewHolderクラスを指定しています。それが(1)です。
また、アダプタクラスは各アイテムにデータを割り当てるのためのものなので、そのリストデータをあらかじめコンストラクタで受け取り、フィールドに保持しておきます。それが、(2)です。このため、RecyclerListAdapterクラスをnewする際はリストデータを渡す必要があります(リスト4の(5))。
さて、各メソッド内の処理を見ていきましょう。
まず、onCreateViewHolder()メソッドです。ここでの処理は、ビューホルダオブジェクトを生成することですが、その前に各アイテムのレイアウトxmlからViewオブジェクトを作成する必要があります。それはinflete処理であり、(4)がそれにあたります(infleteについては第9回を参照してください)。ただし、その前にLayoutInflaterを取得しておく必要があります。そのためにはLayoutInflaterのstaticメソッドfrom()を使います。それが(3)です(引数はコンテキストです)。
そして、xmlからinflateされたViewオブジェクトを引数としてRecyclerListViewHolderをnewし、それを戻り値とします。それが(5)です。
次はonBindViewHolder()メソッドについてです。このメソッドは引数としてonCreateViewHolder()で生成したビューホルダオブジェクトとアイテムのポジション番号を渡します。これらの引数を使って、まずはポジションから表示データを取得しています。それが(6)です。取得した表示データをビューホルダ内のTextViewフィールドの表示文字列として格納しています。それが(7)です。
最後のgetItemCount()メソッドについての解説は不要でしょう。
この状態で、一度アプリを再起動してください。以下の画面が表示されるはずです。
リスト部分をスクロールしてみてください。スクロール連動も無事動いていると思います。ただし、ListViewには当たり前のようにあった区切り線がありませんし、各アイテムをタップしても反応がありません。
先ほどのアダプタクラスもそうですが、RecyclerViewではこういったListViewがあらかじめ備えている機能を自作する必要があります。その代わりに、柔軟な表示を実現できているのです。
このように、RecyclerViewはListViewの代わりをするものではありません。RecyclerViewとListViewは適材適所で使い分けていくことで、よりユーザビリティの高いアプリを作成することが可能になるのです。
なお、ダウンロードサンプルには区切り線とタップした時の処理も含めているので、参考にしてください。
まとめ
今回は、連載の最後としてRecyclerViewを扱いました。1年以上にわたり、この連載にお付き合いいただきありがとうございました。
この連載では、地に足の着いたAndroid開発技術が身につくような内容を心がけてきました。連載で習得したものを出発点として、その後は各自で応用・発展していくことができる基礎力を習得していただけたのであれば、うれしい限りです。
