본문 바로가기
개발/Android

[Android] Fragment에서 View Binding 사용 시 주의사항

by tempus 2022. 1. 3.
반응형

안드로이드 공식 문서에서 Fragment의 View Binding 사용에 대하여 다음과 같이 샘플 코드를 제공하고 있습니다.

    private var _binding: ResultProfileBinding? = null
    // This property is only valid between onCreateView and
    // onDestroyView.
    private val binding get() = _binding!!

    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        _binding = ResultProfileBinding.inflate(inflater, container, false)
        val view = binding.root
        return view
    }

    override fun onDestroyView() {
        super.onDestroyView()
        _binding = null
    }
    

위의 코드에서 보듯이 binding에 대하여 onDestroyView에서 null로 만들어 줍니다. 왜 그럴까요?

 

➡ 흔히 Fragment에서는 재사용을 위해 View들을 메모리에 보관하도록 합니다. 그래서 onDestroy호출이 되어도 내부적으로 View들을 보관하고 있습니다.

그리고 Fragment의 생명주기는 Fragment View의 생명주기 보다 길기 때문에 View Binding에 대한 참조를 null로 만들어서 GC가 수집해가지 않으면 메모리 누수 발생할 수 있습니다.

 

하지만 매번 binding을 null로 만드는 것은 귀찮기 때문에 보통 다음과 같은 방법을 사용하여 해결합니다.

 

1. View Binding을 사용하지 않고 findViewById를 사용하기

private lateinit var title: TextView 

fun onViewCreated (view: View, savedInstanceState: Bundle) { 
    title = view.findViewById(R.id.title)
}

하지만 이 방법은 Type Safe하지 않고 성능적으로 좋지 않기 때문에 저는 주로 아래의 방법을 사용합니다.

 

2. BaseFragment를 만들어서 사용하기

typealias Inflate<T> = (LayoutInflater, ViewGroup?, Boolean) -> T

abstract class BaseFragment<VB: ViewBinding>(
    private val inflate: Inflate<VB>
) : Fragment() {

    private var _binding: VB? = null
    val binding get() = _binding!!

    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        _binding = inflate.invoke(inflater, container, false)
        return binding.root
    }

    override fun onDestroyView() {
        super.onDestroyView()
        _binding = null
    }
}
class MainFragment : BaseFragment<FragmentMainBinding>(FragmentMainBinding::inflate), FullImageContract.View {

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        binding.title.text = "title"
    }

}

일단은 반복적인 코드를 줄일 수 있고 구글에서 제시하는 샘플 코드와 같기 때문에 제일 좋지 않을까라고 생각합니다.

 

이외에도 다른 방법들이 있지만 가장 접근하기 쉬운 2가지 방법에 대해서만 말해보았습니다.

반응형

댓글


loading