반응형
리사이클러뷰의 라이프 사이클 (화면에 보여지기까지의 순서)
- onAttachedToRecyclerView - 리사이클러뷰를 화면에 붙임
- onCreateViewHolder - 홀더를 생성
- onBindViewHolder - 홀더와 뷰를 바인딩
- onViewAttachedToWindow - 홀더가 화면에 온전히 보여짐
- onViewDetachedFromWindow - 홀더가 화면에 보여지지 않음
- onViewRecycled - 재사용할 홀더 가져오기
- onDetachedFromRecyclerView - 리사이클러뷰를 화면에서 떼냄
"이 포스팅은 쿠팡 파트너스 활동의 일환으로, 이에 따른 일정액의 수수료를 제공받습니다."
작성한 RecyclerView의 코드
TestAdapter.kt
class TestAdapter: RecyclerView.Adapter<RecyclerView.ViewHolder>() {
private var holderSize =0
// 뷰홀더를 생성함 - 표시할 아이템 갯수만큼 반복하여 호출됨
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
Timber.d("onCreateViewHolder","${holderSize++}")
val binding = TestItemBinding.inflate(LayoutInflater.from(parent.context), parent, false)
// 뷰를 recycle 해서 사용하도록 설정
return ItemViewHolder(binding).apply { setIsRecyclable(true) }
}
// 지정한 레이아웃(자신이 커스텀한 item)과 뷰홀더를 바인딩함 - 반복
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
if(holder is ItemViewHolder){
holder.bind()
}
}
// 표시할 아이템의 갯수를 지정
override fun getItemCount(): Int {
return 50
}
// 리사이클러뷰가 화면에 붙음(제일 처음 호출)
override fun onAttachedToRecyclerView(recyclerView: RecyclerView) {
super.onAttachedToRecyclerView(recyclerView)
Timber.d("onAttachedToRecyclerView")
}
// 뷰홀더를 떼내서 화면에서 보이지 않게함
override fun onViewDetachedFromWindow(holder: RecyclerView.ViewHolder) {
super.onViewDetachedFromWindow(holder)
Timber.d("onViewDetachedFromWindow holder position: ${holder.adapterPosition}")
}
// 뷰홀더를 재활용하여 사용할 때 호출됨
override fun onViewRecycled(holder: RecyclerView.ViewHolder) {
super.onViewRecycled(holder)
Timber.d("onViewRecycled holder position: ${holder.adapterPosition}")
}
// 뷰홀더를 화면에 붙인다 - 반복
override fun onViewAttachedToWindow(holder: RecyclerView.ViewHolder) {
super.onViewAttachedToWindow(holder)
Timber.d("onViewAttachedToWindow holder position: ${holder.adapterPosition}")
Timber.d("-------------------")
}
// 리사이클러뷰를 그리는데 실패함
override fun onFailedToRecycleView(holder: RecyclerView.ViewHolder): Boolean {
Timber.d("onFailedToRecycleView")
return super.onFailedToRecycleView(holder)
}
// 홀더가 화면에 보여지지 않음
override fun onDetachedFromRecyclerView(recyclerView: RecyclerView) {
Timber.d("onDetachedFromRecyclerView")
}
// 커스텀한 아이템(레이아웃)을 바인딩할 클래스 - 반복
inner class ItemViewHolder(var binding: TestItemBinding) : RecyclerView.ViewHolder(binding.root) {
// 여기서 UI를 업데이트 한다
fun bind() {
Timber.d("onBindViewHolder adapter position: $adapterPosition")
binding.id.text="해당 어뎁터는 $adapterPosition 홀더입니다"
}
}
}
RecyclerView 정의 부분
val testAdapter = TestAdapter()
binding.recyclerView.apply {
layoutManager = LinearLayoutManager(context, VERTICAL, false)
adapter = testAdapter
}
출력된 로그 분석
제일 처음 리사이클러뷰가 보여졌을 때
- 처음 화면
- 처음 화면에 보여졌을 때는 0부터 25번 항목까지 보인다
- 처음 부분 로그
- 마지막 부분 로그
처음 보여지는 부분은 Recycle 없이 모든 항목에 대한 뷰홀더를 만들고 거기에 레이아웃을 바인딩 하려 화면에 출력한다
즉, 처음 화면이 보여지는 부분의 리사이클러뷰는 다음과 같이 반복한다
리사이클러뷰 반복(recycled 되기 전)
- onAttachedToRecyclerView - 붙이기
- onCreateViewHolder - 뷰홀더 생성
- onBindViewHolder - 뷰홀더와 레이아웃 바인딩
- onViewAttachedToWindow - 뷰홀더 붙이기
조금 스크롤 했을 때
- 출력 로그
조금 스크롤 했을 때는 다음과 같이 반복한다
리사이클러뷰 반복(스크롤 했을 때 & recyclered 되기 전)
- onViewDetachedFromWindow - 보이지 않게된 뷰홀더를 떼낸다
- onCreateViewHolder - 뷰홀더 생성
- onBindViewHolder - 뷰홀더와 레이아웃 바인딩
- onViewAttachedToWindow - 뷰홀더 붙이기
≫ 아직까지는 recycle을 하지 않는다. ≫ 사라진 뷰홀더를 즉시 재활용(Recycle)하진 않는다
Recycled할 때까지 스크롤
- Recycled 됐을 시점의 화면 사진
- 해당 타이밍의 로그
- 즉, 처음부터 Recycled 되는 것이 아니라 일정부분 뷰홀더가 Detached 되고 나서 Recycled 되는 것을 확인할 수 있다
그렇기 때문에 다음과 같이 반복한다
리사이클러뷰 반복(스크롤 했을 때 & recycled 됐을 때)
- (필요할 때) onCreateViewHolder - 뷰홀더를 생성 (필요할 때만 생성한다)
- onViewDetachedFromWindow - 보이지 않게된 뷰홀더를 떼낸다
- onBindViewHolder - 뷰홀더와 레이아웃 바인딩
- onViewRecycled - 안보이게된 뷰홀더를 재활용
- onViewAttachedToWindow - 재활용한 뷰홀더를 붙이기
RecyclerView에서 메모리 릭이 발생하는 이유
그래서 메모리 릭이 발생하는 이유는 뭘까?
간단하게 말하면 뷰홀더가 보이지 않는다고해서
뷰홀더에 있던 데이터가 즉시 사라지는 것이 아니기 때문이다.
메모리 릭이 발생하는 이유
- 사라진 뷰홀더에 있는 데이터가 즉시 사라지지 않는다
- 위에서 봤다시피 보이지 않게된 뷰홀더가 즉시 사라지는 것은 아니다
- 그렇기 때문에 해당 뷰홀더에 큰 데이터가 남아있었다면 그대로 남아있게 된다
- 이미지 데이터 같은 것들이 가끔 남아서 보이는 이유가 이 이유임
- 그렇기 때문에 onViewRecycled 또는 onViewDetachedFromWindow에서 명시적으로 데이터를 삭제해줘야한다
- 또는 recycled를 하지 않게 한다
- setIsRecyclable(true)
- 또는 recycled를 하지 않게 한다
반응형
'안드로이드(kotlin)' 카테고리의 다른 글
안드로이드13에서 Notification 권한 허가 받기 방법 및 변경점 (0) | 2023.01.14 |
---|---|
registerForActivityResult 사용 방법과 startActivityForResult가 Deprecated된 이유 (2) | 2023.01.07 |
Navigation을 사용한 화면 이동 시 라이프사이클 변화 (0) | 2022.12.24 |
LicenseToolsPlugin을 사용해서 자동으로 라이센스 공개하기 (1) | 2022.12.22 |
안드로이드(Kotlin)를 SOLID로 설계하기 (0) | 2022.12.19 |
"이 포스팅은 쿠팡 파트너스 활동의 일환으로, 이에 따른 일정액의 수수료를 제공받습니다."
댓글