[Android] LifecycleOwner vs viewLifecycleOwner in Fragment

Minji Jeong·2022년 5월 15일
0

Android

목록 보기
16/39
post-thumbnail
안드로이드에선 DB나 서버의 값이 변경되는 것을 실시간으로 감지한 후 UI에 업데이트하기 위해 LiveData를 사용한다. LiveData를 관찰하기 위해선 observe()를 사용하고, observe()에 LifecycleOwner라는 것을 전달한다. 그런데 프래그먼트에서 LiveData를 사용하던 중, 인자로 전달되는 LifecyclerOwner와 viewLifecycleOwner의 차이가 무엇인지 궁금해져서 조사해 본 내용을 간단하게 포스팅으로 남겨본다.

먼저, 프래그먼트에는 2개의 Lifecycle이 존재한다.

LifecycleOwner

LifecycleOwner는 프래그먼트 자체의 생명주기를 가지고 있는 클래스로, 프래그먼트의 전반적인 생명주기(onAttach() ~ onDestroy())와 연결되어 있다.

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
   viewModel.liveData.observe(this, Observer {
   })
}

viewLifecycleOwner

viewLifecycleOwner는 프래그먼트 뷰의 생명주기(onCreateView ~ onDestroyView)를 가지고있는 클래스다. 프래그먼트의 UI가 활성화(onCreateView) 되어있거나 비활성화 (onDestroyView)되어있을 때 연결된다.

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
   viewModel.liveData.observe(viewLifecycleOwner, Observer {
   })
}

기존의 프래그먼트는 1개의 lifecycle만 가지고 있었다. 그러나 프래그먼트는 액티비티와 다르게 onDestroy가 호출되지 않은 상태에서 onCreateView가 여러번 호출될 수 있다.

예를 들어 Memo 프래그먼트와 Calendar 프래그먼트가 있다고 가정해보자. 만약 Memo 프래그먼트에서 하단바의 버튼을 클릭해 Calendar 프래그먼트로 이동했을 때, Memo 프래그먼트에서 onDestroyView()가 호출되어 프래그먼트 '뷰'는 소멸되지만 onDestroy()는 호출되지 않아 프래그먼트 '자체'는 여전히 남아있는 상태가 된다.

class MemoFragment : Fragment() {

    private lateinit var binding : FragmentMemoBinding
  
    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View {
        binding = FragmentMemoBinding.inflate(inflater)
        return binding.root
    }

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)

        val viewModel : ViewModel by inject()

        viewModel.getAllMemo().observe(viewLifecycleOwner, Observer {
        	...
        })
    }

    override fun onDestroyView() {
        super.onDestroyView()
        Log.e(TAG, "onDestroyView()")
    }

    override fun onDestroy() {
        super.onDestroy()
        Log.e(TAG, "onDestroy()")
    }

    companion object{
        const val TAG = "MemoFragment"
    }
}

이렇게되면 Calendar 프래그먼트로 이동했다 하더라도 Memo 프래그먼트에서 사용했던 LiveData는 그대로 남아있게 되고, 이는 곧 메모리 누수를 초래하게 되는 것이다.

✅ 결론

결론적으로 프래그먼트의 생명주기가 Destroy되지 않은 상황에서 LiveData에 새로운 Observer가 등록되어 복수의 Observer가 호출되는 현상이 발생할 수 있었고, 이러한 현상이 당시 문제가 되었다고 한다. 따라서 이 문제를 해결하기 위해 프래그먼트 자체의 생명주기가 아닌 프래그먼트 '뷰'의 생명주기인 viewLifecycleOwner를 사용하게 되었다. 또한 UI 업데이트 용으로 프래그먼트 자체의 생명주기를 사용하기에는 프래그먼트의 생명주기가 길기 때문에, 프래그먼트 내부에서 일반적으로 UI를 업데이트 하는 경우에는 viewLifecycleOwner를 사용하는 것이 권장되고 있다.

References

https://stackoverflow.com/questions/59521691/use-viewlifecycleowner-as-the-lifecycleowner
https://gift123.tistory.com/57
https://wooooooak.github.io/android/2019/08/05/fragment%EC%83%9D%EB%AA%85%EC%A3%BC%EA%B8%B0%EC%99%80%EA%B0%9D%EC%B2%B4%ED%8C%8C%EA%B4%B4%EC%8B%9C%EC%A0%90/

profile
Mobile Software Engineer

0개의 댓글