RecyclerView에 아이템이 어떻게 추가될까?

RecyclerView는 아이템이 변경되었는지, ViewHolder을 재활용할 수 있는지를 확인하여 효율적으로 UI를 그린다.

변경된 아이템 파악하기1

변경된 아이템은 크게 4가지 방법으로 처리된다.

  1. 모든 뷰 새로 그리기
    • Adapter#notifyDataSetChanged를 호출하는 경우에 해당한다.
    • 가장 단순하지만 비용이 많이 들기 때문에 사용하지 않는 것이 좋다.
  2. 특정 뷰 추가/삭제하기
    • Adapter#nofityItemInserted/ Adapter#nofityItemRemoved를 호출하는 경우에 해당한다.
    • 기존 아이템이나 새로운 아이템이 동일한 item2을 찾지 못한 경우에 해당한다.
    • 특정 뷰를 다시 그리고, 그 뒤의 뷰의 위치를 옮긴다.
  3. 특정 뷰 위치 바꾸기
    • Adapter#nofityItemMoved를 호출하는 경우에 해당한다.
    • 기존 아이템과 새로운 아이템의 item과 content3가 모두 동일하지만 position이 다른 경우에 해당한다.
    • 뷰는 다시 그리지 않고, 두 뷰의 위치를 옮긴다.
  4. 특정 뷰 새로 그리기
    • Adapter#nofityItemChanged를 호출하는 경우에 해당한다.
    • 기존 아이템과 새로운 아이템의 item이 동일하지만 content가 다른 경우에 해당한다.
    • 특정 뷰만 다시 그린다4.

ViewHolder 재활용하기

아이템을 부착할 뷰홀더가 있는지 확인한다. 있다면 해당 뷰홀더를 사용하고, 없다면 새로 만든다.
뷰홀더는 아래 순서로 생성 및 재활용된다.

  1. submitList 호출시 ViewType을 기반으로 캐시5 확인.
  2. onCreateViewHolder: (캐시된 뷰홀더가 없는 경우) 뷰홀더 생성.
  3. onBindViewHolder: 아이템을 뷰홀더에 바인딩.
  4. onAttachedToWindow: 뷰가 화면에 보이게 되었을 때 호출.
  5. onDetachedToWindow: 뷰가 화면에 보이지 않게 되었을 때 호출.
  6. onViewRecycled: 뷰홀더가 다시 사용될 수 있도록 바인딩된 아이템 제거. 이후 onBindViewHolder 재호출.

1Adapter#setHasStableIds를 사용하지 않을 때 기준. 이를 사용하면 Adapter#getItemId의 반환값을 기준으로 변경 여부를 확인한다.
2DiffUtil.ItemCallback#areItemsTheSame 메서드가 비교하는 값.
3DiffUtil.ItemCallback#areContentsTheSame 메서드가 비교하는 값.
4RecyclerView#setHasFixedSize를 사용하면 뷰를 다시 그리는 과정을 최적화할 수 있다.
5LayoutManager 캐시, RecyclerView 캐시, 전역 RecyclerViewPool.