Androidのアプリ開発で大量のデータを画面上に表示したいときがあります。
RecyclerViewを使えば、大量のデータを効率的に表示することができます。
RecyclerViewは、優れたアプリを作るためのライブラリ「Android Jetpack」の1つです。
RecyclerViewとは
Androidデベロッパーでは、RecyclerViewは次のように説明されています。
RecyclerView は、その名のとおり、これらの個々の要素をリサイクルします。アイテムが画面外にスクロールされても、RecyclerView はビューを破棄せず、画面上にスクロールされた新しいアイテムのビューを再利用します。この再利用は、パフォーマンスの大幅な改善、アプリの応答性の向上、消費電力の削減をもたらします。
Androidデベロッパー
Androidでデータをリストやグリッド状に表示させるには、RecyclerView以外にもListViewやGridViewがあります。
RecyclerViewは、ListViewやGridViewに比べて実装が複雑になりますが、様々な方法でデータを表示させることができ、現在の画面上に表示されているデータしか処理しないため、非常に効率的です。
RecyclerViewを使えば、画面からスクロールアウトしたビューを再利用して新しいデータを表示します。以下の画像では、ABCのビューがスクロールアウトした後に、新しいデータのXYZを表示するためにABCのビューを再利用します。
RecyclerViewを使うための5つのステップ
今回はデータをリスト表示する、以下のようなアプリを作成します。
RecyclerViewを使うために、大きく5つ作業が必要になります。
- gradleに依存関係を追加する
- レイアウトにrecyclerViewを配置する
- データ1つあたりのレイアウトファイルを作成する
- アダプターとビューホルダーを作成する
- レイアウトマネージャーを作成する
それでは1つずつ見ていきましょう。
ステップ1 gradleに依存関係を追加する
「build.gradle(Module: app)」ファイルを開いて、次の依存関係を追加します。
dependencies {
・・・
implementation 'androidx.recyclerview:recyclerview:1.2.1'
}
最新のバージョンは、AndroidXのリリースページで確認することができます。
ステップ2 レイアウトにrecyclerViewを配置する
レイアウトにRecyclerViewを配置します。
res/layoutの「activity_main.xml」を開いて、以下の内容に書き換えます。
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/rvList"
android:layout_width="match_parent"
android:layout_height="match_parent"
/>
</LinearLayout>
<androidx.recyclerview.widget.RecyclerView />の部分にデータが表示されるようになります。
ステップ3 データ1つあたりのレイアウトファイルを作成する
RecyclerViewで表示するデータ1つあたりのレイアウトファイルを作成します。
res/layoutフォルダを右クリックし、「New」→「XML」→「Layout XML File」からレイアウトファイルを作成します。
今回は、「text_item_view」という名前で作成します。「text_item_view.xml」を開いたら以下のように変更してください。
<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/textView"
android:textSize="48sp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
/>
TextViewだけのシンプルなレイアウトファイルです。TextView1つだけでなく、複数のビューを配することもできます。
ステップ4 アダプターとビューホルダーを作成する
RecyclerViewを使用するためには、アダプターとビューホルダーが必要になります。
このアダプターの作成がRecyclerViewの中心的な作業になります。
アダプターとは
アダプターとは、「適合させる」という意味があります。アダプターパターンは、有名なGoFのデザインパターンの一つで、あるクラスのインターフェースを変更することなく別クラスのインターフェースに変更します。
例えば、電気のコンセントは日本と海外では異なります。日本の家電を海外で使うときは、変換アダプターを使いプラグの形状を変えて使います。
このように家電自体のコンセントを変えずに、別のコンセントで使えるようにするのがアダプター役割です。
アダプターパターンも電気のコンセントと同じように、異なるクラス同士のインターフェースを変更せずに使用する役割を担います。
今回のコードでは、表示するデータをレイアウトファイルのRecyclerViewに表示させるためにアダプターを使っています。
RecyclerViewでアダプター使うときには、次の3つのメソッドをオーバーライドする必要があります。
- onCreateViewHolder():RecyclerViewは、新しいViewHolderを作成する必要があるたびにこのメソッドを呼び出します。
- onBindViewHolder():RecyclerViewは、このメソッドでViewHolderにデータを関連付けます。
- getItemCount():RecyclerViewは、このメソッドで表示するデータの数を取得します。
RecyclerViewでデータが表示されるまでの流れを簡単に説明すると次のとおりです。
- onCreateViewHolder()を呼び出す
- onCreateViewHolder()で、アイテムのレイアウトXMLファイルをもとにビューホルダーを作成して返す。
- onBindviewHolder()を呼び出す。そのときに、2で作成したビューホルダーと表示される位置を受け取る。
- 受け取ったビューホルダーに表示するデータを埋め込む
アダプタークラスの作成
アダプターが何かわかったところで、実際のコードを作成してみましょう。
javaフォルダ内のプロジェクトを右クリックし、「New」→「Kotlin Class/File」からKotlinファイルを作成します。
「ItemAdapter」という名前で作成し、「ItemAdapter.kt」を開いたら以下のように変更してください。Import文などは省略しています。
class ItemAdapter: RecyclerView.Adapter<ItemAdapter.ViewHolder>() {
val data = listOf<Int>(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20)
class ViewHolder(view: View): RecyclerView.ViewHolder(view) {
val textView: TextView
init {
textView = view.findViewById(R.id.textView)
}
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val layoutInflater = LayoutInflater.from(parent.context)
val view = layoutInflater.inflate(R.layout.text_item_view, parent, false)
return ViewHolder(view)
}
override fun onBindViewHolder(viewHolder: ViewHolder, position: Int) {
val item = data[position]
viewHolder.textView.text = item.toString()
}
override fun getItemCount() = data.size
}
onCreateViewHolder()
onCreateViewHolder()は、新しいビューホルダーを作成する必要があるときに呼び出され、ビューホルダーを返します。つまり、表示するためのビューホルダーを作成します。
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val layoutInflater = LayoutInflater.from(parent.context)
val view = layoutInflater.inflate(R.layout.text_item_view, parent, false)
return ViewHolder(view)
}
ビューホルダーを作成するのですが、その前にビューを作成する必要があります。
xmlファイルからビューを作成するために使うのがInflate()です。inflateは「膨らます」という意味で、xmlファイルのレイアウトを膨らませて画面に表示させるイメージです。
レイアウトのビューを作成するためにLayoutInflaterを使います。LayoutInflater.from()メソッドに対象となるコンテキストを渡して、膨らませるLayoutInflaterを取得します。
そして、inflate()にステップ3で作成した「text_item_view.xml」を渡し、ビューを作ります。
最後にビューホルダーを作成して返しますが、ビューホルダーはアダプタークラスのサブクラスで定義しています。
class ViewHolder(view: View): RecyclerView.ViewHolder(view) {
val textView: TextView
init {
textView = view.findViewById(R.id.textView)
}
}
この時点では実際のデータは埋め込められていません。実際のデータを埋め込むのが、次に説明するonBindViewHolder()です。
onBindViewHolder()
onBindViewHolder()は、ViewHolderに表示するデータを関連付けます。ビューホルダーに指定された位置のデータを埋め込むために使います。
引数として、onCreateViewHolder()で作成したビューホルダーとビューに表示するデータの位置を受け取ります。
override fun onBindViewHolder(viewHolder: ViewHolder, position: Int) {
val item = data[position]
viewHolder.textView.text = item.toString()
}
つまりonBindViewHolder()は、表示するデータ1つを取得して、そのデータをビューホルダーに埋め込んでいます。
//表示する1つのデータ
val item = data[position]
//ビューホルダーのtextに文字列として埋め込む
viewHolder.textView.text = item.toString()
getItemCount()
getItemCount()は、表示するためのデータの数を取得します。表示するデータは、1から20までの数字を格納したリストデータになります。
RecyclerViewは、アダプターが持っているデータの数を知る必要があり、この情報で表示するデータが他にないかを判断します。
//表示するためのデータ
val data = listOf<Int>(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20)
override fun getItemCount() = data.size //dataのサイズ この場合は20
ステップ5 レイアウトマネージャーを作成する
RecyclerViewに必要なアダプターなどの作成はできました。あとは、RecyclerViewに設定していきます。
「MainActivity.kt」を開いて、次のコードを記載します。
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
//RecyclerViewの取得
val recyclerView = findViewById<RecyclerView>(R.id.rvList)
//Adapterの設定
val adapter = ItemAdapter()
recyclerView.adapter = adapter
//LayoutManagerの設定
val layoutManager = LinearLayoutManager(this)
recyclerView.layoutManager = layoutManager
}
}
まず、ステップ2で作成した「activity_main.xml」のRecyclerViewを取得します。そして、RecyclerViewにアダプターとレイアウトマネージャーを設定します。
レイアウトマネージャーとは
1つ1つのデータをどのような並びで表示させるかを決めるのがレイアウトマネージャーです。
RecyclerViewは、LayoutManagerを使用してリストやグリッドなどの表示を行います。
レイアウトマネージャーは、標準で3つのレイアウトが用意されています。
- LinearLayoutManager:リストで表示する
- GridLayoutManager:それぞれのデータの高さ(幅)がそろった格子状に表示する
- StaggeredGridLayoutManager:格子状に表示するが、高さ(幅)がそれぞれのデータで異なる。
レイアウトマネージャーを指定しているのが以下のコードです。リスト表示するため、LinearLayoutManagerを指定しています。
val layouManager = LinearLayoutManager(this)
LinearLayoutManagerは、リストは縦に並んで表示されます。
表示するリストを横に並べさせることもできます。その場合は引数に「LinearLayoutManager.HORIZONTAL」を渡します。
val layoutManager = LinearLayoutManager(this, LinearLayoutManager.HORIZONTAL, false)
ちなみに、3番目の引数はレイアウトを逆に表示するかどうかです。「true」を指定した場合は、下から上(横並びのときは右から左)に並べられたリストになります。
val layoutManager = LinearLayoutManager(this, LinearLayoutManager.VERTICAL, true)
LinearLayoutManager以外の場合は、次のように指定します。
//5列の格子状に表示
val layouManager = GridLayoutManager(this, 5)
//5列で高さがバラバラな格子状に表示
val layoutManager = StaggeredGridLayoutManager(5, StaggeredGridLayoutManager.VERTICAL)
今回の場合は、表示するデータの高さがすべて同じなので、GridLayoutManagerもStaggeredGridLayoutManagerも同じような表示になります。
まとめ
RecyclerViewは、実装が少し難しいがデータを効率的にリストやグリッド状に表示させることができる。
RecyclerViewを使うために、大きく5つ作業が必要になる。
- gradleに依存関係を追加する
- レイアウトにrecyclerViewを配置する
- データ1つあたりのレイアウトファイルの作成する
- アダプターとビューホルダーを作成する
- レイアウトマネージャーを作成する
Android開発のためのオススメ書籍
設計についてのオススメの書籍
参考サイト
RecyclerViewで動的リストを作成する Androidデベロッパー
LinearLayoutManager Androidデベロッパー