티스토리 뷰

728x90



이번 포스팅에서는 Fragment 에서 View Binding 사용법에 대해서 자세히 알아보자.

참고로, 지난 포스팅에서는 View Binding 의 개요, View 접근을 위한 다른 방식들과 비교, 사용법에 대해 알아 보았다.

[Android] - 안드로이드 뷰 바인딩 (2)

[Android] - 안드로이드 뷰 바인딩 (1)



Fragment Lifecycle

Fragment 는 하단과 같이 Fragment 의 고유한 LifeCycle 과 View 와 관련한 LifeCycle 이 존재한다.

 

◼ Fragment LifeCycle : onAttach() ~ onDetach()

화면에 보이지 않는 상태에서 호출

◼ Fragment View LifeCycle : onCreateView() ~ onDestroyView()

화면을 구성할 때 호출

 

 

Memory leak

Memory leak 이란 더 이상 사용하지 않는 객체가 GC 에 의해 회수되지 않고 계속 축적되는 현상이다.

(상세설명은 구글링......)

 

Fragment Lifecycle 에서 본 것 처럼 Fragment 의 LifeCycle 은 View 의 LifeCycle 보다 오래 유지된다.

Fragment 의 onCreateView() 에서 viewBinding 을 한 후 다른 frament 로 교체하게 된다면 viewBinding 은 이미 참조하고 있는 것이 있기 때문에 memory leak 이 발생하게 된다.

 

하단은 안드로이드 공식 문서에서 가이드 하고 있는 Frament 에서 ViewBinding 사용법이다.

 

즉, Fragment 에서 ViewBinding 사용 시 memory leak 의 위험이 있으니 onDestoryView() 에서

binding 변수를 null 로 해줘야 한다.



Solution

Fragment 에서 ViewBinding 시 memory leak 때문에 onDestory() 에서 binding 개체를 null 로 만들어야 한다.

하지만, 매번 binding 개체를 null 로 만들어야 하는 반복적인 작업이 귀찮다면 하단의 대안도 있다.

 

◼ onViewCreated() 에서 ViewBinding 참조 끝내기

ViewBinding 을 멤버로 만들지 않고 onViewCreated() or onCreateView() 에서 참조를 모두 끝내는 방식이다.

 

class MainFragment : Fragment(R.layout.fragment_main) {
override fun onViewCreated(a_view: View, a_savedInstanceState: Bundle?) {
super.onViewCreated(a_view, a_savedInstanceState)
val viewBinding = FragmentMainBinding.bind(a_view)
viewBinding.tvTitle.text = "Parkho"
}
}
view raw MainFragment.kt hosted with ❤ by GitHub

 

◼ BaseFragment 상속해서 사용하기

BaseFragment 를 만들어 반복되는 코드를 따로 모아 놓은 방식이다.

 

typealias Inflate<T> = (LayoutInflater, ViewGroup?, Boolean) -> T
abstract class BaseFragment<a_viewBinding : ViewBinding>(private val inflate: Inflate<a_viewBinding>) :
Fragment() {
private var _viewBinding: a_viewBinding? = null
val viewBinding get() = _viewBinding!!
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
_viewBinding = inflate.invoke(inflater, container, false)
return viewBinding.root
}
override fun onDestroyView() {
super.onDestroyView()
_viewBinding = null
}
}
view raw BaseFragment.kt hosted with ❤ by GitHub
class MainFragment : BaseFragment<FragmentMainBinding>(FragmentMainBinding::inflate) {
override fun onViewCreated(a_view: View, a_savedInstanceState: Bundle?) {
super.onViewCreated(a_view, a_savedInstanceState)
viewBinding.viewBinding.tvTitle.text = "Parkho"
}
}
view raw MainFragment.kt hosted with ❤ by GitHub

 

◼ Kotlin Delegated properties 사용하기

안드로이드 공식문서에서는 binding null 처리를 했지만, 구글 아키텍쳐 샘플 소스 코드에서는 AutoCleardValue 를 만들어 위임 패턴으로 사용한다.

구글 샘플 코드에 있는 AutoCleardValue를 사용하는 방식이다.

 

class AutoClearedValue<T : Any>(val fragment: Fragment) : ReadWriteProperty<Fragment, T> {
private var _value: T? = null
init {
fragment.lifecycle.addObserver(object: DefaultLifecycleObserver {
override fun onCreate(owner: LifecycleOwner) {
fragment.viewLifecycleOwnerLiveData.observe(fragment) { viewLifecycleOwner ->
viewLifecycleOwner?.lifecycle?.addObserver(object: DefaultLifecycleObserver {
override fun onDestroy(owner: LifecycleOwner) {
_value = null
}
})
}
}
})
}
override fun getValue(thisRef: Fragment, property: KProperty<*>): T {
return _value ?: throw IllegalStateException(
"should never call auto-cleared-value get when it might not be available"
)
}
override fun setValue(thisRef: Fragment, property: KProperty<*>, value: T) {
_value = value
}
}
/**
* Creates an [AutoClearedValue] associated with this fragment.
*/
fun <T : Any> Fragment.autoCleared() = AutoClearedValue<T>(this)
class MainFragment : Fragment() {
private var viewBinding by autoCleared<FragmentMainBinding>()
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
viewBinding = FragmentMainBinding.inflate(inflater, container, false)
return viewBinding.root
}
override fun onViewCreated(a_view: View, a_savedInstanceState: Bundle?) {
super.onViewCreated(a_view, a_savedInstanceState)
viewBinding.viewBinding.tvTitle.text = "Parkho"
}
}
view raw MainFragment.kt hosted with ❤ by GitHub

 

- dependecy 도 추가해야 한다.

dependencies {
implementation "androidx.lifecycle:lifecycle-runtime:2.2.0"
implementation "androidx.lifecycle:lifecycle-common-java8:2.2.0"
// 필요에 따라......
implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:2.2.0"
implementation "androidx.lifecycle:lifecycle-livedata-ktx:2.2.0"
}
view raw build.gradle hosted with ❤ by GitHub

 

◼ 라이브러리 사용하기

각 개발자들이 ViewBinding 을 편하게 사용하기 위해 만들어 놓은 library 를 사용하는 방식이다.

 

- ViewBindingPropertyDelegate

- Binding



728x90
댓글