뷰 바인딩에 대한 공식문서
뷰 바인딩은 쉽게말해서 코드 파일에서 XML에 정의된 뷰들을 바로 참조할 수 있는 기능이다.
- 뷰 바인딩은 findViewById를 대체할 수 있다. 따라서 모든 뷰에 대해 findViewById를 일일이 호출할 필요가 없다. 또한 findViewById에서는 잘못된 id를 매개변수로 전달할 경우, null 위험성이 존재한다.
- 구글에서 Kotlin Extension을 Deprecated했다. 뷰 바인딩은 이를 대체할 수 있다.
Kotlin Extension은 내가 작년(2020)까지도 사용했던 기술이다. 왜 Deprecated 되었을까?
- Kotlin Extension은 Kotlin 언어에만 사용가능하다. 즉, Java언어로 된 안드로이드 프로젝트에서는 사용이 불가능하다.
- Kotlin Extension에서, 만일 같은 이름의 View가 있을 경우 코드에서 어떤 뷰를 호출할 지 애매모호 해진다.
등의 문제가 있다.
뷰 바인딩은 위 Kotlin Extension의 문제들을 해결할 수 있을 뿐만 아니라
findViewById의 문제점인 null 위험성, 유형 위험성(형 변환이 잘못되는 문제)가 없다.
뷰 바인딩 모듈을 사용할 경우 XML 레이아웃 파일의 바인딩 클래스를 자동 생성해주며, 바인딩 클래스의 인스턴스에서 XML 레이아웃 파일의 뷰에 직접 참조가 가능해진다.
우선 Module 수준의 build.gradle에 viewBinding을 enabled로 만들어주고 Sync Now를 해준다.
이제 코드로 어떻게 구현하는지 살펴보자.
뷰 바인딩은 액티비티, 프래그먼트에서 자주 쓰게되는데, 각각 메모리에 인플레이션 하는 방법이 다르다.
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/container"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</androidx.constraintlayout.widget.ConstraintLayout>
메인 액티비티 XML 파일이다.
프래그먼트를 담기위한 container라는 ID의 제약레이아웃이 있다.
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
<Button
android:id="@+id/button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Click Here"
app:layout_constraintVertical_chainStyle="packed"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toTopOf="@+id/text_view"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" />
<TextView
android:id="@+id/text_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="@color/purple_500"
android:textSize="21sp"
android:textStyle="bold"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/button" />
</androidx.constraintlayout.widget.ConstraintLayout>
프래그먼트 XML 파일이다.
버튼과 텍스트뷰 뷰가 존재한다.
package com.khs.viewbindingdatabindingexample
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import com.khs.viewbindingdatabindingexample.databinding.ActivityMainBinding
class MainActivity : AppCompatActivity() {
lateinit var binding: ActivityMainBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root)
setFragment()
}
private fun setFragment() {
supportFragmentManager.beginTransaction().replace(binding.container.id, MainFragment()).commit()
}
}
메인 액티비티에서 뷰 바인딩 클래스를 인스턴스화 하는 방법이다.
원래는 setContentView() 메서드 안에 매개변수로 레이아웃 파일을 줬었다.
뷰 바인딩을 사용할 때는 뷰 바인딩 객체의 루트뷰를 매개변수로 넘겨준다.
뷰 바인딩 객체의 루트뷰란, 트리의 루트 노드같은, 모든 뷰에 접근 가능한 뷰이다.
그리고 setFragment() 메서드로, container ID의 제약 레이아웃에 MainFragment라는
프래그먼트를 화면에 띄운다.
이 때, container라는 ID의 뷰에 접근할 때 위에서만들어준 binding이라는 뷰 바인딩 객체로
바로 접근할 수가 있는것을 확인할 수 있다.
뷰 바인딩은 바인딩 객체를 만들어서 해당 바인딩 객체로 뷰에 접근한 다는 것을 알 수있다.
package com.khs.viewbindingdatabindingexample
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.Toast
import androidx.fragment.app.Fragment
import com.khs.viewbindingdatabindingexample.databinding.FragmentMainBinding
class MainFragment: Fragment() {
lateinit var binding: FragmentMainBinding
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
binding = FragmentMainBinding.inflate(inflater, container, false)
setUpView()
return binding.root
}
private fun setUpView() {
binding.textView.text = "ViewBindingExample"
binding.button.setOnClickListener {
Toast.makeText(requireContext(), "버튼 클릭", Toast.LENGTH_SHORT).show()
}
}
}
다음은 메인프래그먼트의 코드 파일이다.
onCreateView를 오버라이딩하는데 원래는 super.onCreateView(inflater, container, false)와 같은 형태로 return했다.
뷰 바인딩을 사용하게 되면, binding 객체를 위와같은 형태(생성된 클래스이름.inflate 메서드 호출)로 초기화해주고,
binding 객체의 루트뷰를 return하면 된다.
setUpView() 메서드가 binding.root가 return될 때보다 먼저 호출이 됐지만 이미 바인딩 객체가 인플레이션됐기 때문에
뷰들은 전부 메모리에 올라와 있는 상태다. 따라서 뷰들에 접근할 수 있게된다.
위와같은 형태로 만들면 액티비티, 프래그먼트에서 뷰 바인딩을 쓸 수 있게 된다.
간략하게 뷰 바인딩에 대해서 알아보았다.
뷰 바인딩만 사용해서는 개발에서 큰 의미는 없고, 데이터 바인딩을 사용한다면 XML 레이아웃 파일을 유연하게 사용할 수 있게된다.
또한 데이터 바인딩에 ViewModel을 추가해서 사용한다면 좋은 코드가 될 것이다.
다음 번에는 데이터 바인딩에 대해서 정리해야겠다.
'안드로이드 > 개발 관련' 카테고리의 다른 글
[Kotlin] 안드로이드 리사이클러뷰 안에 리사이클러뷰 사용해보기, 이중 리사이클러뷰 (Feat. 뷰 바인딩, 데이터 바인딩) (0) | 2021.10.13 |
---|---|
[Kotlin] 안드로이드 데이터 바인딩, 데이터 결합, Data Binding (0) | 2021.10.12 |
[Android] 정리해야 할 개발기술 목록 - 계속 업데이트중 (0) | 2021.08.11 |
[Android][Java] 프래그먼트 뒤로가기 누르면 원상복구 + 프래그먼트 데이터 전달 (0) | 2021.08.01 |
[Android] startActivityForResult Deprecated된 이유와 해결책 (0) | 2021.07.28 |