[개념] 리사이클러뷰와 리스트 어댑터의 DiffUtil
1. Adapter의 역할.
Adapter가 맡은 역할은 크게 아래의 네 가지로 나눌 수 있습니다.
- xml의 마크업 코드를 객체로 inflate를 할 때, ViewHolder에 View 객체를 재사용.
- 화면에 RecyclerView를 통해 출력할 데이터(dataSet) 관리. ex) Data index 접근 및 data가 출력될 ViewHolder 변경 등이 가능하다.
- 경우에 따라 Click Event 관리.
- Adapter는 ListView와 RecyclerView의 position에 해당하는 데이터를 View에 Bind 하여 출력합니다.
2. 리사이클러뷰와 리스트 어댑터의 DiffUtil의 사용시 차이점.
RecyclerView (setHasStableIds)
3. DiffUtil.ItemCallback 분석하기
abstract class BaseModel(
open val id : Long,
open val type : CellType
) {
open fun isTheSame(item: BaseModel) : Boolean {
return this.id == item.id && this.type == item.type
}
companion object {
val DIFF_CALLBACK = object: DiffUtil.ItemCallback<BaseModel>() {
override fun areItemsTheSame(oldItem: BaseModel, newItem: BaseModel): Boolean {
return oldItem.isTheSame(newItem)
}
@SuppressLint("DiffUtilEquals")
override fun areContentsTheSame(oldItem: BaseModel, newItem: BaseModel): Boolean {
return oldItem == newItem
}
}
}
}
위 코드에서 과거(oldItem)와 현재(newItem) 리스트의 차이를 비교 해서 areItemsTheSame과 areContentsTheSame를 override 해주는 것을 확인 할 수 있습니다.
아래의 그림으로 각 함수의 사용을 설명하겠습니다.
open fun isTheSame(item: BaseModel) : Boolean {
return this.id == item.id && this.type == item.type
}
override fun areItemsTheSame(oldItem: BaseModel, newItem: BaseModel): Boolean {
return oldItem.isTheSame(newItem)
}
areItemsTheSame은 위와 같이 id 값과 같은 고유값을 비교해서 같은 id인지 확인을 합니다. 이를 통해 이전 항목과 같은 것 인지 테스트를 하게 됩니다. 같으면 true를, 아니면 false를 리턴합니다.
여기서 areItemsTheSame에 false가 나오게되면 false가 나온 항목의 viewholder 를 다시 그려주게 됩니다. 그래서 깜빡거리는 현상이 나타나게 됩니다. true를 반환시에는 깜빡거리는 현상이 나타나지 않습니다.
false 의 경우 예시)
위의 예시는 전체가 깜빡이지만, areItemsTheSame은 항목 id 각각을 비교하여 flase를 반환한 경우 일치하지 않는 id만 viewholder부터 다시 그리고 안의 내용이 작성되게 됩니다. 그래서 true를 반환하는 id의 경우는 깜빡거리지 않습니다.
@SuppressLint("DiffUtilEquals")
override fun areContentsTheSame(oldItem: BaseModel, newItem: BaseModel): Boolean {
return oldItem == newItem
}
areContentsTheSame 은 areItemsTheSame true일 경우만 호출이 됩니다. 그래서 true가 반환이 된다면 viewholder는 다시 그리지 않기 때문에 깜빡거리는 것이 없게 data class 내부의 값 전체를 다 비교합니다. 비교 후 바뀐 Contents 값을 갱신 해줍니다.
true 의 경우 예시)
4. Team Project Yu Maket 적용 사례
테스트 mock data 2개의 List를 각각 준비합니다.
override fun getAllMarketList(): List<TownMarketModel> {
val mockList = listOf(
TownMarketModel(
id = 0, "쥬얼리 샵", true,
LocationLatLngEntity(128.0, 36.0),
"https://picsum.photos/200", 0.11f
),
TownMarketModel(
id = 1, "옷가게", true,
LocationLatLngEntity(128.0, 36.0),
"https://picsum.photos/200", 0.22f
),
TownMarketModel(
id = 2, "피자스쿨", true,
LocationLatLngEntity(128.0, 36.0),
"https://picsum.photos/200", 0.33f
),
TownMarketModel(
id = 3, "빅마트", false,
LocationLatLngEntity(128.0, 36.0),
"https://picsum.photos/200", 0.44f
),
TownMarketModel(
id = 4, "롯데리아", false,
LocationLatLngEntity(128.0, 36.0),
"https://picsum.photos/200", 0.10f
)
)
return mockList
}
override fun getAllMarketListtest(): List<TownMarketModel> {
val mockList = listOf(
TownMarketModel(
id = 0, "쥬얼리 샵", true,
LocationLatLngEntity(128.0, 36.0),
"https://picsum.photos/200", 0.11f
),
TownMarketModel(
id = 1, "옷가게", true,
LocationLatLngEntity(128.0, 36.0),
"https://picsum.photos/200", 0.22f
),
TownMarketModel(
id = 2, "피자스쿨(test)", true,
LocationLatLngEntity(128.0, 36.0),
"https://picsum.photos/200", 0.33f
),
TownMarketModel(
id = 5, "빅마트(test)", false,
LocationLatLngEntity(128.0, 36.0),
"https://picsum.photos/200", 0.44f
),
TownMarketModel(
id = 4, "롯데리아(test)", false,
LocationLatLngEntity(128.0, 36.0),
"https://picsum.photos/200", 0.10f
)
)
return mockList
}
각 데이터들은 실험을 위해서 서로의 차이를 둬서(test)를 붙였습니다. 빅마트의 경우만 id 값이 3->5로 변경되었고 나머지는 id값의 변경이 없습니다. 옷가게와 쥬얼리 샵은 test를 붙이지 않아서 데이터의 변경이 일어나지 않게 하였습니다.
위와 같이 데이터 값을 정해놓고 areContentsTheSame 과 areItemsTheSame 을 어떻게 이해하고 사용하였는지 확인 해보겠습니다.
id값의 변환이 있기 때문에 뷰홀더를 다시 그려서 빅마트의 경우만 크게 깜빡거리는 것을 확인할 수 있습니다. areContentsTheSame에서 false를 반환했기 때문이죠. 나머지 경우 피자스쿨의 경우 살짝 반짝이는 경우를 알 수 있는데 제목이 test가 붙어서 변했기 때문에 뷰홀더를 다시 그리지는 않고 내부의 데이터값만 변환 되는 것을 알 수 있습니다.
5. reference
https://developer.android.com/reference/androidx/recyclerview/widget/DiffUtil
https://developer.android.com/reference/androidx/recyclerview/widget/ListAdapter
https://developer.android.com/reference/androidx/recyclerview/widget/AsyncListDiffer
https://jaeryo2357.tistory.com/70
https://velog.io/@ilil1/%ED%8C%80-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-Yu-Market-%EC%B2%AB%EB%B2%88%EC%A7%B8-%EC%BD%94%EB%93%9C-%EB%A6%AC%EB%B7%B0-2%ED%8E%B8
Author And Source
이 문제에 관하여([개념] 리사이클러뷰와 리스트 어댑터의 DiffUtil), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://velog.io/@ilil1/리사이클러뷰와-리스트-어댑터의-DiffUtil-t9vm2d88저자 귀속: 원작자 정보가 원작자 URL에 포함되어 있으며 저작권은 원작자 소유입니다.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)