이전 포스트를 보니 'findViewById의 단점을 해결하기 위해서 데이터바인딩을 한다' 정도까지만 생각했었다. 사실 이 단점을 해결해주는 것은 뷰 바인딩이다.
뷰 바인딩은 말 그대로 xml의 뷰들을 묶어줘 id를 통해 가져오기 쉽게 해준다.
데이터바인딩은 한 단계 더 나아가 데이터 전달을 위해 사용한다.
viewBinding{
enabled = true
}
class MainActivity : AppCompatActivity() {
private lateinit var button: Button
private lateinit var binding: ActivityMainBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// setContentView(R.layout.activity_main)
// button = findViewById(R.id.clickMe)
binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root)
button = binding.clickMe
button.setOnClickListener {//마치 메소드를 구현한 것처럼 보이지만 사실 setOnClickListener안에 함수를 parameter로 넣어준 것을 람다식으로 뺀 것이다.
Toast.makeText(this, "clicked..", Toast.LENGTH_SHORT).show()
Snackbar.make(it, "Snackbar..", Snackbar.LENGTH_SHORT).show()
}
}
}
위 코틀린 코드를 보자. 뷰 바인딩을 implement 해주면
binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root)
laytouinflater을 inflate 함수에 담아주고 바인딩의 root인 xml을 contentView로 설정하여 뷰를 binding.id값 만을 가지고 사용할 수 있다.
평소에는 따로 데이터 바인딩 기능을 사용하지 않았다. 데이터 바인딩은 xml 요소에 쉽게 접근하여 데이터를 변경하기 위하여 사용된다.
일일이 FindViewbyId
를 사용하지 않고 접근할 수 있다는 이점이 있다.
build.gradle(Module)에
plugins {
id 'com.android.application'
id 'kotlin-android'
// 코틀린 익스텐션을 추가
id 'kotlin-android-extensions'
}
...
코틀린 익스텐션을 추가하면 요소 아이디에 alt + enter으로 데이터 바인딩이 알아서 됐기 때문이다.
하지만 extenstions 사용이 예기치 않은 오류를 많이 발생시킨다고 하여 google에서 2021년에 deprecated 되었다고 한다,, 또르르
그래서 그런지 대부분의 프로젝트에서 dataBinding을 따로 명시해두고 있으므로, 데이터바인딩으로 프로젝트를 빌드하는 습관을 길러야겠다.
역시 빌드 그래들 모듈 파일에
이 위치에 dataBinding을 enable 하고
레이아웃 파일을 감싸는 태그를 layout 태그로 바꾸고,
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"
기존에 최상단 태그안에 있는 위 세 줄을 바깥 layout 태그로 옮겨준다.
<?xml version="1.0" encoding="utf-8"?>
<layout 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">
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/name_text"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<TextView
android:id="@+id/greeting_text_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/insert_you_name_here"
android:textSize="30sp"
android:textStyle="bold"
android:typeface="sans"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintHorizontal_bias="0.532"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.175" /> ...
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>
xml 파일명, 요소의 id 에 따라서 위와 같이 바인딩 명이 지정된다.
바인딩을 통해 activity를 수정해주면
class MainActivity : AppCompatActivity() {
private lateinit var binding : ActivityMainBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
//setContentView(R.layout.activity_main)
binding = DataBindingUtil.setContentView(this,R.layout.activity_main)
//val button = findViewById<Button>(R.id.submit_button)
binding.submitButton.setOnClickListener {
displayGreeting()
}
}
private fun displayGreeting() {
// val messageView = findViewById<TextView>(R.id.greeting_text_view)
// val nameText = findViewById<EditText>(R.id.name_edit_text)
binding.greetingTextView.text = "Hello! "+ binding.nameEditText.text
}
}
주석처리 된 부분은 데이터바인딩이 되지 않았을 때 이며 일일히 findViewById로 변수선언을 해주는데 반해 binding을 한번만 선언해주면 바인딩된 레이아웃의 멤버요소로 접근이 수월하다.
private fun displayGreeting() {
binding.apply {
greetingTextView.text = "Hello! "+ nameEditText.text
}
}
binding변수조차 반복적으로 쓰는 것이 일이라면 binding.apply로 감싸주어 binding.
부분을 생략할 수 있다.
데이터 클래스를 만들고
data class Student (
var id:Int,
var name:String,
var email:String
)
main에 아래 함수를 만들어
private fun getStudent():Student{
return Student(1,"Alex","alex@gmail.com")
}
아래와 같이 바인딩하여 xml아이디로 값을 전달하는 것이 익숙하다.
binding = DataBindingUtil.setContentView(this,R.layout.activity_main)
binding.student = getStudent()
val student =getStudent()
binding.nameText.text = student.name
binding.emailText.text = student.email
하지만
xml파일에 Student 클래스를 담는 데이터 태그를 생성하고
<?xml version="1.0" encoding="utf-8"?>
<layout 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">
<data>
<variable
name="student"
type="com.anushka.bindingdemo3.Student" />
</data>
<androidx.constraintlayout.widget.ConstraintLayout
...
<TextView
android:id="@+id/name_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="30sp"
android:text="@{student.name}"
//text에 곧바로 변수를 할당한다.
data에서 받은 오브젝트를 xml에서 곧바로 사용해줄 수도 있다.
이를 위해서는 main에서
binding = DataBindingUtil.setContentView(this,R.layout.activity_main)
binding.student = getStudent()
이름이 student인 Data 태그에 아까 생성한 함수 getStudent()로 Student 오브젝트를 넘겨주면 된다.