본문 바로가기
안드로이드(kotlin)

리사이클러뷰의 생명주기 분석 및 메모릭의 원인

by 기계공학 주인장 2023. 1. 5.
반응형

 

리사이클러뷰의 라이프 사이클 (화면에 보여지기까지의 순서)

  1. onAttachedToRecyclerView - 리사이클러뷰를 화면에 붙임
  2. onCreateViewHolder - 홀더를 생성
  3. onBindViewHolder - 홀더와 뷰를 바인딩
  4. onViewAttachedToWindow - 홀더가 화면에 온전히 보여짐
  5. onViewDetachedFromWindow - 홀더가 화면에 보여지지 않음
  6. onViewRecycled - 재사용할 홀더 가져오기
  7. 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 되기 전)

  1. onAttachedToRecyclerView - 붙이기
  2. onCreateViewHolder - 뷰홀더 생성
  3. onBindViewHolder - 뷰홀더와 레이아웃 바인딩
  4. onViewAttachedToWindow - 뷰홀더 붙이기

조금 스크롤 했을 때

  • 출력 로그

조금 스크롤 했을 때는 다음과 같이 반복한다

리사이클러뷰 반복(스크롤 했을 때 & recyclered 되기 전)

  1. onViewDetachedFromWindow - 보이지 않게된 뷰홀더를 떼낸다
  2. onCreateViewHolder - 뷰홀더 생성
  3. onBindViewHolder - 뷰홀더와 레이아웃 바인딩
  4. onViewAttachedToWindow - 뷰홀더 붙이기

아직까지는 recycle을 하지 않는다. ≫ 사라진 뷰홀더를 즉시 재활용(Recycle)하진 않는다


Recycled할 때까지 스크롤

  • Recycled 됐을 시점의 화면 사진

  • 해당 타이밍의 로그

  • 즉, 처음부터 Recycled 되는 것이 아니라 일정부분 뷰홀더가 Detached 되고 나서 Recycled 되는 것을 확인할 수 있다

그렇기 때문에 다음과 같이 반복한다

리사이클러뷰 반복(스크롤 했을 때 & recycled 됐을 때)

  1. (필요할 때) onCreateViewHolder - 뷰홀더를 생성 (필요할 때만 생성한다)
  2. onViewDetachedFromWindow - 보이지 않게된 뷰홀더를 떼낸다
  3. onBindViewHolder - 뷰홀더와 레이아웃 바인딩
  4. onViewRecycled - 안보이게된 뷰홀더를 재활용
  5. onViewAttachedToWindow - 재활용한 뷰홀더를 붙이기

RecyclerView에서 메모리 릭이 발생하는 이유

그래서 메모리 릭이 발생하는 이유는 뭘까?

간단하게 말하면 뷰홀더가 보이지 않는다고해서

뷰홀더에 있던 데이터가 즉시 사라지는 것이 아니기 때문이다.

메모리 릭이 발생하는 이유

  • 사라진 뷰홀더에 있는 데이터가 즉시 사라지지 않는다
    • 위에서 봤다시피 보이지 않게된 뷰홀더가 즉시 사라지는 것은 아니다
    • 그렇기 때문에 해당 뷰홀더에 큰 데이터가 남아있었다면 그대로 남아있게 된다
      • 이미지 데이터 같은 것들이 가끔 남아서 보이는 이유가 이 이유임
    • 그렇기 때문에 onViewRecycled 또는 onViewDetachedFromWindow에서 명시적으로 데이터를 삭제해줘야한다
      • 또는 recycled를 하지 않게 한다
        • setIsRecyclable(true)

 

안드로이드 MVVM을 사용하기 위한 필수 요소 AAC란 무엇인가?

기존에 사용하던 MVVM을 좀 더 간편하게 좀 더 정확하게 사용하기 위해 나온 것이 AAC이다. 즉, AAC란 아키텍쳐가 아니라 MVVM을 좀 더 잘 사용하기 위한 도구라고 생각하면 쉽다. 이전에 MVVM이란 무

android-developer.tistory.com

 

안드로이드 MVVM 아키텍처란 무엇인가 필요성과 그 배경

안드로이드 MVVM 아키텍처 MVC vs MVP vs MVVM 비교 MVVM의 탄생 이유 및 필요성 MVVM 구현 방법 MVC : View와 Controller를 Activity, Fragment에서 담당 MVC 패턴의 경우 그림과 같이 View와 Controller가 연결되어 있습

android-developer.tistory.com

 

안드로이드 WorkManager는 왜 필요하고 어디서 쓰면될까?

안드로이드 코틀린 WorkManager는 어디서 사용하고 어떻게 사용하면될까? WorkManager는 왜 필요한가? 다른 백그라운드 처리들과의 차이 WorkManager는 어디에 사용하면될까? WorkManager는 어떻게 사용할 수

android-developer.tistory.com

 

Navigation을 사용한 화면 이동 시 라이프사이클 변화

Jetpack의 Navigation을 사용하여 화면 이동을 했을 때 Activity, Fragment가 정확히 어떤 타이밍에 어떻게 lifecycle이 순환하는지 확인한다 HTML 삽입 미리보기할 수 없는 소스 필요한 종속 항목 선언 https://d

android-developer.tistory.com

 

반응형


"이 포스팅은 쿠팡 파트너스 활동의 일환으로, 이에 따른 일정액의 수수료를 제공받습니다."


댓글