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

[Android] Data Binding - View์— ๊ฐ์ฒด ์ „๋‹ฌ

interfacer_han 2024. 1. 12. 14:57

#1 ๊ฐ์ฒด ์ „๋‹ฌ์˜ ํ•„์š”์„ฑ

#1-1 ์ด์ „ ๊ธ€

 

Data Binding - ๊ธฐ์ดˆ

#1 ๋ฐ์ดํ„ฐ ๋ฐ”์ธ๋”ฉ ์‚ฌ์šฉ ์ „ #1-1 ์˜ˆ์‹œ ์•ฑ ์œ„๊ณผ ๊ฐ™์€ ๊ฐ„๋‹จํ•œ ์•ฑ์ด ์žˆ๋‹ค. Button์„ ๋ˆ„๋ฅด๋ฉด, EditText์˜ text๊ฐ€ ๋ฐ”๋กœ ์œ„์— ์žˆ๋Š” TextView์˜ text์— ๋Œ€์ž…๋œ๋‹ค. ์ด ์•ฑ์˜ ์ฝ”๋“œ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค. #1-2 activity_main.xml #1-3 Main

kenel.tistory.com

์ด์ „ ๊ธ€์—์„œ ์ด์–ด์ง„๋‹ค. ์ด์ „ ๊ธ€์—์„ , ๋ฐ์ดํ„ฐ ๋ฐ”์ธ๋”ฉ์„ ํ†ตํ•ด View์˜ ๋ ˆํผ๋Ÿฐ์Šค๋ฅผ ์ผ๊ด„์ ์œผ๋กœ ๊ฐ€์ ธ์™€ ์ฐธ์กฐํ•  ์ˆ˜ ์žˆ์—ˆ๋‹ค. ์ด๋ฒˆ์—๋Š” ๋ฐ˜๋Œ€๋กœ View์—๊ฒŒ ๊ฐ์ฒด๋ฅผ ๋ณด๋‚ธ๋‹ค. ์•„๋ž˜์˜ ์˜ˆ์‹œ ์•ฑ์„ ๋ณด์ž. 
 

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

์ด ์•ฑ์€ ์–ด๋–ค ์ฑ… ํด๋ž˜์Šค์˜ ๊ฐ์ฒด๋ฅผ ๋ฐ›์•„ ํ™”๋ฉด์— ํ‘œ์‹œํ•˜๋Š” ์•ฑ์ด๋‹ค. ํ™”๋ฉด ์•„๋ž˜์— ์žˆ๋Š” ๋ฒ„ํŠผ๋“ค์„ ๋ˆ„๋ฅด๋ฉด ํ™”๋ฉด ์œ„ ์ชฝ์˜ TextView๋“ค์˜ text ์†์„ฑ์„ ๋ณ€๊ฒฝํ•œ๋‹ค. ์ด์ „ ๊ธ€์˜ ๋‚ด์šฉ์— ๋”ฐ๋ผ ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ–ˆ์œผ๋ฉฐ, ๊ทธ ์ฝ”๋“œ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค.
 

#1-3 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">

    <androidx.constraintlayout.widget.ConstraintLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context=".MainActivity">

        <TextView
            android:id="@+id/book_name"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:textSize="30sp"
            app:layout_constraintBottom_toTopOf="@+id/book_author"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent"
            app:layout_constraintVertical_chainStyle="packed" />

        <TextView
            android:id="@+id/book_author"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:textSize="30sp"
            app:layout_constraintBottom_toTopOf="@id/book_year"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toBottomOf="@id/book_name" />

        <TextView
            android:id="@+id/book_year"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:textSize="30sp"
            app:layout_constraintBottom_toTopOf="@id/guideline"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toBottomOf="@id/book_author" />

        <androidx.constraintlayout.widget.Guideline
            android:id="@+id/guideline"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="horizontal"
            app:layout_constraintGuide_percent="0.5" />

        <Button
            android:id="@+id/button_book_1"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="์›”๋“ "
            app:layout_constraintBottom_toTopOf="@id/button_book_3"
            app:layout_constraintEnd_toStartOf="@id/button_book_2"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toBottomOf="@+id/guideline" />

        <Button
            android:id="@+id/button_book_2"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="์–ด๋ฆฐ ์™•์ž"
            app:layout_constraintBottom_toTopOf="@id/button_book_4"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toEndOf="@+id/button_book_1"
            app:layout_constraintTop_toBottomOf="@+id/guideline" />

        <Button
            android:id="@+id/button_book_3"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="๋„์ฟ„์˜ ๋””ํ…Œ์ผ"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintEnd_toStartOf="@+id/button_book_4"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toBottomOf="@+id/button_book_1" />

        <Button
            android:id="@+id/button_book_4"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="ํ”Œ๋ฆฝ ์‹ฑํ‚น"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toEndOf="@id/button_book_3"
            app:layout_constraintTop_toBottomOf="@+id/button_book_2" />

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

 

#1-4 Book.kt

// package com.example.withobjectpractice

data class Book (
    val name: String,
    val author: String,
    val year: Int
)

 

#1-5 MainActivity.kt

// package com.example.withobjectpractice

import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.widget.Button
import androidx.databinding.DataBindingUtil
import com.example.withobjectpractice.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)
        
        onShowBookInfoButtonClick(binding.buttonBook1, getWalden())
        onShowBookInfoButtonClick(binding.buttonBook2, getTheLittlePrince())
        onShowBookInfoButtonClick(binding.buttonBook3, getDetailsOfTokyo())
        onShowBookInfoButtonClick(binding.buttonBook4, getFlipThinking())
    }
    
    private fun onShowBookInfoButtonClick(button: Button, book: Book) {
        button.setOnClickListener{
            binding.bookName.text = "์ด๋ฆ„: " + book.name
            binding.bookAuthor.text = "์ €์ž: " + book.author
            binding.bookYear.text = "์ถœํŒ๋…„๋„: " + book.year.toString() + "๋…„"
        }
    }
    
    private fun getWalden(): Book {
        return Book("์›”๋“ ", "David Thoreau", 1854)
    }
    
    private fun getTheLittlePrince(): Book {
        return Book("์–ด๋ฆฐ ์™•์ž", "Saint-Exupéry", 1943)
    }
    
    private fun getDetailsOfTokyo(): Book {
        return Book("๋„์ฟ„์˜ ๋””ํ…Œ์ผ", "์ƒ๊ฐ๋…ธํŠธ", 2018)
    }
    
    private fun getFlipThinking(): Book {
        return Book("ํ”Œ๋ฆฝ ์‹ฑํ‚น", "Berthold Gunster", 2023)
    }
}

์ฑ… ๊ฐ์ฒด๋ฅผ ๋ฐ›์•„์„œ ์ด๋ฆ„, ์ €์ž, ์ถœํŒ๋…„๋„๋กœ ์ด๋ฃจ์–ด์ง„ ํ”„๋กœํผํ‹ฐ๋ฅผ ํ•˜๋‚˜ํ•˜๋‚˜ View์— ๋Œ€์ž…ํ•œ๋‹ค. ์ด ์ฝ”๋“œ๋Š” findViewById()๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ๋ณด๋‹ค๋Š” ๋‚ซ๋‹ค. ํ•˜์ง€๋งŒ, ์•ฑ์˜ ๊ธฐ๋Šฅ์ด ๋งŽ์•„์ง€๊ณ  Activity์˜ ์ฝ”๋“œ ๊ธธ์ด๋„ ๊ธธ์–ด์ง€๋ฉด, ์ด์™€ ๊ฐ™์ด View์— ์„ธ๋ถ€ ์‚ฌํ•ญ์— ๊ด€์—ฌํ•˜๋Š” ์ฝ”๋“œ๋Š” ๊ต‰์žฅํžˆ ๊ฑฐ์Šฌ๋ฆฌ๊ฒŒ ๋  ๊ฒƒ์ด๋‹ค. ์ด ๋•Œ, ์„ธ๋ถ€ ์‚ฌํ•ญ์„ Activity์—์„œ ์ฒ˜๋ฆฌํ•˜์ง€ ์•Š๊ณ , Book ๊ฐ์ฒด ์ž์ฒด๋ฅผ View์— ์ „๋‹ฌํ•ด์„œ ๊ทธ View๋ณด๊ณ  ์•Œ์•„์„œ ๊ทธ ๊ฐ์ฒด๋ฅผ ๋‹ค๋ฃจ๋ผ๊ณ  ํ•œ๋‹ค๋ฉด Activity(Cotroller)๋Š” ๋” ๊ฐ€๋ฒผ์›Œ์งˆ ๊ฒƒ์ด๋‹ค. ์ฆ‰ ๊ฐ์ฒด๋ฅผ ์ „๋‹ฌํ•œ๋‹ค๋Š” ๋ง์€, Cotroller๋Š” ๋ฐ์ดํ„ฐ๋งŒ ์ „๋‹ฌํ•˜๊ณ  ๊ทธ ๋ฐ์ดํ„ฐ๊ฐ€ ์–ด๋–ป๊ฒŒ ๋ณด์ผ์ง€๋Š” ๊ด€์—ฌํ•˜์ง€ ์•Š๊ฒŒ ๋งŒ๋“ค๊ฒ ๋‹ค๋Š” ์†Œ๋ฆฌ๋‹ค.
 
์ง€๊ธˆ๋ถ€ํ„ฐ #1์˜ ์ฝ”๋“œ๊ฐ€ ๊ฐ์ฒด๋ฅผ ์ „๋‹ฌํ•˜๊ฒŒ๋” ๋ฆฌํŒฉํ† ๋ง ํ•ด๋ณธ๋‹ค.
 

#2 ๊ฐ์ฒด๋ฅผ View์— ๋ณด๋‚ด๊ฒŒ ์ˆ˜์ •ํ•˜๊ธฐ

#2-1 activity_main.xml์—์„œ <variable> ํƒœ๊ทธ ์ถ”๊ฐ€ ๋ฐ ํ™œ์šฉ

<?xml version="1.0" encoding="utf-8"?>
<layout ... >

    <data>
        <variable
            name="book"
            type="com.example.withobjectpractice.Book" />
    </data>

    <androidx.constraintlayout.widget.ConstraintLayout ... >

        <TextView
            ...
            android:text="@{`์ด๋ฆ„: ` + book.name}"
            ... />

        <TextView
            ...
            android:text="@{`์ €์ž: ` + book.author}"
            ... />

        <TextView
            ...
            android:text="@{`์ถœํŒ๋…„๋„: ` + book.author + `๋…„`}"
            ... />

        ...

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

<data> ํƒœ๊ทธ๋ฅผ xml์— ๋„ฃ๋Š”๋‹ค. ๊ทธ ์†์— <variable> ํƒœ๊ทธ๋ฅผ ๋„ฃ๋Š”๋‹ค. variable ํƒœ๊ทธ๋Š” type๊ณผ name์˜ 2๊ฐ€์ง€ ์†์„ฑ์ด ์žˆ๋‹ค. type์—๋Š” data class์˜ ์ •ํ™•ํ•œ ์œ„์น˜๋ฅผ ์ ๊ณ , name์—๋Š” type์˜ ๊ธด ์ด๋ฆ„์„ ๋Œ€์‹ ํ•  ๋ณ„๋ช…์„ ์ง€์ •ํ•œ๋‹ค. ์ด์ œ Data binding ํด๋ž˜์Šค๊ฐ€ ์ž๋™์œผ๋กœ, ActivityMainBinding ํด๋ž˜์Šค์— book์ด๋ผ๋Š” ์ด๋ฆ„์˜ ํ”„๋กœํผํ‹ฐ๋ฅผ ์ถ”๊ฐ€ํ•œ๋‹ค. ActivityMainBinding ํด๋ž˜์Šค์˜ ํ™œ์šฉ์€ MainActivity.kt์˜ ๋ชซ์ด๋‹ค. MainActivity.kt๊ฐ€ ์–ด๋–ค Book ๊ฐ์ฒด๋ฅผ View๋‹จ์œผ๋กœ ๋ณด๋‚ด์ค„ ์ง€๋Š” View ์ž…์žฅ์—์„œ ์•Œ ๊ธธ์ด ์—†์œผ๋‚˜, ๊ทธ๊ฒƒ์ด ์–ด๋–ป๊ฒŒ ๋ณด์ผ์ง€๋Š” ํ†ต์ œํ•  ์ˆ˜ ์žˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด, <TextView>์˜ ์†์„ฑ android:text์— "@{book.author}"์™€ ๊ฐ™์ด book ํ”„๋กœํผํ‹ฐ๋ฅผ ์ฐธ์กฐํ•˜๋Š” ๊ฐ’์„ ๋„ฃ๋Š” ๊ฒƒ๊ณผ ๊ฐ™์ด ๋ง์ด๋‹ค.
 

#2-2 MainActivity.kt ์ˆ˜์ •

// package com.example.withobjectpractice

...

class MainActivity : AppCompatActivity() {

    ...
    
    private fun onShowBookInfoButtonClick(button: Button, book: Book) {
        button.setOnClickListener{
            binding.book = book
        }
    }

    ...
}

ActivityMainBinding์˜ ํ”„๋กœํผํ‹ฐ์— book์ด ์ถ”๊ฐ€๋˜์—ˆ์œผ๋ฏ€๋กœ, ํ•ด๋‹น ํ”„๋กœํผํ‹ฐ๋ฅผ ํ™œ์šฉํ•˜๊ฒŒ๋” ์ฝ”๋“œ๋ฅผ ์ˆ˜์ •ํ•œ๋‹ค. ์ดํ›„์˜ ์ž‘์—… ์ฆ‰ ์ด ๊ฐ์ฒด๋ฅผ ์–ด๋–ป๊ฒŒ ์ž˜ ํ‘œ์‹œํ•  ๊ฒƒ์ธ๊ฐ€?๋Š” activity_main.xml (View)์—๊ฒŒ ๋งก๊ธด๋‹ค. (#2-1 ์ฐธ์กฐ)
 

#2-3 ๋ณ€๊ฒฝ์‚ฌํ•ญ ์ž‘๋™ ํ™•์ธ, ์•„์‰ฌ์šด ์ 

์ œ๋Œ€๋กœ ์ž‘๋™ํ•œ๋‹ค. ํ•˜์ง€๋งŒ, ์•„๋ฌด ๋ฒ„ํŠผ๋„ ํด๋ฆญ๋˜์ง€ ์•Š์€ ์ฒ˜์Œ ํ™”๋ฉด์ด ๊ฑฐ์Šฌ๋ฆฐ๋‹ค. <variable>์— ์•„๋ฌด๋Ÿฐ ๊ฐ์ฒด๊ฐ€ ์ „๋‹ฌ๋˜์ง€ ์•Š์•˜๊ธฐ ๋•Œ๋ฌธ์—, null์„ ๋ฐ˜ํ™˜ํ•˜๋Š” ๊ฒƒ์ด๋‹ค. ๊ฐ์ฒด๊ฐ€ ์ „๋‹ฌ๋˜์ง€ ์•Š์€ ์ƒํ™ฉ์—์„œ๋„ ์ž์—ฐ์Šค๋Ÿฝ๊ฒŒ ํ™”๋ฉด์„ ํ‘œ์‹œํ•˜๊ธฐ ์œ„ํ•ด์„œ ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์ฝ”๋“œ๋ฅผ ๋ณ€๊ฒฝํ•œ๋‹ค.
 

#2-4 null๊ฐ’์„ ๊ณ ๋ คํ•œ XML ์ฝ”๋“œ

<?xml version="1.0" encoding="utf-8"?>
<layout ... >

    <data>
        <variable ... >
    </data>

    <androidx.constraintlayout.widget.ConstraintLayout ... >

        <TextView
            ...
            android:text="@{book != null ? `์ด๋ฆ„: ` + book.name : `์ฑ… ์ •๋ณด ์—†์Œ`}"
            ... />

        <TextView
            ...
            android:text="@{book != null ? `์ €์ž: ` + book.author : ``}"
            ... />

        <TextView
            ...
            android:text="@{book != null ? `์ถœํŒ๋…„๋„: ` + book.year + `๋…„` : ``}"
            ... />

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

book์— ๋Œ€ํ•ด null ์ฒดํฌ๋ฅผ ํ•˜๊ณ , ๊ฐ์ฒด๊ฐ€ null์ผ ๋•Œ์™€ ์•„๋‹ ๋•Œ๋ฅผ ๋ถ„๊ธฐ์‹œ์ผœ ๊ฐ๊ฐ ํ‘œ์‹œํ•  ๋ฌธ์ž์—ด์„ ์จ ๋„ฃ๋Š”๋‹ค. ์ด๋ ‡๊ฒŒ ๋ณ€๊ฒฝํ•˜๊ณ  ์•ฑ์„ ์‹คํ–‰์‹œํ‚ค๋ฉด ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค.
 

 

#2-5 ๊ฒฐ๋ก  (๊ฐ์ฒด ์ „๋‹ฌ์˜ ์ด์ )

๋ฐ์ดํ„ฐ ๋ฐ”์ธ๋”ฉ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ํ†ตํ•ด์„œ, data class ๋“ฑ์˜ ๊ฐ์ฒด(Model)๋ฅผ View์— ์ง์ ‘(directly) ๋ณด๋‚ผ ์ˆ˜ ์žˆ๋‹ค. ์ด ๋ฐฉ์‹์œผ๋กœ Activity์™€ View(xml) ๊ฐ„์˜ ๊ฒฐํ•ฉ๋„๋ฅผ ๋А์Šจํ•˜๊ฒŒ ๋งŒ๋“ค์—ˆ๋‹ค. Activity๋Š”์€ View์— ์–ด๋–ค ๋ฐ์ดํ„ฐ๋ฅผ ๋ณด๋‚ผ์ง€๋งŒ ๊ณ ๋ฏผํ•˜๊ณ , ๊ทธ ์ด์ƒ์œผ๋กœ ์‹ ๊ฒฝ์“ฐ์ง€ ์•Š๋Š”๋‹ค. View๋Š” Activity๋กœ๋ถ€ํ„ฐ ๋ฐ›์•„๋“ค์ธ ๊ฐ์ฒด๋ฅผ ์˜ค๋กœ์ง€ ์–ด๋–ป๊ฒŒ ํ‘œ์‹œํ•  ์ง€๋งŒ์„ ๊ธฐ์ˆ ํ•œ๋‹ค. ์ด๋Ÿฌํ•œ ๋А์Šจํ•œ ๊ฒฐํ•ฉ๋„๋Š” ๋ฐ์ดํ„ฐ ๋ฐ”์ธ๋”ฉ ์‚ฌ์šฉ์œผ๋กœ ์–ป์„ ์ˆ˜ ์žˆ๋Š” ํฐ ์ด์ ์ด๋‹ค.
 

#3 ์š”์•ฝ

๊ฐ์ฒด๋ฅผ View์— ๋ณด๋‚ด๋Š” ์ด์œ ๋Š” '๋ถ„์—…'์„ ํ•˜๊ธฐ ์œ„ํ•จ์ด๋‹ค.

 

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

 

android-practice/data-binding/ObjectToView at master · Kanmanemone/android-practice

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

github.com