상세 컨텐츠

본문 제목

[Android] RecyclerView, DiffUtil

안드로이드

by 개발혱 2022. 9. 13. 08:55

본문

ListView vs RecycierView

- RecyclerView는 ListView의 향상된 버전입니다.

  - 스크롤 업 / 다운 하는 동안 셀들을 재사용할 수 있습니다.

     어뎁터에서 뷰 홀더를 구현하면 가능 하지만 어댑터를 작성하는 기본 방법인 ListView 동안에는 선택사항이었습니다.

  - 컨테이너로부터 리스트들을 분리시킵니다.

     런타임 목록 항목을 다른 컨테이너 LinearLayout, GridLayout에 쉽게 넣을 수 있습니다.

  - 애니메이션 공통 목록 작업

     ItemAnimator 애니메이션이 분리되어 위임됩니다. 

RecycierView Pool

 다양한 뷰들 사이에 당신을 뷰를 공유하도록 허용합니다.

 만약 당신은 리사이클러뷰들을 통해서 재활용하길 원한다면, 리사이클러뷰풀의 인스턴스를 발생시키시기바랍니다. 그리고 RecyclerView.setRecycledViewPool(RecycledViewPool) 를 사용하시기바랍니다. 리사이클러뷰는 자동적으로 풀을 발생합니다. 만약 당신이 하나를 제공하지않길 원한다면 그것들의 풀을 발생합니다. 

@Adapter
private val viewPool: RecyclerView.RecycledViewPool = RecyclerView.RecycledViewPool()

@ViewHolder
init {
    recyclerview.adapter = adatper
    val layoutManager = LinearLayoutManager(itemView.context)
    layoutManager.recycleChildrenOnDetach = true//viewPool 해당
    layoutManager.orientation = LinearLayoutManager.HORIZONTAL
    recyclerview.layoutManager = layoutManager
    recyclerview.setRecycledViewPool(viewPool)//viewPool 해당
}

ViewPool을 사용할 경우, 동일한 타입의 리스트뷰를 여러번 생성할 것을 줄여주고 재활용하여 사용하게 됩니다.

ViewPool 예시

ViewPool의 최대 갯수는 5개 입니다.

AsyncListDiffer

 DiffUtil은 아이템 수가 많으면 연산에 필요한 시간이 길어질 수 있기 때문에 백그라운드 스레드에서 처리하는 것이 좋습니다.

AsyncListDiffer은 내부적으로 diff 계산을 백그라운드 스레드로 처리한 뒤 리스트 업데이트까지 해 줍니다.

덕분에 우리는 스레드를 신경쓰지 않고 DiffUtil을 훨씬 편하게 사용할 수 있습니다.

ListAdapter

AsyncListDiffer를 더 쓰기 편하도록 랩핑한 클래스가 바로 ListAdapter입니다. 

ListAdapter는 사용자를 위해 목록을 추적하고 목록이 업데이트 될 때 어댑터에 알립니다.

 

ListAdapter를 사용한 RecyclerView Adapter는 아래처럼 만들 수 있습니다.

DiffUtil

DiffUtil은 두 목록의 차이를 계산하고 첫 번째 목록을 두 번째 목록으로 변환하는 업데이트 작업 목록을 출력하는 유틸리티 클래스입니다.

 

RecyclerView 어댑터에 대한 업데이트를 계산하는 데는 사용할 수 있습니다. 백그라운드 스레드에서 DiffUtil 사용을 단순화 할 수 있는 항목 ListAdapter을 참조하시기바랍니다.

 

한 목록을 다른 목록으로 변환하기 위한 최소 업데이트 수를 계산합니다. 이 클래스는 Eugene W. Myers's difference algorithm을 이용하여 최소한의 업데이트 수를 계산한다. Myers의 알고리즘은 이동된 항목을 처리하지 않으므로 DiffUtil은 결과에 대해 두 번째 단계를 실행하여 이동된 항목을 감지합니다. 

 

DiffUtil, ListAdapter, 및 AsyncListDiffer 사용 중에 목록이 변경되지 않도록 요구합니다. 이것은 일반적으로 목록 자체와 해당 요소를 직접 수정해서는 안 된다는 것을 의미합니다. 대신 콘텐츠가 변경될 때마다 새 목록을 제공해야 합니다. DiffUtil에 전달된 목록은 변경되지 않은 요소를 공유하는 것이 일반적으므로 DiffUtil사용하기 위해 모든 데이터를 다시 로드할 필요는 없습니다.

 

목록이 크면 이 작업에 상당한 시간이 걸릴 수 있으므로 백그라운드 스레드에서 실행한 DiffUtil.DiffResult하고 기본 스레드의 RecyclerView에 적용하는 것이 좋습니다.

 

이 알고리즘은 공간에 최적화되어 있으며 O(N) 공간을 사용하여 두 목록 간의 최소 추가 및 제거 작업 수를 찾습니다. D는 편집 스크립트의 길이인 O(N + D^2) 예상 시간 성능을 갖습니다.

 

이동 감지가 활성화 되면 추가 O(MN) 시간이 걸립니다. 여기서 M은 추가된 총 항목 수이고 N은 제거된 총 항목 수 입니다. 목록이 이미 동일한 제약 조건으로 정렬되어 있는 경우(예: 게시물 목록에 대해 생성된 타임스템프) 성능을 개선하기 위해 이동 감지를 비활성화할 수 있습니다.

 

알고리즘의 실제 실행 시간은 목록의 변경 수와 비교 방법의 비용에 따라 크게 달라집니다. 

Diffutil.Callback

두 목록 간의 차이를 계산하는 동안 DiffUtil에서 사용하는 콜백 클래스입니다.

areItemsTheSame(동일한 항목)

두 객체가 동일한 항목을 나타내는지 여부를 결정하기 위해 DiffUtil에 의해 호출됩니다. (보통 유니크한 아이디값 비교)

예를 들어 항목에 고유 ID가 있는 경우 이 메서드는 ID가 동일한지 확인 해야 합니다.

areContentsTheSame(내용이 같다)

두 항목에 동일한 데이터가 있는지 확인하려는 경우 DiffUtil에 의해 호출됩니다.

DiffUtil은 이 정보를 사용하여 항목의 내용이 변경되는지 감지합니다.  DiffUtil은 UI에 따라 동작을 변경할 수 있도록 대신 Object.equals(Object) 이 메서드를 사용하여 동등성을 확인 합니다. 예를 들어 DiffUtil을 a와 함께 사용하는 RecyclerView.Adapter 경우 항목의 시각적 표현이 동일한지 여부를 반환해야 합니다. 

 이 메서드는 이러한 항목이 areItemsTheSame(int, int)반환 되는 경우에만 호출됩니다.

 

참고 자료

- [안드로이드 공식문서 파헤치기] RecyclerView의 모든 것! - 2편(ViewHolder수명주기)

- Recycler View 제대로 이해하기 - RecyclerView lifecycle

- DiffUtil.ItemCallback

- [Android] RecyclerView DiffUtil

- RecyclerView vs. ListView

- RecyclerView.RecycledViewPool

- RecycledViewPool을 사용한 RecyclerView 최적화

- android RecycledViewPool

 

RecyclerView optimization using RecycledViewPool

In the previous post we have looked at how to clean up resources in RecyclerView.ViewHolder which makes sure we don’t waste memory unnecessarily. But that’s not all of the things you can do to make RecyclerView scrolling more smooth, there are number o

androidexplained.github.io

 

RecyclerView.RecycledViewPool  |  Android Developers

androidx.car.app.managers

developer.android.com

 

RecyclerView vs. ListView

From android developer (Creating Lists and Cards): The RecyclerView widget is a more advanced and flexible version of ListView. Okay, it sounds cool, but when I saw this example picture, I got

stackoverflow.com

 

[Android] RecyclerView DiffUtil

RecyclerView에 표현할 데이터를 업데이트하기 위해 주로 notifyDataSetChanged()를 호출한다. notifyDataSetChanged() 리스트의 내용이 변경되어 notifyDataSetChanged()를 호출하면, Adapter에게 RecyclerView..

dannie.dev

 

관련글 더보기