본문 바로가기
Android

[Android/Kotlin] DiffUtil과 ListAdapter를 활용한 효율적인 RecyclerView 업데이트

by quessr 2024. 7. 1.

안드로이드 개발에서 RecyclerView는 리스트 형태의 데이터를 표시하는 데 많이 사용됩니다. RecyclerView를 최적화하는 방법 중 하나는 DiffUtil과 ListAdapter를 사용하는 것입니다. 이 글에서는 DiffUtil과 ListAdapter를 함께 사용하는 방법과 그 효율성에 대해 알아보겠습니다.

1. DiffUtil이란?

DiffUtil은 안드로이드의 RecyclerView에서 두 데이터 세트를 비교하여 변경된 항목들을 찾아내고, 해당 변경 사항만 RecyclerView에 업데이트하는 유틸리티 클래스입니다. DiffUtil을 사용하면 성능을 최적화하고, 부드러운 UI 애니메이션을 제공할 수 있습니다.

2. ListAdapter란?

ListAdapter는 RecyclerView.Adapter의 서브클래스로, DiffUtil을 내장하여 데이터 변경을 효율적으로 처리하는 Adapter입니다. ListAdapter를 사용하면 DiffUtil을 직접 구현할 필요 없이 쉽게 RecyclerView의 성능을 최적화할 수 있습니다.

3. DiffUtil과 ListAdapter의 효율성

notifyDataSetChanged()를 사용하여 데이터 변경을 알리는 방법은 전체 데이터 세트를 갱신하기 때문에 성능 저하와 UI 깜빡임 문제가 발생할 수 있습니다. 반면, DiffUtil과 ListAdapter를 사용하면 변경된 항목만 업데이트하여 이러한 문제를 해결할 수 있습니다.

DiffUtil과 ListAdapter 사용 예시

1. 데이터 모델 정의

먼저, RecyclerView에서 사용할 데이터 모델을 정의합니다.

data class MyData(val id: Int, val content: String)

 

2. DiffUtil.ItemCallback 구현

DiffUtil.ItemCallback을 구현하여 ListAdapter에 전달합니다.

class MyDiffCallback : DiffUtil.ItemCallback<MyData>() {
    override fun areItemsTheSame(oldItem: MyData, newItem: MyData): Boolean {
        return oldItem.id == newItem.id
    }

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

 

3. ListAdapter 구현

ListAdapter를 구현하여 RecyclerView와 연결합니다.

class MyListAdapter : ListAdapter<MyData, MyListAdapter.MyViewHolder>(MyDiffCallback()) {

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyViewHolder {
        val view = LayoutInflater.from(parent.context).inflate(R.layout.item_layout, parent, false)
        return MyViewHolder(view)
    }

    override fun onBindViewHolder(holder: MyViewHolder, position: Int) {
        holder.bind(getItem(position))
    }

    class MyViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
        private val textView: TextView = itemView.findViewById(R.id.textView)

        fun bind(data: MyData) {
            textView.text = data.content
        }
    }
}

 

4. RecyclerView 설정

Activity나 Fragment에서 RecyclerView와 ListAdapter를 설정합니다.

class MyActivity : AppCompatActivity() {

    private lateinit var recyclerView: RecyclerView
    private val adapter = MyListAdapter()

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        recyclerView = findViewById(R.id.recyclerView)
        recyclerView.layoutManager = LinearLayoutManager(this)
        recyclerView.adapter = adapter

        // 데이터 초기화
        adapter.submitList(getInitialData())
    }

    private fun getInitialData(): List<MyData> {
        return listOf(
            MyData(1, "Item 1"),
            MyData(2, "Item 2"),
            MyData(3, "Item 3")
        )
    }
}

 

무한 스크롤에서의 활용

DiffUtil과 ListAdapter는 무한 스크롤에서도 매우 효율적입니다. 새로운 데이터를 로드하여 리스트에 추가할 때 변경된 항목만 업데이트하기 때문에 성능을 유지하면서 부드러운 사용자 경험을 제공합니다.

private fun loadMoreData() {
    // 새로운 데이터를 불러오는 로직을 구현합니다.
    val newData = fetchDataFromServer()

    // 기존 데이터에 새로운 데이터를 추가합니다.
    val updatedData = adapter.currentList + newData

    // Adapter에 데이터 업데이트를 요청합니다.
    adapter.submitList(updatedData)
}

 

DiffUtil과 ListAdapter를 사용하면 RecyclerView의 성능을 최적화하고, 부드러운 UI 애니메이션을 제공할 수 있습니다. 특히, 무한 스크롤과 같은 대량의 데이터 변경이 자주 발생하는 상황에서도 효율적으로 동작합니다.