Diffutil이란
기존 list와 새 list를 비교해서 변경된 아이템만 골라 변경해주는 유틸리티 클래스입니다.
BaseAdapter에서 자주 사용하던 notifyDataSetChanged()라는 리스트를 업데이트해 주는 메서드가 있지만 하나의 아이템이 변경되어도 그 아이템만 변경해주는 게 아니라 모든 뷰를 전체적으로 다시 그려줘야해서 비용이 많이 들었습니다.
물론 BaseAdapter에 아이템만 변경해주는 notifyItemChanged(int position)라는 메서드도 있습니다.
하지만 이 메서드는 포지션값을 알고 있어야 하며 하나의 아이템만 변경해줍니다.
notifyDataSetChanged()
연결된 관찰자에게 기본 데이터가 변경되었으며 데이터 세트를 반영하는 모든 뷰가 자체적으로 새로 고쳐야 함을 알립니다.
출처 https://developer.android.com/reference/android/widget/BaseAdapter
notifyItemChanged(int position)
등록된 관찰자에게 의 항목 position이 변경 되었음을 알립니다 .
출처 https://developer.android.com/reference/androidx/recyclerview/widget/RecyclerView.Adapter
DiffUtil을 사용하기 쉽게 도와주는 ListAdapter, AsyncListDiffer가 있습니다. (백그라운드 스레드에 DiffUtil의 사용을 단순화 함)
AsyncListDiffer는 기존 리스트와 새리스트를 비교 시 아이템이 개수가 많을 경우 비교 연산 시간이 길어질 수 있기 때문에 작업을 비동기로 수행합니다. 따라서 AsyncListDiffer는 자체적으로 멀티스레드가 되어있기 때문에 개발자가 따로 비동기 처리를 할 필요가 없습니다.
DiffUtil 사용법
DiffUtil을 사용하기 위해서 DiffUtil.Callback을 구현해 줍니다.
다음으로 DiffUtil.ItemCallback을 구현합니다.
구현한 DiffUtil.ItemCallback은 Adapter 내부에 AsyncListDiffer 객체를 선언해서 사용하면 됩니다.
private val diffUtil = AsyncListDiffer(this, DiffUtilItemCallback())
다음으로는 BaseAdapter에 ListAdapter를 상속시켜 더더 간편하게 사용할 수 있습니다.
외부에서 아이템 리스트를 교체하는 replaceTo(), 특정 포지션의 아이템을 반환하는 getItem() 등 RecyclerView.Adapter 인터페이스에 맞춰 개발자가 손수 구현해야하는 기능들을 할 필요가 없게 해주는게 바로 ListAdapter입니다.
ListAdapter는 AsyncListDiffer의 wrapper 클래스이기도 합니다.
(*AsyncListDiffer에서 currentList는 READ ONLY라서 리스트 변경이 불가하다. 변경을 원할 경우 submitList()를 이용한다. read only 때문에 리스트를 더 신경 써서 관리해야 한다.
submitList란 새 list를 제출할 때 사용합니다.
참고:https://zion830.tistory.com/86
DiffUtil.Callback 메서드
areContentsTheSame(oldItemPosition: Int, newItemPosition: Int) 두 항목에 동일한 데이터가 있는지 확인하려는 경우 DiffUtil에 의해 호출됩니다. |
areItemsTheSame(oldItemPosition: Int, newItemPosition: Int) 두 개체가 동일한 항목을 나타내는지 여부를 결정하기 위해 DiffUtil에 의해 호출됩니다. |
getChangePayload(oldItemPosition: Int, newItemPosition: Int) 때 areItemsTheSame(int, int)수익률 true이 개 항목에 대한 areContentsTheSame(int, int)그들에 대해 false를 반환은 DiffUtil는 변화에 대한 페이로드를 얻기 위해이 메소드를 호출합니다. |
getNewListSize() 새 목록의 크기를 반환합니다. |
getOldListSize() 이전 목록의 크기를 반환합니다. |
DiffUtil.ItemCallback 메서드
areContentsTheSame(T oldItem, T newItem)두 항목에 동일한 데이터가 있는지 확인하기 위해 호출됩니다. |
areItemsTheSame(T oldItem, T newItem)두 객체가 동일한 항목을 나타내는지 확인하기 위해 호출됩니다. |
getChangePayload(T oldItem, T newItem)때 areItemsTheSame(T, T)수익률 true이 개 항목에 대한 areContentsTheSame(T, T)그들에 대해 false를 반환,이 방법은 변경에 대한 페이로드를 얻기 위해 호출된다. |
DiffUtil.Callback과 DiffUtil.ItemCallback의 차이
DiffUtil.Callback: 인덱싱 및 항목 비교의 두 가지 역할을 수행
DiffUtil.ItemCallback: 항목 비교만 실행
Q. 꼭 DiffUtil.Callback과 DiffUtil.ItemCallback 같이 구현해야 하는 건지
DiffUtil.ItemCallback만 구현해서 써도 되는 건지?
DiffUtil.ItemCallback은 목록에서 null이 아닌 두 항목 간의 차이를 계산하기 위한 콜백입니다.
DiffUtil.Callback목록 인덱싱 및 항목 비교의 두 가지 역할을 수행합니다. ItemCallback은 이들 중 두 번째만 처리하므로 프리젠테이션 계층 및 콘텐츠별 diffing 코드에서 배열 또는 목록으로 색인을 생성하는 코드를 분리할 수 있습니다.
public Object getChangePayload(@NonNull T oldItem, @NonNull T newItem) {
return null;
}
areItemsTheSame(int, int)이 두 항목에 대해 true를 반환하고 areContentsTheSame(int, int)이 두 항목에 대해 false를 반환하면 DiffUtil은 이 메서드를 호출하여 변경 사항에 대한 페이로드를 가져옵니다. 예를 들어 RecyclerView와 함께 DiffUtil을 사용하는 경우 항목에서 변경된 특정 필드를 반환할 수 있으며 ItemAnimator는 해당 정보를 사용하여 올바른 애니메이션을 실행할 수 있습니다. 기본 구현은 null을 반환합니다. 매개변수: oldItemPosition – 이전 목록에서 항목의 위치 newItemPosition – 새 목록에서 항목의 위치 보고: 두 항목 간의 변경 사항을 나타내는 페이로드 개체입니다.
목록이 많으면 작업에 상당한 시간이 걸릴 수 있으므로 백그라운드 스레드에서 실행하고 DiffUtil.DiffResult를 가져와서 메인스레드(UI스레드)의 RecyclerView에 적용세요. 또한 구현 제약으로 목록의 최대 크기는 2²⁶개로 제한되어 있습니다.
'android' 카테고리의 다른 글
android studio install SDK path error (0) | 2021.09.23 |
---|---|
Context란 (0) | 2021.09.21 |
[Kotlin] apply 안쪽 코드를 못 읽음 (0) | 2021.09.06 |
[kotlin] setresult 값을 get intent 해오지 못 하는 경우 (0) | 2021.08.31 |
[kotlin] Array 로그 찍는 법 (0) | 2021.08.31 |