안드로이드 프로젝트를 처음 생성해서 뷰에 데이터를 표현할 때 가장 많이 쓰는 함수는 "View.findViewById(id: Int)" 일 것입니다. 하지만 뷰에 쓰는 컴포넌트가 많아질 수록 반복해서 호출해야하고, 코드가 길어지는 문제를 야기합니다. 우리는 바인딩을 통해 이러한 문제를 해결해보려 합니다.
코틀린에선 findViewById를 쓰지않고 컴포넌트의 id를 통해 바로 접근할 수 있었지만 androidStudio 4.1에서 kotlin-android-extensions 플러그인이 다양한 문제로 인해 기본적으로 제공되지 않으면서 id를 통해 접근할 수 없게되었다.
바인딩에는 2가지 방법이 있습니다. 간단하게 뷰를 가져오기만 하는 뷰 바인딩, 바인딩 오브젝트를 통한 양방향 접근이 가능한 데이터바인딩이 있습니다. 그 중 살펴볼 내용은 뷰 바인딩입니다.
뷰 바인딩은 findViewById를 대체할 수 있는 방법 중 하나로 바인딩 클래스를 통해 레이아웃 Id로 모든 뷰의 직접참조가 가능합니다.
android {
...
viewBinding {
enabled = true
}
}
// Android Studio 4.0
android {
buildFeatures {
viewBinding = true
}
}
안드로이드 스튜디오 4.0부터는 viewBinding의 위치가 buildFeatures로 이동되서 아래와 같이 사용하면 됩니다.
만약 바인딩 클래스를 생성하는 동안 특정 컴포넌트는 바인딩에서 제외하고 싶다면 tools:viewBindingIgnore="true"를 넣어줍니다.
<LinearLayout
...
tools:viewBindingIgnore="true" >
...
</LinearLayout>
모듈에 뷰 바인딩을 사용하도록 설정하면 모듈의 각 XML에 대해 바인딩클래스가 생기게 됩니다. 바인딩 클래스의 이름은 XML 이름을 카멜 케이스로 변환한 뒤 'Binding'를 추가적으로 붙여주게됩니다.
Activity에서 바인딩 클래스 인스턴스를 설정하려면 onCreate()에서 다음과 같은 절차를 따라야 합니다.
- 생성된 바인딩 클래스에 포함된 정적 inflate() 메서드를 호출합니다. 그러면 활동에서 사용할 바인딩 클래스 인스턴스가 생성됩니다.
- getRoot() 메서드를 호출하거나 Kotlin 속성 구문을 사용하여 루트 뷰 참조를 가져옵니다.
- 루트 뷰를 setContentView()에 전달하여 화면상의 활성 뷰로 만듭니다.
//lateinit으로 스코프를 열어줌
private lateinit var binding: ResultProfileBinding
override fun onCreate(savedInstanceState: Bundle) {
super.onCreate(savedInstanceState)
binding = ResultProfileBinding.inflate(layoutInflater)
val view = binding.root
setContentView(view)
}
Fragment에서 호출시 1, 2단계는 같지만 3단계에선 setContentView()에 루트뷰를 전달 하는 것이 아닌 onCreateView()에서 루트뷰를 반환해주는 차이를 보입니다.
private var binding: ResultProfileBinding? = null
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를 썼던 것 처럼 id를 통해 호출하면 됩니다.
binding.name.text = viewModel.name
binding.button.setOnClickListener { viewModel.userClicked() }