DoReMi

[Kotlin] ListAdatper / DiffUtil 본문

Android/개념

[Kotlin] ListAdatper / DiffUtil

도레미누 2024. 1. 19. 23:45

ListAdapter? DiffUtil? 왜 써야하는데?

대부분 RecylcerView를 update하기 위해서는 notifyDataSetChanged() 라는 함수를 호출해서 사용했을 것이다.

하지만 notifyDataSetChanged()은 recyclerView의 데이터를 전체 다 업데이트 하게 된다.

recylcerView의 데이터가 전부 교체되는 것이 아닌 1개만 변경되는 경우 상당히 비효율적이라고 볼 수 있다.

그래서 등장한 것이 ListAdapter와 DiffUtil이다.


DiffUtil이란?

기존 RecyclerView Adapter가 하는 일

미리 생성해둔 뷰홀더 객체에 사용자가 원하는 데이터 리스트를 주입하고 데이터 리스트의 변경사항이 있을 때 이를 UI에 반영한다.

RecyclerView.DiffUtil의 역할

현재 데이터 리스트와 교체될 데이터 리스트를 비교하고 바뀌어야 할 데이터만 바꿔줌으로써 훨씬 빠른 시간 내에 효율적으로 데이터 교환을 할 수 있게 한다.

DiffUtilCallback Class

object MyDoodleDiffCallback: DiffUtil.ItemCallback<DoodleImage>() {
    override fun areItemsTheSame(oldItem: DoodleImage, newItem: DoodleImage): Boolean {
        return oldItem.id == newItem.id
    }

    override fun areContentsTheSame(oldItem: DoodleImage, newItem: DoodleImage): Boolean {
        return oldItem == newItem
    }
}

areItemsTheSame : 기존 어댑터와 새롭게 변경되는 어댑터의 아이템이 같은지 확인한다. 각 아이템의 고유 ID값을 활용하여 비교한다. 리턴 타입은 Boolean이다.

areContentsTheSame : 기존 어댑터와 변경되는 어댑터의 아이템 안의 내용을 비교한다. areItemsTheSame 에서 true가 나올 경우 추가적으로 비교하기 위해서 사용하는 함수이다.

ListAdapter란?

ListAdapter는 DiffUtil을 활용하여 리스트를 업데이트할 수 있는 기능을 추가한 recylcerAdapter라고 생각하면 된다.

기존 어댑터와 비교해서 추가로 DiffUtil 기능에 대한 콜백 기능 클래스만 구현하면 되므로 생산성, 효율성을 높일 수 있을 거라 생각합니다.

또한 DiffUtilCallback을 이용해서 item의 갯수를 확인할 수 있기 때문에 ListAdapter에서 구현해야 할 함수를 보면 getItemCount가 사라져 있다.

ListAdapter 정의

ListAdapter<데이터 클래스, 리사이클러뷰 뷰홀더>(개발자 정의 콜백)

ListAdapter Method

  • getItem(position: Int) : protected method이기 때문에 클래스 내부에서 구현할 때 사용한다. 어댑터 내 List Indexing을 할 때 활용할 수 있다.
  • getCurrentList() : 어댑터가 가지고 있는 리스트를 가져올 때 사용한다.
  • submitList(MutableList <T> list) : 리스트 항목을 변경하고 싶을 때 사용한다.
class DoodleAdapter :
    ListAdapter<DoodleImage, DoodleAdapter.DoodleViewHolder>(MyDoodleDiffCallback) {

    class DoodleViewHolder(binding: DoodleSquareBinding) : RecyclerView.ViewHolder(binding.root) {
        private val imageView: ImageView = binding.doodleImageView

        fun bind(bitmap: Bitmap) {
            imageView.setImageBitmap(null)
            imageView.scaleType = ImageView.ScaleType.CENTER_CROP
            imageView.setImageBitmap(bitmap)
        }
    }

    override fun onCreateViewHolder(
        parent: ViewGroup,
        viewType: Int
    ): DoodleViewHolder {
        val binding = DoodleSquareBinding.inflate(LayoutInflater.from(parent.context), parent, false)
        return DoodleViewHolder(binding)
    }

    override fun onBindViewHolder(holder: DoodleViewHolder, position: Int) {
        val item = getItem(position)
        holder.bind(item.bitmap)
    }
}

'Android > 개념' 카테고리의 다른 글

[kotlin] Dagger Hilt  (0) 2024.01.31
[kotlin] ViewModelFactory  (0) 2024.01.26
[Kotlin] Flow(StateFlow,SharedFlow)  (2) 2023.12.19
[Kotlin] Coil 라이브러리  (0) 2023.11.19
[Kotlin] 파이어베이스 사용 코드 예시  (0) 2023.09.14