๊นจ์•Œ ๊ฐœ๋… ๐Ÿ“‘/Android

[Android] Data Binding - ๊ธฐ์ดˆ

interfacer_han 2024. 1. 11. 16:40

#1 ๋ฐ์ดํ„ฐ ๋ฐ”์ธ๋”ฉ ์‚ฌ์šฉ ์ „

#1-1 ์˜ˆ์‹œ ์•ฑ

์œ„๊ณผ ๊ฐ™์€ ๊ฐ„๋‹จํ•œ ์•ฑ์ด ์žˆ๋‹ค. Button์„ ๋ˆ„๋ฅด๋ฉด, EditText์˜ text๊ฐ€ ๋ฐ”๋กœ ์œ„์— ์žˆ๋Š” TextView์˜ text์— ๋Œ€์ž…๋œ๋‹ค. ์ด ์•ฑ์˜ ์ฝ”๋“œ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค.
 

#1-2 activity_main.xml

<?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">

    <TextView
        android:id="@+id/my_text_view"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginBottom="25dp"
        android:textSize="30dp"
        app:layout_constraintBottom_toTopOf="@id/my_container"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent" />

    <androidx.constraintlayout.widget.ConstraintLayout
        android:id="@+id/my_container"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent">

        <EditText
            android:id="@+id/my_edit_text"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:ems="10"
            android:hint="Input any text to print"
            android:inputType="text"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintEnd_toStartOf="@id/my_button"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent" />

        <Button
            android:id="@+id/my_button"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Print"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toEndOf="@id/my_edit_text"
            app:layout_constraintTop_toTopOf="parent" />
    </androidx.constraintlayout.widget.ConstraintLayout>

</androidx.constraintlayout.widget.ConstraintLayout>

 

#1-3 MainActivity.kt

// package com.example.databindingpractice

import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.widget.Button
import android.widget.EditText
import android.widget.TextView

class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        val myTextView = findViewById<TextView>(R.id.my_text_view)
        val myEditText = findViewById<EditText>(R.id.my_edit_text)
        val myButton = findViewById<Button>(R.id.my_button)

        myButton.setOnClickListener{
            myTextView.text = myEditText.text
        }
    }
}

์•ˆ๋“œ๋กœ์ด๋“œ๋ฅผ ์ฒ˜์Œ ๋ฐฐ์šธ ๋•Œ๋ถ€ํ„ฐ ์‚ฌ์šฉํ–ˆ๋˜ findViewById()๊ฐ€ ์žˆ๋‹ค. findViewById()๋Š” view(๋ณด์ด๋Š” ํ™”๋ฉด)์— ์žˆ๋Š” ๋ ˆํผ๋Ÿฐ์Šค(์ฐธ์กฐ)๋ฅผ ํ™•๋ณดํ•˜๋Š” ๋ฐฉ๋ฒ• ์ค‘ ๊ฐ€์žฅ ๊ธฐ์ดˆ์ ์ธ ๋ฐฉ๋ฒ•์ด๋‹ค. findViewById()๋Š” ๋Ÿฐํƒ€์ž„์ด ์•„๋‹ˆ๋ผ ์ปดํŒŒ์ผ ์‹œ์ ์— view์˜ ๋ ˆํผ๋Ÿฐ์Šค๋ฅผ ํ™•๋ณดํ•˜๊ธฐ์—, ์ ์–ด๋„ ๋Ÿฐํƒ€์ž„ ์ค‘ view์— ๊ด€ํ•œ ์—๋Ÿฌ๋Š” ๋‚˜์ง€ ์•Š๊ฒŒ ๋ณด์žฅํ•œ๋‹ค๋Š” ์žฅ์ ์ด ์žˆ๋‹ค. ํ•˜์ง€๋งŒ, TextView์™€ ๊ฐ™์€ ์œ„์ ฏ๋“ค์˜ ๊ฐฏ์ˆ˜๊ฐ€ ๋งŽ์•„์ง€๋ฉด, ํ•˜๋‚˜ํ•˜๋‚˜ findViewById()๋ฅผ ์“ฐ๋ฉฐ ๋ทฐ ๊ณ„์ธต์— ์ ‘๊ทผํ•˜๋Š” ๊ฒƒ์ด ๋ฒˆ๊ฑฐ๋กœ์›Œ์ง„๋‹ค. ๋™์‹œ์— ์ฝ”๋“œ์˜ ๊ฐ€๋…์„ฑ๋„ ์ €ํ•˜๋œ๋‹ค.

์ด ๋•Œ, findViewById()์˜ ์žฅ์ ์„ ์œ ์ง€ํ•˜๋ฉด์„œ, ๋‹จ์ ์„ ํ•ด์†Œํ•˜๋Š” ๋ฐฉ๋ฒ•์ด ์žˆ๋Š”๋ฐ ๋ฐ”๋กœ Binding object๋ผ๋Š” ๊ฐ์ฒด๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๋ฐฉ๋ฒ•์ด๋‹ค. Binding object๋Š” ๊ฐ layout์— ๋“ค์–ด์žˆ๋Š” ๋ชจ๋“  view์˜ ๋ ˆํผ๋Ÿฐ์Šค๋ฅผ ์ €์žฅํ•˜๋Š” ๊ฐ์ฒด๋‹ค.
 

#2 ๋ฐ์ดํ„ฐ ๋ฐ”์ธ๋”ฉ์˜ ๊ธฐ์ดˆ์ ์ธ ์‚ฌ์šฉ

#2-1 build.gradle.kts (Module :app)์—์„œ ๋ฐ์ดํ„ฐ ๋ฐ”์ธ๋”ฉ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ์ถ”๊ฐ€ํ•˜๊ธฐ

plugins {
    ...
}

android {
    ...
    
    buildFeatures {
        dataBinding = true
    }
}

dependencies {
    ...
}

Binding object๋ฅผ ์‚ฌ์šฉํ•˜๊ธฐ์œ„ํ•ด ๋จผ์ €, Data Binding ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ(androidx.databinding)๋ฅผ ๋‹ค์šด๋กœ๋“œํ•ด์•ผ ํ•œ๋‹ค. ๋ชจ๋“ˆ ์ˆ˜์ค€์˜ ๊ทธ๋ž˜๋“ค ๋นŒ๋“œ ํŒŒ์ผ build.gradle.kts (Module :app)์—์„œ android {...} ์•ˆ์—, buildFeatures { dataBinding = true } ๊ตฌ๋ฌธ์„ ์ถ”๊ฐ€ํ•œ๋‹ค. ๊ทธ๋ž˜๋“ค ๋ฒ„์ „ 4.0๋ฏธ๋งŒ์€ ๋Œ€์‹  dataBinding { enabled = true } ๊ตฌ๋ฌธ์„ ์ถ”๊ฐ€ํ•œ๋‹ค. ์ด๋Ÿฌ๋ฉด gradle์ด ์•Œ์•„์„œ androidx.databinding ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ๋‹ค์šด๋กœ๋“œ ํ•œ๋‹ค. ๊ตฌ๋ฌธ์„ ์ถ”๊ฐ€ํ•˜๋ฉด ์ƒ๋‹จ์— Sync๋ฅผ ํ•˜๋ผ๋Š” ์•ˆ๋‚ด ๋ฉ”์‹œ์ง€๊ฐ€ ๋œจ๋Š”๋ฐ, ํ•ด๋‹น ๋ฉ”์‹œ์ง€์˜ Sync ๋ฒ„ํŠผ์„ ๋ˆ„๋ฅธ๋‹ค.
 

#2-2 activity_main.xml์— <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:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context=".MainActivity">

        ...

    </androidx.constraintlayout.widget.ConstraintLayout>
</layout>

<?xml version="1.0" encoding="utf-8"?>๋ฅผ ์ œ์™ธํ•œ ๋ชจ๋“  ๋ถ€๋ถ„์„ <layout> ํƒœ๊ทธ๋กœ ๊ฐ์‹ผ๋‹ค. <layout> ํƒœ๊ทธ๋Š” ๋ฐ์ดํ„ฐ ๋ฐ”์ธ๋”ฉ์„ ์œ„ํ•œ ๋ ˆ์ด์•„์›ƒ ํŒŒ์ผ์ž„์„ ์•ˆ๋“œ๋กœ์ด๋“œ ์‹œ์Šคํ…œ์— ์•Œ๋ ค์ค€๋‹ค. ์ด๋ ‡๊ฒŒํ•˜๋ฉด, Data Binding ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๊ฐ€ ์ž๋™์œผ๋กœ Binding class๋ฅผ ์ƒ์„ฑํ•œ๋‹ค. ์ด์ œ๋ถ€ํ„ฐ Binding class์—์„œ Binding object๋ฅผ ์ฐ์–ด๋‚ผ ์ˆ˜ ์žˆ๋‹ค. ์ด ํด๋ž˜์Šค์˜ ์ด๋ฆ„์€ abc_def_ghi.xml๋ผ๋ฉด AbcDeFGhiBinding์œผ๋กœ ์ •ํ•ด์ง„๋‹ค. ์ฆ‰, _๋กœ ๊ตฌ๋ถ„๋˜๋Š” ๋‹จ์–ด๋“ค์˜ ์ฒซ๊ธ€์ž๋ฅผ ๋Œ€๋ฌธ์ž๋กœ ๋ฐ”๊พผ ๋’ค์— "Binding"์ด ๋ถ™์—ฌ์ง„๋‹ค.

xmlns ์ฆ‰, xml ํŒŒ์ผ์˜ ๋„ค์ž„์ŠคํŽ˜์ด์Šค ์„ ์–ธ(namespace declarations)์€ xml ํŒŒ์ผ์—์„œ ๊ฐ€์žฅ ์™ธ๊ณฝ(outmost)์— ์žˆ๋Š” ํƒœ๊ทธ์˜ ์†์„ฑ์œผ๋กœ ๋“ค์–ด๊ฐ€ ์žˆ์–ด์•ผ ํ•œ๋‹ค๋Š” ๊ทœ์น™์ด ์žˆ์œผ๋ฏ€๋กœ, ์›๋ž˜ ์žˆ๋˜ ์ž๋ฆฌ์—์„œ <layout> ํƒœ๊ทธ๋กœ ์˜ฎ๊ฒจ์ค€๋‹ค.
 

#2-3 MainActivity.kt์—์„œ Binding object ์‚ฌ์šฉํ•˜๊ธฐ

// package com.example.databindingpractice

import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import androidx.databinding.DataBindingUtil
import com.example.databindingpractice.databinding.ActivityMainBinding

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.myButton.setOnClickListener{
            binding.myTextView.text = binding.myEditText.text
        }
    }
}

Activity์—์„œ ๋ฐ”์ธ๋”ฉ ํด๋ž˜์Šค๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๋ชจ์Šต์ด๋‹ค. androidx.databinding.DataBindingUtil ํด๋ž˜์Šค์˜ setContentView()๋กœ ์ดˆ๊ธฐํ™”๋ฅผ ํ•œ๋‹ค. ์›๋ž˜์˜ setContentView()๋Š” androidx.appcompat.app.AppCompatActivity์˜ ๋ฉ”์†Œ๋“œ์˜€๋‹ค. ํ•˜์ง€๋งŒ, ์ด๋ฆ„์ด ๊ฐ™๋‹ค๋Š” ๊ฒƒ์—์„œ ์•Œ ์ˆ˜ ์žˆ๋“ฏ ํ•˜๋Š” ์ผ์€ '๋น„์Šท'ํ•  ๊ฒƒ์ž„์„ ์œ ์ถ”ํ•  ์ˆ˜ ์žˆ๋‹ค. binding ๊ฐ์ฒด์—๋Š” ActivityMainBinding ํด๋ž˜์Šค์˜ ์œ„์ ฏ id๋“ค ์ฆ‰ activity_main.xml์˜ ์œ„์ ฏ id ์ •๋ณด๊ฐ€ ํ”„๋กœํผํ‹ฐ๋กœ์„œ ๋‹ด๊ฒจ์ ธ ์žˆ๋‹ค.

๊ทธ ํ”„๋กœํผํ‹ฐ์˜ ์ด๋ฆ„์€ Binding ํด๋ž˜์Šค์˜ ์ด๋ฆ„ ๊ทœ์น™๊ณผ ๋น„์Šทํ•˜๊ฒŒ ์ž๋™ ์ƒ์„ฑ๋˜์–ด์žˆ๋‹ค. xml์—์„œ ์œ„์ ฏ์˜ android:id ์†์„ฑ์ด "@+id/abc_def_ghi"๋กœ ์„ค์ •๋˜์–ด์žˆ๋‹ค๋ฉด abcDefGhi๊ฐ€ ํ”„๋กœํผํ‹ฐ๋ช…์ด ๋œ๋‹ค.
 
๊ฒฐ๋ก ์ ์œผ๋กœ, findViewById๋กœ ๋ ˆํผ๋Ÿฐ์Šค๋ฅผ ํ•˜๋‚˜ํ•˜๋‚˜ ๋ถˆ๋Ÿฌ์™€์„œ ๋ณ€์ˆ˜ ์ด๋ฆ„์„ ํ•˜๋‚˜ํ•˜๋‚˜ ๋ถ™์ด๋Š” ๋ฐฉ์‹์— ๋น„ํ•ด ์†Œ์Šค ์ฝ”๋“œ ์ž‘์„ฑ ์†๋„๊ฐ€ ๋” ๋นจ๋ผ์กŒ์œผ๋ฉฐ, ๊ฐ€๋…์„ฑ๋„ ์ข‹์•„์กŒ๋‹ค.
 

#2-4 apply ํ•จ์ˆ˜ ์‚ฌ์šฉ

/*
binding.myButton.setOnClickListener{
    binding.myTextView.text = binding.myEditText.text
}
*/

binding.apply {
    myButton.setOnClickListener {
        myTextView.text = myEditText.text
    }
}

์ฝ”ํ‹€๋ฆฐ์˜ scope ํ•จ์ˆ˜๋“ค ์ค‘ ํ•˜๋‚˜์ธ apply๋ฅผ ํ™œ์šฉํ•˜๋ฉด ์œ„๊ณผ ๊ฐ™์ด ์ฝ”๋“œ๋ฅผ ๋”์šฑ ๊ฐ„์†Œํ™”์‹œํ‚ฌ ์ˆ˜ ์žˆ๋‹ค.
 

#3 ์š”์•ฝ

Data Binding์œผ๋กœ findViewById()๋ฅผ ์ผ๊ด„ ์„ค์ •ํ•  ์ˆ˜ ์žˆ๋‹ค.

 

#4 ์™„์„ฑ๋œ ์•ฑ

 

android-practice/data-binding/DataBindingBasics at master ยท Kanmanemone/android-practice

Contribute to Kanmanemone/android-practice development by creating an account on GitHub.

github.com