본문 바로가기

Android

[Android] View Binding

필자는 예전에 데이터 바인딩과 뷰바인딩을 혼동한 적이 있었다. 그래서 이번 포스팅은 뷰바인딩에 대해 공부하고자 한다.

 View Binding

View Binding은 뷰와 상호작용하는 코드를 쉽게 작성할 수 있도록 만들어 주는 기능이다.

모듈에서 View Binding을 사용하도록 설정하면 모듈에 있는 XML 레이아웃 파일들의 바인딩 클래스가 생성된다. 이 바인딩 클래스의 인스턴스에는 해당 레이아웃에서 ID를 가지고 있는 모든 뷰와 루트 뷰의 직접 참조가 포함되어 있다. 그래서 대부분의 경우 View Binding은 findViewById를 대체할 수 있다.

모듈에서 View Binding 사용 설정

View Binding은 모듈 단위로 사용 설정되며, build.gradle 파일에 View Binding 사용 여부를 명시한다.

// android studio 4.0 이하
android {
    viewBinding {
        enabled = true
    }
}

---------------------------

// android studio 4.0 이상
android { 
    buildFeatures { 
        viewBinding = true 
    }
}

특정 레이아웃 무시

특정 레이아웃의 바인딩 클래스를 생성하지 않으려면 tools:viewBindingIgnore="true" 속성을 루트 뷰에 추가해야 한다.

<LinearLayout
        tools:viewBindingIgnore="true">
</LinearLayout>

바인딩 클래스

모듈에 View Binding 사용하도록 설정되면 XML 레이아웃 파일의 이름을 파스칼 표기법으로 변환하고 끝에 Binding을 추가한 이름을 가진 바인딩 클래스가 생성된다.

<LinearLayout ... >
        <TextView android:id="@+id/name" />
        <ImageView android:cropToPadding="true" />
        <Button android:id="@+id/btn" />
</LinearLayout>

예를 들어 레이아웃 파일 이름이 result_profile.xml인 경우 ResultProfileBinding이라는 바인딩 클래스가 생성되며, 이 클래스에는 name이라는 TextView 필드와 btn이라는 Button 필드가 있다. ImageView는 ID가 없기 때문에 바인딩 클래스에 참조가 존재하지 않는다.

루트뷰 접근

모든 바인딩 클래스에는 해당 레이아웃의 루트 뷰에 관한 직접 참조를 제공하는 getRoot() 메서드가 포함되어 있다. 따라서 레이아웃의 루트 뷰는 ID가 없어도 바인딩 클래스를 통해 직접 접근할 수 있다.

View Binding 사용

Activity에서 View Binding 사용

생성된 바인딩 클래스의 inflate() 메서드를 호출하면 바인딩 클래스의 인스턴스가 생성된다.

인스턴스가 생성되면 getRoot() 메서드를 통해 루트 뷰 참조를 가져오고 이 루트 뷰를 onCreate()에서 setContentView() 메서드에 전달하여 레이아웃을 활성 뷰로 만든다.

private lateinit var binding: ResultProfileBinding

override fun onCreate(savedInstanceState: Bundle) {
    super.onCreate(savedInstanceState)
    binding = ResultProfileBinding.inflate(latoutInflater)
    val view = binding.root
    setContentView(view)
}

이후에는 인스턴스를 사용하여 뷰를 참조한다.

binding.name.text = viewModel.name
binding.btn.setOnClickListener { viewModel.userClicked() }

Fragment에서 View Binding 사용

Activity에서 View Binding을 사용하는 것과 거의 동일하며, 활성 뷰로 만드는 부분에서만 차이가 있다.

Fragment에서는 onCreateView()에서 루트 뷰를 반환하여 레이아웃을 활성 뷰로 만든다.

private var _binding: ResultProfileBinding? = null
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
}

findViewById와의 차이점

Null Safety

  • View Binding은 뷰의 직접 참조를 생성하므로 유효하지 않은 뷰 ID로 인해 Null Pointer 예외가 발생하지 않는다.
  • 레이아웃에 포함된 뷰가 특정 조건에서만 존재하는 경우, 바인딩 클래스는 해당 필드를 @Nullable로 마크하여 참조 실수를 방지할 수 있게 해준다.

Type Safety

  • 각 바인딩 클래스에 있는 필드의 타입이 XML 파일에서 참조하는 뷰의 타입과 일치한다. 즉, 클래스 변환 예외가 발생할 위험이 없다.

예외 탐지

  • View Binding은 Null Safety하고 Type Safety하기 때문에 레이아웃과 코드 사이의 비호환성이 발생하면 findViewById와 달리 런타임이 아닌 컴파일 타임에 예외를 탐지할 수 있다.

Data Binding과의 차이

View Binding과 Data Binding 모두 뷰를 직접 참조하는데 사용할 수 있는 바인딩 클래스를 생성한다. 다만, View Binding은 보다 단순한 경우에 사용한다.

View Binding이 더 나은 점

  • 주석 처리가 필요하지 않기 때문에 컴파일 시간이 더 짧다.
  • XML에 태그를 추가할 필요없고, 사용 설정하면 모든 레이아웃에 View Binding이 자동 적용되기 때문에 편리하다.

View Binding이 더 안좋은 점

  • XML 레이아웃 파일에서 직접 동적 UI 컨텐츠를 선언하는데 사용할 수 없다.
  • 양방향 데이터 바인딩을 지원하지 않는다.

'Android' 카테고리의 다른 글

[Android Jetpack] 앱 속 DB, Room  (0) 2023.11.16
[Android] AAC (Android Architecture Components)  (0) 2023.08.30
[Android] DataBinding  (0) 2023.08.30
[Android] Multi-ViewType RecyclerView  (1) 2023.08.09
[Android] RecyclerView  (1) 2023.08.03