Android Kotlin基礎講座 07.1:RecyclerViewの基礎
目次
タスク:コードを改善する
RecyclerViewは既に完璧な状態です。AdapterとViewHolderの実装方法を学習し、RecyclerView Adapterを用いてリストを表示するためにそれらを組み合わせました。
ここまでのコードはアダプターとビューホルダーの制作過程を示しています。しかしながら、このコードには改善の余地があります。表示するためのコードとビューホルダーを管理するためのコードが一緒になっており、onBindViewHolder()はどのようにViewHolderを更新するかを知っています。
製品版アプリでは、複数のビューホルダーや、より複雑なアダプターを持つことになりますし、複数人の開発者が変更を加えることになります。ビューホルダーに関連するものは全てビューホルダー内にのみ含まれているようにコードを構成するべきでしょう。
ステップ1:onBindViewHolder()をリファクタリングする
このステップでは、コードをリファクタリングし、全てのビューホルダーの機能をViewHolderに移していきます。このリファクタリングの目的はアプリがどのようにユーザーに見えるかを変更するためのものではなく、開発者がコードを簡単に、安全に編集することができるようにするためのものです。幸いにもAndroid Studioにはそのためのツールがあります。
- SleepNightAdapterのonBindViewHolder()内のitem変数の宣言文以外の全てのコードを選択してください。
- 右クリックし、Refactor > Functionを選択してください。
- 関数をbindと命名し、表示されたパラメーターに全てチェックを入れて、OKをクリックしてください。
bind()関数はonBindViewHolder()の下に配置されます。
private fun bind(holder: ViewHolder, item: SleepNight) {
val res = holder.itemView.context.resources
holder.sleepLength.text = convertDurationToFormatted(item.startTimeMilli, item.endTimeMilli, res)
holder.quality.text = convertNumericQualityToString(item.sleepQuality, res)
holder.qualityImage.setImageResource(when (item.sleepQuality) {
0 -> R.drawable.ic_sleep_0
1 -> R.drawable.ic_sleep_1
2 -> R.drawable.ic_sleep_2
3 -> R.drawable.ic_sleep_3
4 -> R.drawable.ic_sleep_4
5 -> R.drawable.ic_sleep_5
else -> R.drawable.ic_sleep_active
})
}
- カーソルをbind()のholderパラメーターのholderというワードの上に置き、Alt+Enter(MacはOption+Enter)を押し、インテンションメニューを開いてください。
Convert parameter to receiverを選択し、これを以下のシグネチャを持つ拡張関数に変換してください。
private fun ViewHolder.bind(item: SleepNight) {...}
- bind()関数を切り取りし、ViewHolder内にペーストしてください。
- bind()をpublicに変更してください。
- 必要な場合はbind()をアダプターにインポートしてください。
- 現在bindはViewHolder内にあるので、シグネチャのViewHolder部分は削除できます。以下がViewHolderクラス内のbind()関数の完成形になります。
fun bind(item: SleepNight) {
val res = itemView.context.resources
sleepLength.text = convertDurationToFormatted(
item.startTimeMilli, item.endTimeMilli, res)
quality.text = convertNumericQualityToString(
item.sleepQuality, res)
qualityImage.setImageResource(when (item.sleepQuality) {
0 -> R.drawable.ic_sleep_0
1 -> R.drawable.ic_sleep_1
2 -> R.drawable.ic_sleep_2
3 -> R.drawable.ic_sleep_3
4 -> R.drawable.ic_sleep_4
5 -> R.drawable.ic_sleep_5
else -> R.drawable.ic_sleep_active
})
}
ステップ2:onCreateViewHolderをリファクタリングする
アダプター内のonCreateViewHolder()メソッドは現在レイアウトリソースのビューをViewHolder用にインフレートしています。しかしながら、インフレーションはアダプターとは何の関係がなく、ViewHolderに関係しています。ですのでインフレーションはViewHolder内で行われるべきです。
- onCreateViewHolder()関数内に含まれる全てのコードを選択してください。
- 右クリックし、Refactor > Functionを選択してください。
- 関数名をfromとし、表示されたパラメーターに全てチェックを入れて、OKをクリックしてください。
- カーソルをfromの上にあてて、Alt+Enter(Macの場合はOption+Enter)を押し、インテンションメニューを開いてください。
- Move to companion objectを選択してください。from()関数はViewHolderインスタンス上からではなく、ViewHolderクラス上で呼ばれるため、companionオブジェクト内にある必要があります。
- companionオブジェクトをViewHolderクラスに移動してください。
- from()をpublicにしてください。
- onCreateViewHolder()内、return文を変更してViewHolderクラスのfrom()の呼び出しの結果を返すようにしてください。
変更後のonCreateViewHolder()とfrom()メソッドは以下のコードのようになります。これでエラーなしで実行できるはずです。
override fun onCreateViewHolder(parent: ViewGroup, viewType:
Int): ViewHolder {
return ViewHolder.from(parent)
}
companion object {
fun from(parent: ViewGroup): ViewHolder {
val layoutInflater = LayoutInflater.from(parent.context)
val view = layoutInflater
.inflate(R.layout.list_item_sleep_night, parent, false)
return ViewHolder(view)
}
}
- ViewHolderクラスのシグネチャを変更して、コンストラクタをprivateにしてください。from()は現在ViewHolderインスタンスを返すメソッドですので、これ以上ViewHolderのコンストラクタを呼び出す理由はありません。
class ViewHolder private constructor(itemView: View) : RecyclerView.ViewHolder(itemView){
- アプリを起動してください。以前と同じ様にビルド、起動できるはずです。
完成済みプロジェクト
お疲れさまでした。完成済みプロジェクトは以下からダウンロードできます。