Fragment와 ViewBinding

홍승범·2023년 1월 26일
0

Android

목록 보기
6/9

ViewBinding

모듈에 있는 각 xml 레이아웃 파일에 대한 결합클래스를 생성. 바인딩 클래스의 인스턴스에는 상응하는 레이아웃에 ID가 부여된 모든 뷰에 대한 직접 참조가 포함됨.

아래와 같이 app의 build.gradle 파일에 선언해주면 사용할 수 있음

android {
        ...
        viewBinding {
            enabled = true
        }
    }

생성된 결합 클래스에는 xml에서 id 가 부여된 뷰에 대해서만 참조가 생성되며 없는 뷰는 생성되지 않는다. 또한 상응하는 레이아웃 파일의 루트뷰에 대한 직접 참조를 제공하는 getRoot 메서드가 포함됨.

특징은 다음과 같다

  • findViewById와의 차이점

    1. Null 안전 : 뷰의 참조를 직접 생성해주므로 유효하지 않은 뷰ID로 인해 null pointer 예외가 발생할 위험이 없다. 또한 레이아웃의 일부 구성에만 뷰가 있는 경우, 결합클래스에서 참조를 포함하는 필드가 @Nullable로 표시됨
    2. 유형 안전 : 각 바인딩 클래스의 필드 유형이 xml 파일에서 참조하는 뷰와 일치하므로, 클래스 변환 예외가 발생할 위험이 없음
  • DataBinding과의 비교
    1. ViewBinding은 보다 단순한 사례를 처리하기 위한것

    1. 더 빠른 컴파일 : 뷰 결합에는 주석처리가 필요하지 않으므로 컴파일시간이 더 짧음
    2. 사용 편의성 : xml에 바인딩을 위한 틀별한 태그가 필요하지 않고, 모든 레이아웃에 바인딩이 자동 적용됨
    3. 레이아웃변수 및 레이아웃 표현식을 지원하지 않으므로 xml 레이아웃파일에서 직접 동적 UI 콘텐츠를 선언하는데 사용할 수 없음
    4. 양방향 데이터 결합을 지원하지 않음.

ViewBinding in Fragment

안드로이드 공식문서에는 Fragment에서의 ViewBinding사용법을 아래와 같은 샘플코드로 제시한다

 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
 }

프래그먼트의 라이프사이클 에서도 설명했지만, Fragment는 Fragment라이프사이클과 view의 라이프사이클이 다르다.

정확히는 view의 라이프사이클리 서브셋이 되어 뷰보다 Fragment의 인스턴스가 더 오래 지속되기 때문에 적절한 시점(보통 onDestroyView)에서 참조를 처리하지 않으면 메모리 누수가 발생할 가능성이 있다.

그렇기에 구글은 참조를 nullify하는 코드를 onDestroyView에 작성하고 있다.

이렇게 변수를 두개 생성하고 매번 null을 해주는 코드를 작성하기는 귀찮으므로, 다음과 같은 해결 방법들이 있다.

  1. viewBinding 말고 findViewById 사용하기
    • TypeSafe 하지 않은 문제가 매우 크고, 코드 작성도 번거롭다.
  2. onCreateView 또는 onViewCreated에서 바인딩 참조를 모두 처리하고 끝내기
    • 특히 이미 view가 확장되어있다면 binding클래스의 bind() 함수를 통해 참조를 가져올 수 있음
    • 단 이 bind가 여러번 불리지 않도록 조심해야 함.
  3. BaseActivity, BaseFragment등 스켈레톤 클래스를 만들어 반복되는 코드를 줄일 수 있음
  4. property delegation을 통한 자동 처리
    • AutoClearedValue 구글에서 제안한 아키텍쳐 샘플 코드로서 프로퍼티 위임을 사용하며 초기화시 fragment의 viewLifeCycleOwner에 옵저버를 달아, destory시에 자동으로 프로퍼티를 null시켜 주는 동작을한다. 사용시에는 아래 코드와 같이 사용한다
    • 문제는 Fragment의 코드를 줄이기 위해 더 많은 코드가 생산되어야 한다는 것 정도?
private var binding by autoCleared<FragmentVideoItemBinding>()
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

    }

    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View {
        binding = FragmentVideoItemBinding.inflate(LayoutInflater.from(requireContext()), container, false)
        return binding.root
    }
  1. 마지막은 다른 개발자들이 만들어놓은 여러 라이브러리를 사용하는것.

결론

어떤 방법을 사용하든 어쨌든 Fragment의 생명주기는 유심히 살펴보아야 한다!


https://developer.android.com/topic/libraries/view-binding?hl=ko
https://yoon-dailylife.tistory.com/57w

profile
그냥 사람

0개의 댓글