- RecyclerView
- Adapter
- Layout Manager
목록 UI를 설계할 때 개발자로는 기본적으로 이 3가지 요소로 RecyclerView 목록을 구현하고는 하는데,
오늘은 목록의 동작 과정에 대해 좀 더 자세히 알아보도록 하자.
다음은 Recyclerview의 주요 구성요소에 대한 간단한 설명이다.
RecyclerView
itemView가 나열되어 있는 viewGroup
(ViewHolder 패턴을 강제화, 컴포넌트 패턴)
Layout Manager
목록의 개별 요소(ItemView)를 올바른 위치에 배치(정렬)해주는 컴포넌트
개별 항목의 위치를 정하며 사용자에게 더 이상 보이지 않는 항목 뷰(View)를 재사용할 시점을 결정한다.
레이아웃 매니저(Layout Manager)는 View를 재사용하기 위해 어댑터(Adapter)에게 View의 내용(Contents)을 데이터세트의 다른 요소로 바꾸도록 요청할 수 있다.
View 재활용의 성능 향상 이점
- 불필요한 View 생성 방지
- 고비용의 findViewById() 조회 방지
표준 레이아웃 관리자
- LinearLayoutManager : 항목을 1차원 목록으로 정렬
- GridLayoutManager : 항목을 2차원 그리드로 정렬
- 세로(vertically) 정렬: 각 행의 모든 요소를 동일한 너비와 높이로 만들려고 하지만 행마다 높이가 다를 수 있습니다.
- 가로(horizontally) 정렬: 각 열의 모든 요소를 동일한 너비와 높이로 만들려고 열마다 너비가 다를 수 있습니다.
- StaggeredGridLayoutManager : 각 열이 약간씩 오프셋 된 2차원 그리드로 항목을 정렬
- 행의 항목이 동일한 높이(세로 Grid인 경우)이거나 동일한 열의 항목이 동일한 너비(가로 Grid인 경우) 일 필요가 없습니다.
- 결과적으로 행 또는 열의 항목이 서로 오프셋 상태가 될 수 있습니다.
Adapter
RecyclerView에 ItemView를 제공해 주는 컴포넌트
Adapter는 필요에 따라 ViewHolder 객체를 만들고 이러한 뷰(View)에 데이터를 연결한다.
ViewHolder는 목록에 있는 개별 항목의 레이아웃을 포함하는 View의 래퍼(wrapper)로,
이 두 클래스가 함께 작동하여 데이터 표시 방식을 정의한다.
바인딩(binding): 뷰(View)와 해당 데이터(data)를 연결하는 과정(process)
Adapter의 주요 메서드
- onCreateViewHolder() : RecyclerView가 새 ViewHolder를 만들어야 할 때마다 호출
- ViewHolder와 그에 연결된 View를 생성하고 초기화
- ViewHolder가 아직 특정 데이터에 바인딩된 상태가 아니기 때문에, 뷰의 내용(Contents)은 채우지는 않음
- onBindViewHolder() : RecyclerView가 ViewHolder를 데이터와 연결할 때 호출
- 적절한 데이터를 가져와서 그 데이터를 사용하여 뷰 홀더(ViewHolder)의 레이아웃을 채움
- ex) 뷰 홀더(ViewHolder)의 TextView 위젯을 특정한 Text 글자로 채움
- getItemCount() : RecyclerView가 데이터 세트 크기를 가져올 때 호출
- RecyclerView는 이 메서드를 사용하여, 항목을 추가로 표시할 수 없는 상황을 확인
- ex) 주소록 앱에서는 총 주소 개수
Animator
항목이 변경될 때마다 RecyclerView는 애니메이터를 사용한다.
RecyclerView.ItemAnimator 추상 클래스를 확장한 객체.
기본적으로 RecyclerView는 DefaultItemAnimator를 사용하여 애니메이션을 제공한다.
ViewHolder Lifecycle
Recyclerview를 User가 스크롤하는 경우, 내부에서 일어나는 상황
- Recyclerview는 스크롤되면서 새로운 ItemView를 보여줘야 함.
- Recyclerview -> Layout Manager: 새로운 ItemView를 보여줘야 한다는 사실을 알림.
- Layout Manager는 데이터가 연결(Bind=> Adapter) 된 ItemView를 배치
사용자에게, 해당하는 ItemView를 보여주기 위해 진행되는 과정을 풀어,
ViewHodler의 Lifecycle를 연관 지어 설명하면 다음과 같다.
RecyclerView가 새로운 View를 보여주는 과정
사용자가 RecyclerView를 위로 스크롤 할 경우 아래에 보이지 않던 VIew를 보여주기 위해 다음과 같은 과정이 일어난다.
RecyclerView는 Layout Manager에게 새로 보일 View의 배치를 요청하고,
Layout Manager는 요청 받은 View의 레이아웃 위치를 계산하여 해당하는 View 객체를 RecyclerView한테 요청한다.
(배치할 위치를 계산하고 배치할 객체를 RecyclerView한테 요청 ← "여기에 배치하면 될 듯! 어서 주셈!")
View 객체가 Cache에 존재할 경우
RecyclerView는 요청받은 View 객체가 Cache에 존재하는지 확인하고, 존재할 경우 해당 객체를 Layout Manager에 전달한다.
Layout Manager는 전달받은 View 객체를 배치하고 RecyclcerView에게 알려준다. (addView())
RecyclerView도 해당 사실을 Adapter에게 알려준다. (OnViewAttachedToWindow())
_(배치 완료)_
만약 Cache가 존재하지 않은 경우
RecyclerView는 View 객체를 가져오기 위해 단계를 더 거치게 된다.
RecyclerView는 찾고자 하는 View 객체 ViewType을 Adapter에게 요청하여 확인한 다음,
Recycled Pool에 해당 ViewType의 ViewHolder가 있는지 확인한다.
만약 Recycled Pool에 ViewHolder가 없는 경우
ViewHolder를 얻기 위해 한 가지 단계가 더 추가된다.
만약, Recycled Pool에 VIewHolder가 존재할 경우는 바로 해당 ViewHodler를 Bind 하는 과정으로 넘어간다.
RecyclerView는 Adapter에게 요청한 새 ViewHodler나 Recycled Pool에서 가져온 ViewHolder를 Adapter에 전달하여 BInd를 요청한다.
그렇게 얻은 Bind 된 VIew 객체를 RecyclerView는 Layout Manager에게 전달한다.
Layout Manager는 전달받은 View 객체를 배치하고 RecyclcerView에게 알려준다. (addView())
RecyclerView도 해당 사실을 Adapter에게 알려준다. (OnViewAttachedToWindow())
_(배치 완료)_
전체적인 Flow를 정리하면 다음과 같다.
- RecyclerView에 스크롤 이벤트가 일어나고, RecyclerView는 Layout Manager에 ItemView 배치를 요청한다.
- Layout Manager가 레이아웃에서 ItemView가 배치되어야 할 위치(position)를 계산한다.
- Layout Manager는 해당 위치를 Recyclerview에게 알려 View 객체(ItemView)를 요청한다.
- recyclerView.getViewForPosition() 호출
- RecyclerView는 해당 위치에 배치되어야 할 View 객체(ItemView)가 있는지 Cache를 확인한다.
- cache.getViewForPosition()
- 만약, Cache에 해당 View 객체가 없다면?
- RecyclerView는 Adapter에게 해당하는 View 객체(ItemView)의 ViewType을 요청한다.
- adapter.getViewType()
- RecyclerView는 Recycled Pool에 알게 된 ViewType의 ViewHolder가 있는지 확인한다.
- pool.getViewHolderByType()
- Recycled Pool에 ViewHolder가 없다면?
- RecyclerView는 Adapter에 새로운 ViewHolder를 만들 것을 요청한다.
- createViewHolder
- ViewHolder을 전달받은 RecyclerView는 Adapter에게 위치(Position)와 ViewHolder를 전달해 주고 해당 ViewHolder에 Bind를 요청한다.
- adapter.bindViewHolder()
- Bind 된 ItemView(View 객체)를 전달받은 RecyclerView는 ItemView를 Layout Manager에게 전달한다.
- Layout Manager는 전달받은 ItemView를 특정 위치에 배치하고 RecyclerView에 이 사실을 알립니다.
- addView
- RecyclerView는 ItemView가 잘 배치되었다는 사실을 Adapter에도 알려줍니다.
- onViewAttachedToWindow
간단하게 정리해 보면,
RecyclerView를 스크롤할 때 새로운 View를 Layout Manager에게 배치를 요청하고,
이때 배치될 View 객체를 RecyclerView가 제공하기 위해
- Cache : 캐싱된 Veiw 객체
- Recycled Pool : 해당 데이터가 Bind 되지 않은 ViewHodler
- Adapter: 해당하는 ViewHolder 새로 만들기
다음과 같은 순번을 따라 VIew 객체를 구해온다.
1번 단계의 캐싱 적중이 된다면 Bind 단계도 거치지 않고 바로 View 객체를 전달할 수 있게 되며,
Adpater도 거치지 않고 오직 Layout Manager <-> RecyclerView <-> Cache 끼리의 상호작용으로 View 배치가 완료되는 것이다.
게다가, Cache와 Recycled Pool은 Recycler 내부에 존재하기 때문에 속도 측면에서 더 효율적으로 동작할 수 있을 것이다.
크게 보면 캐싱 적중을 한다면 Layout Manager <-> RecyclerView 상호작용만으로 View 객체를 배치할 수 있는 것이다.
그렇다면 스크롤을 통해 사라지는 View는 어떤 과정을 거치는 걸까?
이때, 사라지는 View는 Layout Manager에 의해 배치에서 제거되고, 해당 View는 나중에 재활용됩니다.
RecyclerView에서 기존 View가 사라지는 과정
View가 제거된 이후 RecyclerView는 해당 View가 Cache에 저장될 View인지 확인하고,
만약 Cache에서 제거될 ItemView가 있다면 이 사실을 Recycled Pool에게 알려주고 Recyceld Pool도 Adapter에 이 사실을 알려 해당 객체가 메모리에서 제거될 수 있도록 알려준다.
정리하면 다음과 같다.
- Layout Manager은 화면에서 벗어난 ItemView을 제거하고 RecyclerView한테 알려준다.
- removeAndRecycleView()
- RecyclerView는 해당 사실을 Adapter에게 알려준다.
- onViewDetachedFromWindow()
- 또한, RecyclerVeiw는 현재 제거되는 ItemView가 위치(Position)에 대해 유효한지 확인하고, Cache에 보관하라고 지시한다.
- Cache에 삭제되어야 할 ItemView가 있다면? (oldest cache)
- 삭제될 ItemView에 대한 내용을 Recycled Pool에게 알려주어 해당 ItemView의 정보를 전달한다.
- recylce()
- Recycled Pool은 해당 ItemView를 메모리상에서 제거해도 된다는 메시지를 Adapter에게 전달한다.
- onViewRecycled()
RecyclerView는 View의 재활용을 효율적으로 사용하기 위해 Cache와 Recycled Pool을 사용하는데,
Cache에 공간이 남아 있다면 기본적으로 View의 객체는 Cache에 저장되고, 만약 Cache가 가득 찼을 경우 Cache에서 가장 오래된 View 객체(oledest cache)는 Recycled Pool에 저장된다고 한다.
그렇게 RecyclerView는 Cache와 Recycled Pool을 이용해 View 객체를 일일이 새로 생성하지 않고, 적절하게 View 객체를 재활용하여 자원을 효율적으로 사용한다.
더 알아보면 좋은 내용
- Adapter 심층 탐구
- Compose LazyColumn과의 비교
- ViewHolder Lifecycle 추가 내용
- Fancy Reserves
- Death
출처 및 참고자료
출처
https://developer.android.com/develop/ui/views/layout/recyclerview?hl=ko
RecyclerView로 동적 목록 만들기 | Views | Android Developers
이 페이지는 Cloud Translation API를 통해 번역되었습니다. 컬렉션을 사용해 정리하기 내 환경설정을 기준으로 콘텐츠를 저장하고 분류하세요. RecyclerView로 동적 목록 만들기 Android Jetpack의 구성요
developer.android.com
https://landenlabs.com/android/info/recycler/recycler.html
Android Recycler View Lifecycle diagrams and notes
[Go Back] Android Recycler View Lifecycle diagrams and notes Main Components Main RecyclerView components. ViewHolder Life Cycle While Layout Manager is calculating layout, it asks RecyclerView for View objects recyclerView.getViewForPosition(...) Recylcer
landenlabs.com
참고 자료
[Android] RecyclerView Deep Dive - 1. RecyclerView 정의와 동작원리 및 생명주기
개요 이전에 RecyclerView에 대한 글을 정리한 적이 있었다. 당시에는, RecyclerView의 등장 의의와 RecyclerView를 사용하는 경우에 구현해야 하는 구현부에 대한 내용을 중심으로 작성했었다. 2022.12.22 - [I
hodie.tistory.com
Recycler View 제대로 이해하기 - RecyclerView lifecycle
안드로이드에서 리스트뷰는 많은 데이터들을 일렬로 나열해주는 우리가 자주 볼수있는 화면입니다. 그러나, 매번 스크롤할때마다 새 항목을 만들고 뷰를 생성하는게 비용이 커서 리소스 소비
kimdabang.tistory.com
Anatomy of RecyclerView: a Search for a ViewHolder
Intro
medium.com
'Android > 학습' 카테고리의 다른 글
[Kotlin] Coroutine Flow란, 그리고 Flow, StateFlow, SharedFlow.. (9) | 2025.07.06 |
---|---|
[CS] 동기 vs 비동기, 블로킹 vs 논블로킹, 그리고.. (1) | 2025.06.14 |
[Kotlin] Kotlin Coroutine with Dispatcher (1) | 2025.04.09 |
[Android] Paging3의 PagingSource, PagingConfig와의 관계 (0) | 2025.03.29 |
[Android] Fragment Manager, Basic 편 (1) | 2025.02.16 |