効率的なRecyclerViewアプリケーション
19242 ワード
RecyclerViewとは?
RecyclerViewの主なカテゴリと説明
各ビューのHolderオブジェクトを保存
物品の配置を担当する
LinearLayoutManager:リストを横または縦にスクロール
GridLayoutManager:グリッド形式リスト
StaggerdGridLayoutManager:フォークグリッド形式リスト
従来のListViewで使用されているAdapterと同様の概念で、データとプロジェクトのビューを作成します.
ベースレコードビュー
これに基づいて、RecyclerViewを使用してAdapterクラスを作成し、RecyclerViewクラスのAdapterを継承して実装します.
class UserRecyclerViewAdapter : RecyclerView.Adapter<UserRecyclerViewAdapter.MyViewHolder>() {
private val userList = ArrayList<User>()
class MyViewHolder(private val binding:ItemListBinding) : RecyclerView.ViewHolder(binding.root){
fun bind(user:User){
binding.apply {
binding.user = user
}
}
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyViewHolder {
return MyViewHolder(
ItemListBinding.inflate(
LayoutInflater.from(parent.context),
parent,
false
)
)
}
override fun onBindViewHolder(holder: MyViewHolder, position: Int) {
holder.apply { bind(userList[position]) }
}
override fun getItemCount(): Int = userList.size
fun setItem(items: ArrayList<User>) {
userList.clear()
userList.addAll(items)
notifyDataSetChanged()
}
}
これをfragmentなどに使用する方法は以下の通りです.val adapter = UserRecyclerViewAdapter()
// 구현한 Adapter를 등록한다.
binding.recyclerView.adapter = adapter
// Item으로 사용될 List(userList)를 넘겨준다.
adapter.setItem(userList)
// RecyclerView 갱신을 위해 사용
adapter.notifyDataSetChanged()
このように使用する場合、Recyclerviewでデータが変更された場合は、notifyDataSetChangedメソッドを使用してViewHolderコンテンツを更新する必要があります.欠点は、データが変更されるたびにnotifyDataSetChangedが呼び出されることです.これは面倒で、更新する必要のないアイテムもすべて更新され、メモリリソースが大量に消費されます.また、更新時に画面が点滅する話題もあります.
これはDiffUtilで解決できます.
DiffUtil
https://developer.android.com/reference/androidx/recyclerview/widget/DiffUtil
DiffUtilは、2つのデータセットを受信することによって差異を計算するクラスである.
DiffUtilを使用すると、2つのデータセットを比較し、その変更のみを理解してRecyclerViewに反映できます.
参考までに、DiffUtilはEugene W.MyersのDifferenceアルゴリズムを用いてO(N+D^2)時間内にリストの比較を行う.
(N:追加と削除の項目数、D:スクリプト長)
DiffUtilでは、次の手順に従います.
DiffUtil.ItemCallback実施
object TermsListDiffCallback : DiffUtil.ItemCallback<User>() {
override fun areItemsTheSame(oldItem: User, newItem: User): Boolean {
return oldItem == newItem
}
override fun areContentsTheSame(oldItem: User, newItem: User): Boolean {
return oldItem.id == newItem.id
}
}
このDiffUtilはO(N+D^2)の時間的複雑さを持つため,リストの数が多いほど比較が必要なオブジェクトが多くなるため,MainThreadでは書きにくい.Recyclerviewアダプタを作成する場合は、ListAdapterが継承され、このDiffUtilが使用されていることを確認します.Calbackオブジェクトを受信することで、バックグラウンドThreadで実行する効率的なRecyclerViewを実現できます.
ListAdapter
上のUserRecyclerViewAdapter.ktを再包装したソースです.
package com.example.recyclerview2.adapter
import android.util.Log
import android.view.LayoutInflater
import android.view.ViewGroup
import androidx.recyclerview.widget.DiffUtil
import androidx.recyclerview.widget.ListAdapter
import androidx.recyclerview.widget.RecyclerView
import com.example.recyclerview2.data.User
import com.example.recyclerview2.databinding.ItemListBinding
class UserRecyclerViewAdapter :
ListAdapter<User, UserRecyclerViewAdapter.MyViewHolder>(TermsListDiffCallback) {
class MyViewHolder(private val binding: ItemListBinding) :
RecyclerView.ViewHolder(binding.root) {
fun bind(user: User) {
binding.user = user
}
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyViewHolder {
return MyViewHolder(
ItemListBinding.inflate(
LayoutInflater.from(parent.context),
parent,
false
)
)
}
override fun onBindViewHolder(holder: MyViewHolder, position: Int) {
holder.apply {
bind(getItem(position))
}
}
object TermsListDiffCallback : DiffUtil.ItemCallback<User>() {
override fun areItemsTheSame(oldItem: User, newItem: User): Boolean {
return oldItem == newItem
}
override fun areContentsTheSame(oldItem: User, newItem: User): Boolean {
return oldItem.id == newItem.id
}
}
}
まず変わったのは.1.UserRecyclerView AdapterクラスはRecyclerViewです.Adapterを継承するのではなく、ListAdapterを継承します.
2.パラメータとしてDiffUtilを実現するTermsListDiffCallbackオブジェクトを渡す.
3.Itemのsizeを返すgetItemCount()メソッドと、Itemsを設定するsetItem(items:ArrayList)メソッドがなくなりました.
以下のように使用します.
val adapter = UserRecyclerViewAdapter()
binding.recyclerView. = adapter
adapter.submitList(userList)
以前単独で実装されたsetItems法ではなく,ListAdapterクラスのSubmitList法が用いられていることが分かる.これにより、DiffUtilおよびListAdapterを使用すると、RecyclerViewをより効率的に実現することができる.
追加(RecyclerViewで更新できない問題解決策のクリーンアップ)
BindingAdapterを使用してRecyclerViewAdapterを次の場所に接続すると、画面がリフレッシュできないという問題が発生しました.ホットスポットを解析することにより,submitList法が原因である.
submitList(gitUserList)
submitListメソッドで、AsyncListDifferに入ります.Javaクラスでは、次のような論理が表示されます.newListを既存のListと比較し,同一であれば論理を返す.
最初にsubmitListに渡されたオブジェクト(ここではgitUserList:ArrayList)を変更値のみを同じオブジェクトに入れ、同じアドレスを参照して低論理で同じと判断する.
そのため、解決策は次のとおりです.
1.最初にサブミットリストを作成するときは、新しいオブジェクトを追加するか
2.submitList(GitUserList.toMutableList)のように新しいオブジェクトに入れればよい.
Reference
この問題について(効率的なRecyclerViewアプリケーション), 我々は、より多くの情報をここで見つけました https://velog.io/@jaewon3739/효율적인-RecyclerView-적용テキストは自由に共有またはコピーできます。ただし、このドキュメントのURLは参考URLとして残しておいてください。
Collection and Share based on the CC Protocol