Android

[Android] RecyclerView의 AsyncListDiffer 알아보기

도우 2024. 3. 7. 16:02
728x90

DiffUtil에 대한 정보는 이전에 포스팅 하였다.

https://ehdnsdlek.tistory.com/20

 

[Android] RecyclerView의 DiffUtil 알아보기

RecyclerView를 업데이트 하기 위해 초기에는 notifyDataSetChanged()를 호출하여 전체 목록을 업데이트 했지만 이러한 방법은 전체 목록을 재생성하기 때문에 매우 비효율적이다. 이러한 문제를 해결하

ehdnsdlek.tistory.com

오늘은 AsyncListDiffer에 대해 알아보자


AsyncListDiffer 

DiffUtil은 메인 스레드에서 작업이 수행되는 경우 성능이 매우 저하된다고 했다.
AsyncListDiffer는 DiffUtil의 계산을 백그라운드 스레드에서 수행하여 이러한 문제를 해결하고자 등장했다.

이를 통해 UI의 반응성을 유지하면서 데이터 리스트의 변경사항을 효과적으로 처리할 수 있다.

AsyncListDiffer는 RecyclerView와 함께 사용 되며 데이터의 비동기 업데이트를 쉽게 구현할 수 있다.

 

AsyncListDiffer의 사용법

AsyncListDiffer는 DiffUtil을 기반으로 하지만, 차이점 계산을 백그라운드 스레드에서 비동기적으로 수행하여 메인 스레드의 블로킹을 방지하는 래퍼 클래스이다.

내부적으로 이 데이터 리스트에 대한 차이점 계산을 백그라운드 스레드에서 수행하고 계산이 완료되면
UI 스레드에서 RecyclerView에게 변경 사항을 알린다.

AsyncListDiffer는 DiffUtil.Callback 대신 DiffUtil.ItemCallBack<T>의 구현이 필요하다.

 

DiffUtil.ItemCallback<T>에서 구현해야 하는 메서드

  1. areItemsTheSame( T oldItem, T newItem )
    두 객체가 동일한 항목을 대표하는지 여부를 결정한다. (데이터 항목의 고유 ID를 기반으로 판단)

  2. areContentsTheSame( T oldItem, T newItem )
    두 객체의 데이터 내용이 같은지 비교한다. 
    areItemsTheSame이 true를 반환한 항목에 대해서만 호출된다.

 

선택적으로 구현할 수 있는 메서드

  1. getChangePayload( T oldItem, T newItem )
    두 항목 사이의 변경 내용에 대한 payload를 생성한다.
    => 항목의 변화가 세밀하게 관리되어야 할 때 사용한다.
    ex) 특정 필드의 변경을 감지하고 해당 필드만 업데이트 하려는 경우

 

주요 메소드

  1. getCurrentList()
    현재 AsyncListDiffer에 의해 관리되고 있는 리스트를 반환한다.
    => 최신의 데이터 상태를 반영한다.

  2. addListListener(AsyncListDiffer.ListListener<T> listener)
    리스트가 업데이트 될 때마다 알림을 받기위한 리스너이다.
    => 새로운 리스트가 제출되고 차이점 계산이 완료된 후에 호출된다.

 

submitList()

submitList() 메소드가 호출되면 새로운 데이터 리스트를 어댑터에 제출하고,
이전 리스트와 새 리스트 간의 차이점을 백그라운드에서 계산한다.

이 계산이 완료되면, 계산된 차이점을 바탕으로 어댑터에 변경 사항을 알리는 업데이트(notifyItemInserted...)가 내부적으로 수행된다.

이후 어댑터에 변경 사항이 알려지면, RecyclerView는 필요한 위치에 있는 뷰를 업데이트 하기 위해
onBindViewHolder를 호출하며, 이때 최신 데이터를 바탕으로 뷰를 바인딩하게 된다.

예시 코드는 다음과 같다.

public class MyAdapter extends RecyclerView.Adapter<MyAdapter.MyViewHolder> {
    private final AsyncListDiffer<YourDataType> differ = new AsyncListDiffer<>(this, new DiffUtil.ItemCallback<YourDataType>() {
        @Override
        public boolean areItemsTheSame(@NonNull YourDataType oldItem, @NonNull YourDataType newItem) {
            // 항목의 고유 식별자를 비교하여 동일한지 확인합니다.
            return oldItem.getId().equals(newItem.getId());
        }

        @Override
        public boolean areContentsTheSame(@NonNull YourDataType oldItem, @NonNull YourDataType newItem) {
            // 항목의 내용이 같은지 비교합니다.
            return oldItem.equals(newItem);
        }
    });

    @NonNull
    @Override
    public MyViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        // 뷰홀더 생성 로직
        return new MyViewHolder(LayoutInflater.from(parent.getContext()).inflate(R.layout.item_view, parent, false));
    }

    @Override
    public void onBindViewHolder(@NonNull MyViewHolder holder, int position) {
        // 데이터 바인딩 로직
        YourDataType item = differ.getCurrentList().get(position);
        holder.bind(item);
    }

    @Override
    public int getItemCount() {
        return differ.getCurrentList().size();
    }

    public void submitList(List<YourDataType> newData) {
        // 새로운 데이터 세트를 AsyncListDiffer에 제출하여 업데이트합니다.
        differ.submitList(newData);
    }

    static class MyViewHolder extends RecyclerView.ViewHolder {
        // 뷰 홀더 구현
        public MyViewHolder(View itemView) {
            super(itemView);
            // 초기화 로직
        }

        public void bind(YourDataType item) {
            // 아이템 데이터를 뷰에 바인딩하는 로직
        }
    }
}

 

 

정리

이러한 AsyncListDiffer를 사용하면 백그라운드 스레드에서 작업을 수행하고, 변경된 아이템에 대해서만 업데이트 하며,
변경할 아이템의 position을 추적할 필요가 없으므로 훨씬 효율적이다.

다음은 AsyncListDiffer를 더욱 편하게 사용할 수 있는 ListAdapter에 대해서 알아보도록 하자

https://ehdnsdlek.tistory.com/22

 

[Android] RecyclerView와 ListAdapter

이전에 DiffUtil과 AsyncListDiffer에 대해 포스팅하였다. 이번에는 ListAdapter에 대해서 알아보자 ListAdapter RecyclerView의 데이터 업데이트를 처리하는 과정에서 DiffUtil의 사용은 성능을 크게 향상시킬 수

ehdnsdlek.tistory.com

 

728x90