오늘은 2019년 Google I/O에서 소개된 View Binding에 대해 알아보겠습니다.
현재까지 안드로이드에서 뷰에 접근할 수 있는 다양한 방법이 제공되었습니다.
위의 표에서 안드로이드 팀은 해당 방법들을 다음과 같은 세세 가지의 기준을 정해 비교했습니다.
findViewById의 문제점
val textView = findViewById<TextView>(R.id.txtView)
Butter Knife의 문제점
@BindView(R.id.btnNext) val nextButton : Button
Kotlin Synthtic의 문제점
btnSend.setOnClickListener { startActivity(Intent(this, SecondActivity::class.java)) }
아쉽게도 세 가지의 기준을 모두 만족하는 바인딩 방법은 존재하지 않았습니다.
But Why Not?
세 가지 기준을 모두 만족할 수 있는 바인딩 방법은 없을까?
현재 가장 많이 사용되는 Data Binding의 목적은 View와 Model을 엮어주는 역할인데 많은 개발자들이 단순히 View에 대한 참조를 얻기 위한 목적으로 Data Binding을 사용하는 것을 보고, 이러한 맥락에서 구글에서 View에 대한 참조를 얻기 위한 목적으로 오늘의 View Binding이 탄생하게 되었습니다.
View Binding의 특징
// Android Studio 4.0
android {
buildFeatures {
viewBinding = true
}
}
안드로이드 스튜디오 4.0 부터는 param의 위치가 buildFeatures로 이동되어 위와 같이 선언합니다.
class MainActivity : AppCompatActivity() {
private lateinit var binding: ActivityMainBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root)
binding.txtSample.text = "View Binding Sample"
}
}
사용방법은 Data Binding과 유사해보이지만, Data Binding과 달리 xml파일에 전체를 감싸는 layout태그를 선언해주지 않아도 최상단의 부모를 root라는 property로 제공합니다.
그래서 액티비티의 setContentView에 binding 객체의 root를 넘겨주고 뷰에 접근 할 수 있습니다.
class DetailFragment : Fragment() {
private var _binding: FragmentDetailBinding? = null
// This property is only valid between onCeateView and
// onDestroyView.
private val binding get() = _binding!!
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
_binding = FragmentDetailBinding.inflate(inflater, container, false)
return binding.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
binding.textView.text = "View Binding in Fragment"
}
override fun onDestroyView() {
super.onDestroyView()
_binding = null
}
}
프래그먼트에서 사용법은 위와 같습니다. 프래그먼트의 생명주기에서 자신의 UI를 그리기 시작하는 부분인 onCreateView에서 바인딩을 시켜주고 binding 객체의 root를 리턴해 넘겨줍니다.
프래그먼트에서는 Nullable 처리를 위해 추가적인 코드가 필요합니다. 프래그먼트는 뷰 보다 오래 지속되기 때문에 onDestroyView()에서 binding class 인스턴스 null 값으로 변경하여 참조를 정리해주어야 합니다.
Result APK size // DataBinding, ViewBinding
Databinding = 2670 kb
ViewBinding = 2620 kb
References