- Android 데이터 바인딩 라이브러리를 사용하면 xml 레이아웃 파일에 대한 바인딩 클래스를 생성 할 수 있습니다.
- 이러한 바인딩 클래스를 사용하여 findViewById ()를 호출하지 않고도 뷰 컴포넌트를 효율적으로 사용할 수 있습니다.
- 또한 레이아웃 변수와 레이아웃 표현식을 사용하여 레이아웃에 값을 설정하고 레이아웃에서 값을 자동으로 가져올 수 있습니다.
데이터 바인딩이 필요한 이유
Android 개발에서는 findViewById () 함수를 사용하여 뷰에 대한 참조를 얻습니다.
그러나 그렇게 할 때마다 Android 시스템은 뷰 계층 구조를 거쳐 런타임에 찾아야합니다.
또한 더 큰 Android 애플리케이션에는 많은 레이아웃과 수백 개의 뷰가있을 수 있습니다.
따라서 시스템은 뷰 계층 구조를 몇 번이고 반복해야합니다.
이는 매우 비효율적이고 자원을 소비하는 프로세스입니다.
그래서 구글은 그 문제에 대한 해결책으로 안드로이드 데이터 바인딩 라이브러리를 도입했습니다.
It generates a corresponding binding class for each xml layout.
그런 다음 해당 바인딩 클래스의 인스턴스 (객체)를 사용하여 뷰 구성 요소에 값을 설정하고 값을 가져올 수 있습니다.
findViewById ()를 제거하는 것이 데이터 바인딩의 유일한 이점은 아닙니다. 이전 접근 방식에 비해 데이터 바인딩에는 많은 장점이 있습니다.
데이터 바인딩의 장점.
- findViewById () 제거
- 값을 자동으로 업데이트합니다 (값을 업데이트 할 수있는 모든 방법을 추적 할 필요는 없음).
- UI 테스트에 매우 효과적입니다.
- 더 읽기 쉬운 코드.
- 더 관리하기 쉬운 코드.
- 더 빠른 개발 시간.
- 더 빠른 실행 시간.
- 컴파일 시간 동안 오류가 발견 될 수 있습니다.
- MVVM 및 MVI 아키텍처에 적합합니다.
Kotlin Android 확장 프로그램은 이제 지원 중단됨
Kotlin Android 확장 프로그램은 Gradle 버전 6.2 및 Android 스튜디오 버전 4.0.1부터 지원이 중단되었습니다. 따라서 데이터 바인딩과 뷰 바인딩을 배우는 것이 필수적입니다.
간단한 데이터 바인딩 예제.
가능한 가장 간단한 데이터 바인딩 예제부터 시작하겠습니다.
Android 앱에서 데이터 바인딩을 사용하려면 3 가지 작업을 수행해야합니다.
- 앱 수준 build.gradle 파일에서 데이터 바인딩 활성화
- <layout> 태그를 xml 파일의 가장 바깥 쪽 태그로 추가합니다.
- 데이터 바인딩 개체를 생성합니다.
1 단계
앱 수준 build.gradle 파일을 엽니다. 그리고 이 코드 부분을 Android 블록 안에 추가하여 데이터 바인딩을 활성화합니다.
buildFeatures { dataBinding = true }
어떤 경우에는 kotlin kapt 플러그인을 사용하는 것이 유용합니다. 그래서 그것을 gradle의 플러그인 블록에 추가합시다.
id 'kotlin-kapt'
다음은 완전한 build.gradle 파일입니다.
plugins {
id 'com.android.application'
id 'kotlin-android'
id 'kotlin-kapt'
}
android {
compileSdkVersion 30
buildToolsVersion "30.0.2"
defaultConfig {
applicationId "com.anushka.bindingdemo1"
minSdkVersion 26
targetSdkVersion 30
versionCode 1
versionName "1.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
kotlinOptions {
jvmTarget = '1.8'
}
buildFeatures {
dataBinding = true
}
}
dependencies {
implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
implementation 'androidx.core:core-ktx:1.3.2'
implementation 'androidx.appcompat:appcompat:1.2.0'
implementation 'com.google.android.material:material:1.2.1'
implementation 'androidx.constraintlayout:constraintlayout:2.0.4'
testImplementation 'junit:junit:4.+'
androidTestImplementation 'androidx.test.ext:junit:1.1.2'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0'
}
2 단계
activity_main.xml 파일을 열고 <layout> 태그를 레이아웃 파일 의 가장 바깥 쪽 태그 로 추가 합니다. 데이터 바인딩 라이브러리에이 xml 레이아웃 파일에 대한 바인딩 개체를 생성하도록 지시합니다.
여기 내 완전한 activity_main.xml 파일이 있습니다. 또한 EditText, TextView 및 Button을 추가했습니다.
<?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: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" />
<EditText
android:id="@+id/name_edit_text"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_margin="20dp"
android:ems="10"
android:hint="Insert you name here"
android:inputType="textPersonName"
android:textSize="30sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/greeting_text_view"
app:layout_constraintVertical_bias="0.126" />
<Button
android:id="@+id/submit_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Submit"
android:textSize="30sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.498"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.613" />
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>
생성 된 데이터 바인딩 클래스의 이름
- 레이아웃 태그로 래핑 한 레이아웃의 이름은 activity_main 입니다.
- 이를 사용하여 Android 데이터 바인딩 라이브러리는 ActivityMainBinding 이라는 이름의 바인딩 클래스를 만듭니다 .
- 데이터 바인딩 라이브러리는 xml 레이아웃의 이름을 사용하고 각 이름의 첫 글자를 대문자로 만들고 밑줄을 제거하고 끝에 "Binding"을 추가합니다.
3 단계
우선 프로젝트를 다시 빌드 하십시오. 레이아웃에 대한 데이터 바인딩 관련 클래스를 생성하려면 Android 스튜디오를 다시 빌드해야합니다.
다음으로 MainActivity로 돌아가서 새로 생성 된 ActivityMainBinding의 개체를 만듭니다.
MainActivity.kt를 엽니다.
클래스 맨 위에 개체 참조 변수를 선언합니다.
private lateinit var binding : ActivityMainBinding
Then inside the onCreate funciton, construct the data binding instance replacing the default setContentView(R.layout.activity_main) function call.
binding = DataBindingUtil.setContentView(this, R.layout.activity_main)
이제이 클래스에서 데이터 바인딩을 사용할 준비가되었습니다.
이제 EditText에 삽입 된 이름을 읽는 간단한 코드를 작성해 보겠습니다. 그런 다음 데이터 바인딩을 사용하여 TextView에 해당 이름의 인사말 메시지를 표시합니다
binding.submitButton.setOnClickListener { displayGreeting() }
class MainActivity : AppCompatActivity() {
private lateinit var binding: ActivityMainBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = DataBindingUtil.setContentView(this, R.layout.activity_main)
binding.submitButton.setOnClickListener {
displayGreeting()
}
}
private fun displayGreeting() {
binding.apply {
greetingTextView.text = "Hello! " + nameEditText.text
}
}
}
No more findViewById()
데이터 바인딩을 사용하고 있으므로 id를 사용하여 뷰를 찾을 필요가 없습니다.
이것이 데이터 바인딩을 사용하지 않았다면 위의 코드가 어떻게 보였을까요?
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val button = findViewById(R.id.submit_button)
button.setOnClickListener {
displayGreeting()
}
}
private fun displayGreeting() {
val messageView = findViewById<TextView>(R.id.greeting_text_view)
val nameText = findViewById<EditText>(R.id.name_edit_text)
val message = "Hello! "+ nameText.text
messageView.text = message
}
}
데이터 바인딩은 실제로 어떻게 작동합니까?
- <layout> </ layout> 태그로 표시 한 각 xml 레이아웃 파일에 대해 데이터 바인딩 라이브러리는 바인딩 클래스를 생성합니다.
- 이 바인딩 클래스를 사용하면 레이아웃의 각 속성에서 값을 설정하고 가져올 수 있습니다.
레이아웃 변수 및 레이아웃 표현식.
데이터 바인딩의 주요 이점 중 하나는 뷰의 값을 자동으로 업데이트 할 수 있다는 것입니다.
즉, 값을 업데이트 할 수있는 모든 방법을 추적 할 필요가 없습니다.
예를 들어 앱에서 이름과 연락처 이메일 주소가있는 "Company"의 인스턴스를 얻는다고 가정 해 보겠습니다.
데이터 바인딩을 사용하지 않는 경우에는 액티비티 클래스 (또는 프래그먼트 클래스)에서 해당 인스턴스를 가져 오는 코드를 작성한 다음 거기에있는 각 뷰 구성 요소 (TextView,…)에 하나씩 설정된 값에 코드를 작성해야합니다.
그러나 그렇게하는 대신 "Company"인스턴스를 레이아웃에 전달할 수 있습니다. 또한 데이터 바인딩 라이브러리를 지원하는 레이아웃 변수 및 레이아웃 표현식을 사용하여 각 뷰 구성 요소에 값을 자동으로 설정하고 값을 가져 오는 코드를 작성합니다.
코드 예제를 통해 더 자세히 설명하겠습니다.
4 단계
이제 프로젝트에 새 데이터 클래스를 추가하겠습니다. 새 데이터 클래스를 만들고 이름을 company로 지정하겠습니다.
data class Company(
var id: Int,
var name: String,
var email: String
)
5 단계
보다, activity_main.xml 파일에서 레이아웃 태그 바로 뒤에 데이터 태그를 추가하고 "Company"인스턴스에 대한 레이아웃 변수를 정의합니다.
<data>
<variable
name="company"
type="com.anushka.bindingdemo1.Company" />
</data>
회사 이름과 이메일을 표시하려면 두 개의 TextView가 필요합니다. 두 개의 TextView를 xml 레이아웃 파일로 끌어다 놓습니다.
(activity_main.xml의 디자인 모드로 전환하고 두 개의 TextView를 레이아웃 맨 아래에 놓으십시오. 자동으로 제약 조건을 설정하려면 "Infer Constraints"버튼을 사용하십시오.)
android : text = "@ {company.name}"
android : text = "@ {company.email}"
이러한 변경 후 전체 activity_main.xml 파일은 다음과 같습니다.
<?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="company"
type="com.자기패키지경로.Company" />
</data>
<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: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" />
<EditText
android:id="@+id/name_edit_text"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_margin="20dp"
android:ems="10"
android:hint="@string/insert_you_name_here"
android:inputType="textPersonName"
android:textSize="30sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/greeting_text_view"
app:layout_constraintVertical_bias="0.126" />
<Button
android:id="@+id/submit_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/submit"
android:textSize="30sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.498"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.613" />
<TextView
android:id="@+id/company_text_view"
android:text="@{company.name}"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="133dp"
android:textSize="30sp"
android:textStyle="bold"
android:typeface="sans"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" />
<TextView
android:id="@+id/company_email_text_view"
android:text="@{company.email}"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="31dp"
android:textSize="24sp"
android:textStyle="bold"
android:typeface="sans"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/company_text_view" />
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>
6 단계
그런 다음 MainActivyt.kt로 돌아가서 comany 인스턴스를 레이아웃 개체 (라이브러리에서 acitvity_main.xml 파일에 대해 생성 한 데이터 바인딩 개체)에 전달하는 코드를 작성해 보겠습니다.
여기에서는 "Company"인스턴스를 반환하는 새 함수를 만듭니다.
private fun getCompany ( ) : Company { return Company ( 1 , "ABC Solutions" , " support@abc.org " ) }
그런 다음 "onCreate"내부에 코드를 작성하여 레이아웃의 데이터 변수 값을 설정합니다.
binding.company = getCompany()
class MainActivity : AppCompatActivity() {
private lateinit var binding: ActivityMainBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = DataBindingUtil.setContentView(this, R.layout.activity_main)
binding.company = getCompany()
binding.submitButton.setOnClickListener {
displayGreeting()
}
}
private fun displayGreeting() {
binding.apply {
greetingTextView.text = "Hello! " + nameEditText.text
}
}
private fun getCompany():Company{
return Company(1,"ABC Solutions","support@abc.org")
}
}
프래그먼트로 데이터 바인딩.
액티비티와 프래그먼트 모두에 대해 동일한 방식으로 XML 레이아웃 코드 부분을 처리합니다. (레이아웃 태그, 레이아웃 변수, 레이아웃 표현식)
그러나 바인딩 인스턴스를 구성하는 방식에는 약간의 차이가 있습니다
액티비티와 프래그먼트 모두에 대해 DataBindingUtil 을 사용 합니다.
For activates we invoke setContentView funciton, but for fragment we invoke inflate function. In addition, we need to return binding.root .
Here is a fragment code example.
class HomeFragment : Fragment() {
private lateinit var binding: FragmentHomeBinding
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
binding = DataBindingUtil.inflate(inflater, R.layout.fragment_home, container, false)
binding.button.setOnClickListener {
Toast.makeText(activity, "Button Clicked", Toast.LENGTH_LONG).show()
}
return binding.root
}
}
RecyclerView로 데이터 바인딩.
RecyclerView와 함께 데이터 바인딩을 사용할 때 목록 항목 xml 리소스 파일 에 <layout> </ layout> 태그를 추가해야 합니다. 그것은 다른 레이아웃 파일에 추가됩니다. (관련 활동 또는 조각의 xml 레이아웃)
class MyRecyclerViewAdapter(private val clickListener: (Subscriber) -> Unit) :
RecyclerView.Adapter<MyViewHolder>() {
private val subscribersList = ArrayList<Subscriber>()
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyViewHolder {
val layoutInflater = LayoutInflater.from(parent.context)
val binding: ListItemBinding =
DataBindingUtil.inflate(layoutInflater, R.layout.list_item, parent, false)
return MyViewHolder(binding)
}
override fun getItemCount(): Int {
return subscribersList.size
}
override fun onBindViewHolder(holder: MyViewHolder, position: Int) {
holder.bind(subscribersList[position], clickListener)
}
fun setList(subscribers: List<Subscriber>) {
subscribersList.clear()
subscribersList.addAll(subscribers)
}
}
class MyViewHolder(val binding: ListItemBinding) : RecyclerView.ViewHolder(binding.root) {
fun bind(subscriber: Subscriber, clickListener: (Subscriber) -> Unit) {
binding.nameTextView.text = subscriber.name
binding.emailTextView.text = subscriber.email
binding.listItemLayout.setOnClickListener {
clickListener(subscriber)
}
}
}
데이터 바인딩을 사용하거나 사용하지 않는 어댑터 클래스의 다른 방법을 비교해 보겠습니다.
onCreateViewHolder
데이터 바인딩이 없습니다.
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyViewHolder {
val layoutInflater = LayoutInflater.from(parent.context)
val listItem = layoutInflater.inflate(R.layout.list_item,parent,false)
return MyViewHolder(listItem)
}
데이터 바인딩.
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyViewHolder {
val layoutInflater = LayoutInflater.from(parent.context)
val binding: ListItemBinding =
DataBindingUtil.inflate(layoutInflater, R.layout.list_item, parent, false)
return MyViewHolder(binding)
}
기본 recycerview 어댑터에서 layoutInflater를 사용하여 목록 항목 xml 리소스 파일에 대한 View 인스턴스를 가져옵니다.
그러나 데이터 binidng를 사용할 때는 목록 항목 xml 리소스 파일 uisng DataBindingUtil의 바인딩 개체를 가져와야합니다.
RecyclerView.ViewHolder 클래스 (또는 내부 클래스)
데이터 바인딩이 없습니다.
class MyViewHolder(val view: View) : RecyclerView.ViewHolder(view) {
fun bind(subscriber: Subscriber, clickListener: (Subscriber) -> Unit) {
view.nameTextView.text = subscriber.name
view.emailTextView.text = subscriber.email
view.listItemLayout.setOnClickListener {
clickListener(subscriber)
}
}
}
데이터 바인딩.
class MyViewHolder(val binding: ListItemBinding) : RecyclerView.ViewHolder(binding.root) {
fun bind(subscriber: Subscriber, clickListener: (Subscriber) -> Unit) {
binding.nameTextView.text = subscriber.name
binding.emailTextView.text = subscriber.email
binding.listItemLayout.setOnClickListener {
clickListener(subscriber)
}
}
}
기본 recycerview 어댑터에서는 View 인스턴스에서 뷰 구성 요소를 가져와 값을 설정합니다.
RecyclerView.ViewHolder has view as the parameter RecyclerView.ViewHolder(view)
그러나 데이터 binidng를 사용할 때 바인딩 개체를 사용하여 뷰 구성 요소를 가져오고 여기에 값을 설정합니다.
RecyclerView.ViewHolder에는 매개 변수로 binding.root 가 있습니다.
RecyclerView.ViewHolder(binding.root)
원글
https://appdevnotes.com/android-databinding-tutorial-for-beginners-in-kotlin/
Android Databinding tutorial for beginners in Kotlin. - AppDevNotes
In this tutorial you will learn about Android Data Binding (beginner to expert) with easy to understand project examples.
appdevnotes.com
'Android > MVVM' 카테고리의 다른 글
Two Way Data Binding vs One Way Data Binding (0) | 2021.05.20 |
---|---|
Live Data (0) | 2021.05.20 |
안드로이드 뷰모델 (0) | 2021.05.20 |
02. MVVM 적용 샘플 #01 (0) | 2021.03.31 |
#01. MVVM (0) | 2021.03.31 |