DiffUtil & ListAdapter
- DiffUtil 탄생(?)배경
이전에 리사이클러뷰가 보여주는 data 목록에 (추가, 삭제, 변경) 이 발생하면 notifyDataSetChanged() 함수를 사용하여 리사이클러뷰에 알리도록 했다.
val data = listOf<SleepNight>() set(value) { field = value notifyDataSetChanged() }
하지만 해당 함수를 사용한 데이터 갱신은 리사이클러뷰로 하여금 모든 아이템들을(아직 스크린에 보여지지 않는 부분 포함)모두 갱신하게 만들어 Large한 데이터 목록을 다룰 경우 비효율적이라는 문제점이 있다.
따라서 두 리스트(old , new) 를비교하여 데이터 목록의 추가, 제거, 변경 상태를 해당 데이터만 리사이클러 뷰에 알려주는 DiffUtil가 탄생하게 되었다. - DiffUtil 사용
Adapter class가 있는 파일에 새로운 Top-Level 클래스
DiffUtilCallback : DiffUtilCallback<data class 타입>를 만든다.
class SleepNightDiffUtilCallback : DiffUtil.ItemCallback<SleepNight>() { override fun areItemTheSame(oldItem: SleepNight, newItem: SleepNight): Boolean { return oldItem.nightId == newItem.nightId } override fun areContentsTheSame(oldItem: SleepNight, newItem:SleepNight) : Boolean { return oldItem == newItem } }
- override fun areItemTheSame(~~): Boolean => oldItem의 유니크한 변수와 newItem의 유니크한 변수 (nightId)를 비교한다. 해당 함수는 데이터의 추가 및 제거를 확인하는 함수.
-override fun areContentsTheSame(~~): Boolean -> oldItem과 newItem이 가진 모든 프로퍼티를 비교한다. data class는 equals을 비교할 수 있는 함수를 기본적으로 제공하기 때문에 가능. 해당 함수는 데이터의 업데이트를 확인하는 함수. - ListAdapter 사용
DiffUtil class를 사용하기 위해서는 기존의 Adapter class의 상속을 ListAdatper로 바꾸어 줘야 한다.
ListAdapter는 RecyclerView에서 지원하는 Adapter의 종류 중 하나이다.
ListAdapter<Data class type, ViewHolder class>(DiffUtil class)
에서//기존 Adapter 클래스 class sleepNightAdapter : RecyclerView.Adapter<sleepNightAdatper.ViewHolder>(){}
//변경된 Adapter 클래스 class sleepNightAdapter : ListAdatper<SleepNight, sleepNightAdapter.ViewHolder>(SleepNightDiffUtilCallback()){ }
로 변경.
변경됨에 따라 기존 Adatper 클래스 내에 있던 변수와 함수들이 불필요하게 되는데,
val data = listOf<SleepNight>() override fun getItemCount() : Int = data.size
해당 프로퍼티와 변수는 사라지게 된다.
따라서 해당 프로퍼티를 사용하던 onBindViewHolder 함수 또한 변경.
override fun onBindViewHolder(holder: ViewHolder, position:Int) { //val item = data[position] val item = getItem(position) ... }
또한 Fragment내에서 adapter에 데이터를 초기화하는 코드 또한 변경.
adatper . submitList(data: SleepNight) 함수를 통해 새로운 데이터로 초기화 할 수 있다.//In SleepNightTrackerFragment.kt viewModel.nights.observe(viewLifecycleOwner, Observer{ it?.let{ adatper.submitList(it) } })