[Android] Databinding ๐Ÿ”—

Jayยท2021๋…„ 1์›” 19์ผ
1

Android

๋ชฉ๋ก ๋ณด๊ธฐ
13/39
post-thumbnail
post-custom-banner

Intro

๋ฐ์ดํ„ฐ๋ฐ”์ธ๋”ฉ์„ ๊ณต๋ถ€ํ•œ๋‹ค๋ฉด, Jetpack๊ณผ AAC๋ฅผ ๋“ค์–ด๋ณธ ์  ์žˆ์„ ๊ฒƒ์ด๋‹ค.
Jetpack์€ 2018๋…„ ๊ตฌ๊ธ€ IOํ–‰์‚ฌ์—์„œ ๋ฐœํ‘œ๋œ ์•ˆ๋“œ๋กœ์ด๋“œ ์•ฑ ๊ฐœ๋ฐœ ํŒจํ‚ค์ง€ ๋ฌถ์Œ ์ž…๋‹ˆ๋‹ค.
Databinding์€ JetPack์˜ ๊ตฌ์„ฑ ์š”์†Œ ์ค‘ ์•„ํ‚คํ…์ฒ˜์™€ ๊ด€๋ จ๋œ AAC๋ถ€๋ถ„์— ์†ํ•œ๋‹ค.
์ด๋ฆ„ ๊ทธ๋Œ€๋กœ ๋ทฐ์— ๋ฐ์ดํ„ฐ๋ฅผ ๋ฌถ์–ด์ฃผ๋Š” ์—ญํ• ์„ ํ•˜๋Š” AAC ๊ธฐ๋ฒ•์˜ ํ•˜๋‚˜.
๋ฐ์ดํ„ฐ ๋ฐ”์ธ๋”ฉ ์„ ์ •๋ฆฌํ•˜์ž.


๐Ÿ“ Android Developers ๊ณต์‹ ๋ฌธ์„œ๋ฅผ ๋ฒˆ์—ญํ•ฉ๋‹ˆ๋‹ค.

Reference : https://developer.android.com/topic/libraries/data-binding


DataBinding

The Data Binding Library is a support library that allows you to bind UI components in your layouts to data sources in your app using a declarative format rather than programmatically.

Google์—์„  ๋ฐ์ดํ„ฐ๋ฐ”์ธ๋”ฉ์— ๋Œ€ํ•ด ์œ„์™€ ๊ฐ™์ด ์„ค๋ช…ํ•˜์˜€๋‹ค.
๋ฐ์ดํ„ฐ๋ฐ”์ธ๋”ฉ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋Š” ํ”„๋กœ๊ทธ๋ž˜๋ฐ ๋ฐฉ์‹์ด ์•„๋‹Œ ์„ ์–ธ์ ์ธ ํ˜•์‹์„ ์‚ฌ์šฉํ•˜์—ฌ ๋ ˆ์ด์•„์›ƒ์˜ UI ๊ตฌ์„ฑ์š”์†Œ์— ์•ฑ์˜ ๋ฐ์ดํ„ฐ ์†Œ์Šค๋ฅผ ๋ฐ”์ธ๋”ฉ ํ•  ์ˆ˜ ์žˆ๋Š” ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์ด๋‹ค.

๋ ˆ์ด์•„์›ƒ์€ ์ข…์ข… UI ํ”„๋ ˆ์ž„์›Œํฌ ๋ฉ”์†Œ๋“œ๋ผ๊ณ  ๋ถˆ๋ฆฌ์šฐ๋Š” ์•กํ‹ฐ๋น„ํ‹ฐ๋‚ด์—์„œ ์ •์˜๋˜๊ธฐ๋„ํ•œ๋‹ค.

์•„๋ž˜์˜ ์˜ˆ์ œ๋ฅผ ๋ณด์ž.

findViewById()๋ฅผ ์ด์šฉํ•˜์—ฌ UI ๊ตฌ์„ฑ์š”์†Œ์ธ Textview๋ฅผ ์ฐพ๊ณ  viewmodel๋ณ€์ˆ˜์˜ ์†์„ฑ์ธ userName์„ ๋ฐ”๋กœ ๋ฐ”์ธ๋”ฉ ์‹œํ‚จ๋‹ค.

findViewById<TextView>(R.id.sample_text).apply {
    text = viewModel.userName
}

๋‹ค๋ฅธ ์˜ˆ์ œ๋ฅผ ๋ณด์ž.

๋ฐ์ดํ„ฐ๋ฐ”์ธ๋”ฉ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ Layout file์— ์ง์ ‘ ์œ„์ ฏ์— text๋ฅผ ๋„ฃ๋Š” ๋ฐฉ๋ฒ•์„ ๋ณด์—ฌ์ค€๋‹ค.
์ด ๋ฐฉ๋ฒ•์€ ์œ„์—์„œ ๋ณธ ์ฝ”๋“œ๋ฅผ ์—†์•จ ์ˆ˜ ์žˆ๋‹ค.
๋Œ€์‹ , @{} ๐Ÿ‘ˆ๐Ÿป ์ด๋Ÿฌํ•œ syntax๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋‚˜ํƒ€๋‚ผ ์ˆ˜ ์žˆ๋‹ค.

<TextView
    android:text="@{viewmodel.userName}" />

Benefits of Use

  • ๋ฐ”์ธ๋”ฉ ์ปดํฌ๋„ŒํŠธ๋Š” ์•กํ‹ฐ๋น„ํ‹ฐ์—์„œ ์ ํ˜€์ง€๊ฒŒ ๋˜์—ˆ๋˜ UI ํ”„๋ ˆ์ž„์›Œํฌ์™€ ๊ด€๋ จ๋œ ๋งŽ์€ ์ฝ”๋“œ๋ฅผ ์ค„์ผ ์ˆ˜ ์žˆ๊ณ , ๋” ๊ฐ„๋‹จํ•˜๊ฒŒ ํ˜น์€ ๋” ์‰ฝ๊ฒŒ ์œ ์ง€ ๋ณด์ˆ˜ ํ•  ์ˆ˜ ์žˆ๋‹ค.
  • NPE๊ณผ ๋ฉ”๋ชจ๋ฆฌ ๋ˆ„์ˆ˜๋ฅผ ๋ง‰๋Š”๋ฐ ๋„์›€์„ ์ฃผ๋Š” ๋“ฑ ์•ฑ์˜ ์„ฑ๋Šฅ์„ ๋†’์ผ ์ˆ˜ ์žˆ๋‹ค.

๐Ÿšธ ๋ฐ์ดํ„ฐ ๋ฐ”์ธ๋”ฉ์„ ์ฃผ์˜ํ•ด์„œ ์“ฐ์ž.


๊ตฌ๊ธ€ ๊ณต์‹ ์‚ฌ์ดํŠธ์— ๋‚˜์™€์žˆ๋Š” ๊ฒƒ ์ฒ˜๋Ÿผ, ๋‹จ์ˆœํžˆ findViewById()๋ฅผ ๋Œ€์ฒดํ•˜๊ธฐ ์œ„ํ•œ ๋ชฉ์ ์ด๋ผ๋ฉด dataBinding๋ณด๋‹จ ViewBinding์„ ๊ถŒํ•˜๊ณ  ์žˆ๋‹ค.
(๋ทฐ๋ฐ”์ธ๋”ฉ์ด ๋‚˜์˜จ ๋ชฉ์ ์ด ๋Œ€๋ถ€๋ถ„์˜ ๊ฐœ๋ฐœ์ž๋“ค์ด ๋ฐ์ดํ„ฐ๋ฐ”์ธ๋”ฉ์„ findViewById()๋Œ€์ฒด ์ˆ˜๋‹จ์œผ๋กœ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ๊ธฐ์— ๋‚˜์™”๋‹ค๊ณ  ํ•˜์˜€๋‹ค.)

ํ˜น์‹œ, ViewBinding๊ณผ DataBinding์˜ ์ฐจ์ด๊ฐ€ ๊ถ๊ธˆํ•˜๋‹ค๋ฉด
๋‹ค์Œ์˜ ํฌ์ŠคํŠธ๋ฅผ ๋ณด์ž. ๐Ÿ‘‰๐Ÿป ViewBinding VS DataBinding์ด์•ผ๊ธฐ


Using the DataBinding Library

์‚ฌ์šฉ์— ์•ž์„œ, ๋ชจ๋“  ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๊ฐ€ ๊ทธ๋ ‡๋“ฏ ์„ธํŒ…์„ ํ•ด์•ผํ•  ๊ฒƒ์ด๋‹ค.
build.gradleํŒŒ์ผ์—

android{
.
.
.
  dataBinding{ 
      enabled = true 
  }
}

์ด๋ ‡๊ฒŒ ํ•œ ์ค„ ์ถ”๊ฐ€ํ•ด์ฃผ์ž.

๐Ÿ‘‹ ํ˜น์‹œ.. gradle๋ฒ„์ „์ด

classpath "com.android.tools.build:gradle:4.1.0"

์ด๋ ‡๊ฒŒ 3.6๋ฒ„์ „์„ ๋„˜์–ด๊ฐ„๋‹ค๋ฉด

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

์ด๋Ÿฐ ์‹์œผ๋กœ ์ถ”๊ฐ€ํ•ด์ค˜์•ผ ํ•  ๊ฒƒ์ด๋‹ค.

Layout์— Bindingํ‘œํ˜„์„ ๋„ฃ์ž.

์ผ๋ฐ˜์ ์œผ๋กœ xml file์„ ์—ด์–ด๋ณด๋ฉด

<ConstraintLayout...
        xmlns:app="http://schemas.android.com/apk/res-auto">
    <!-- UI layout's root element -->
<ConstraintLayout/>

์ด๋Ÿฐ์‹์œผ๋กœ ๊ตฌ์„ฑ๋˜์–ด ์žˆ์„ ๊ฒƒ์ด๋‹ค.
๊ทธ๋Ÿผ ๋ ˆ์ด์•„์›ƒ ํŒŒ์ผ์˜ ๋ฃจํŠธ ํƒœ๊ทธ์— Layout์„ ์ถ”๊ฐ€ํ•ด์•ผ ํ•œ๋‹ค.
์ถ”๊ฐ€ํ•œ ์•„๋ž˜์˜ ์˜ˆ์‹œ๋ฅผ ๋ณด์ž.

<layout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto">
    <data>
        <variable
            name="viewmodel"
            type="com.myapp.data.ViewModel" />
    </data>
    <android.support.constraint.ConstraintLayout 		
        android:layout_width="match_parent" 		
        android:layout_height="match_parent"> 
        
    	<TextView 			
          android:id="@+id/tv_start"
          android:layout_width="wrap_content"
          android:layout_height="wrap_content"
          android:text="@{viewmodel.data}"
          tools:layout_editor_absoluteX="0dp"
          tools:layout_editor_absoluteY="0dp" />
</android.support.constraint.ConstraintLayout>


</layout>

๐Ÿ˜น data๋Š” ๊ฐ‘์ž๊ธฐ ์™œ ์ƒ๊ฒผ๋ƒ๊ณ ?

์œ„์˜ ์˜ˆ์‹œ์—์„œ data ํƒœ๊ทธ๋Š” ๋ทฐ๋ชจ๋ธ์„ ๊ฐ์ฒดํ™” ์‹œ์ผœ์„œ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๊ฒŒํ•œ๋‹ค.
'viewmodel'์˜ ๊ฐ์ฒด๋ช…์œผ๋กœ ๋„ํŠธ ์—ฐ์‚ฐ์ž๋ฅผ ํ†ตํ•ด ํด๋ž˜์Šค์˜ ๋ณ€์ˆ˜๋‚˜ ๋ฉ”์†Œ๋“œ์— ์ ‘๊ทผ ํ•  ์ˆ˜ ์žˆ๋‹ค.
์œ„์˜ ์˜ˆ์ œ์—์„œ viewmodel์— ์„ ์–ธ๋œ data๊ฐ’์„ ๊ฐ€์ ธ์™€์„œ tv_start์— ๋ฐ”์ธ๋”ฉ ์‹œ์ผœ์ค€๋‹ค.
ํด๋ž˜์Šค ๊ฐ์ฒดํ™”๋กœ ๋ ˆ์ด์•„์›ƒ์—์„œ ์œ„์ ฏ์˜ ์„ค์ •๊ฐ’์„ ๋ณ€๊ฒฝํ•จ์œผ๋กœ์จ ์†Œ์Šค์ฝ”๋“œ๋ฅผ ์ค„์ผ ์ˆ˜ ์žˆ๋Š” ๊ฒƒ์ด๋‹ค.

Binding Class ๋„ค์ด๋ฐ ๋ณ€๊ฒฝ

๋ ˆ์ด์•„์›ƒ์˜ ๋ฃจํŠธ ํƒœ๊ทธ๋ฅผ ์ด์šฉํ•ด์„œ ๋ณ€๊ฒฝํ•˜๋ฉด ๋ ˆ์ด์•„์›ƒ ํŒŒ์ผ ์ด๋ฆ„์„ ๊ธฐ์ค€์œผ๋กœ ํŒŒ์Šค์นผ ํ‘œ๊ธฐ๋ฒ•์— ๋”ฐ๋ผ ๋ฐ”์ธ๋”ฉ ํŒŒ์ผ์ด ์ƒ์„ฑ๋œ๋‹ค.
[๋ ˆ์ด์•„์›ƒ๋ช…]Binding ๐Ÿ‘ˆ๐Ÿป ์ด๋Ÿฌํ•œ ํ˜•์‹์œผ๋กœ ์ƒ๊ฒผ๋‹ค.
ex) activity_main.xml ๐Ÿ‘‰๐Ÿป ActivityMainBinding ์ด๋ ‡๊ฒŒ ๋œ๋‹ค.
๊ทผ๋ฐ ์ด๋Ÿฌํ•œ ์ด๋ฆ„ ํ‘œ๊ธฐ๋ฒ•์ด ์ข€ ๋ณ„๋กœ ์ผ ์ˆ˜ ์žˆ๋‹ค. ์—„์ฒญ๋‚˜๊ฒŒ ๊ธด ํด๋ž˜์Šค ์ด๋ฆ„์ด๋ฉด?
๊ทธ๋ž˜์„œ ์ปค์Šคํ…€์ด ๊ฐ€๋Šฅํ•˜๋‹ค.

<data
	class="Main">        
</data>

์œ„์™€ ๊ฐ™์ด class="๋ฐ”๊ฟ€ ์ด๋ฆ„"์„ ๋„ฃ์–ด์„œ ๋ฐ”์ธ๋”ฉ ์‹œํ‚ฌ ์ˆ˜ ์žˆ๋‹ค.
ํ—ท๊ฐˆ๋ฆฌ์ง€ ์•Š๊ฒŒ ์ž˜ ๋„ค์ด๋ฐํ•  ํ•„์š”๊ฐ€ ์žˆ๊ฒ ๋‹ค.


Work with Obsrevable data Objects

๐Ÿ‘€ ๊ด€์ฐฐ๊ฐ€๋Šฅํ•œ ๋ฐ์ดํ„ฐ ๊ฐ์ฒด์™€ ์“ฐ๊ธฐ ์ข‹๋‹ค.

  • DataBinding Library๋Š” ๋ฐ์ดํ„ฐ์˜ ๋ณ€๊ฒฝ ์‚ฌํ•ญ์„ ์‰ฝ๊ฒŒ ๊ด€์ฐฐํ•  ์ˆ˜ ์žˆ๋Š” ํด๋ž˜์Šค์™€ ๋ฉ”์„œ๋“œ๋ฅผ ๊ธฐ๋ณธ์œผ๋กœ ์ œ๊ณตํ•œ๋‹ค.
  • ๊ธฐ๋ณธ ๋ฐ์ดํ„ฐ๊ฐ€ ๋ณ€๊ฒฝ ๋  ๋•Œ UI ์ƒˆ๋กœ ๊ณ ์นจ์— ๋Œ€ํ•ด ๊ฑฑ์ •ํ•  ํ•„์š”๊ฐ€ ์—†๋‹ค.
  • ๋ณ€์ˆ˜ or ์†์„ฑ์„ ๊ด€์ฐฐ ๊ฐ€๋Šฅํ•˜๊ฒŒ ๋งŒ๋“ค ์ˆ˜ ์žˆ๋‹ค.
  • ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅด ์‚ฌ์šฉํ•˜๋ฉด ๊ฐœ์ฒด, ํ•„๋“œ, ์ปฌ๋ ‰์…˜์„ ๊ด€์ฐฐํ•  ์ˆ˜ ์žˆ๋‹ค.

Two-way data binding

  • ๋ฐ์ดํ„ฐ๋ฐ”์ธ๋”ฉ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋Š” ์–‘๋ฐฉํ–ฅ ๋ฐ์ดํ„ฐ ๋ฐ”์ธ๋”ฉ์ด๋‹ค.
  • ์ด ์œ ํ˜•์˜ ๋ฐ”์ธ๋”ฉ์— ์‚ฌ์šฉ๋˜๋Š” ํ‘œ๊ธฐ๋ฒ•์€ ์†์„ฑ์— ๋Œ€ํ•œ ๋ฐ์ดํ„ฐ ๋ณ€๊ฒฝ ์‚ฌํ•ญ์„ ์ˆ˜์‹ ํ•˜๊ณ  ๋™์‹œ์— ํ•ด๋‹น ์†์„ฑ์— ๋Œ€ํ•œ ์‚ฌ์šฉ์ž ์—…๋ฐ์ดํŠธ๋ฅผ ์ˆ˜์‹ ํ•˜๋Š” ๊ธฐ๋Šฅ์„ ์ง€์›ํ•œ๋‹ค.

Binding adapters

์—ฌ๊ธฐ์„œ ์ •๋ง ๊ธฐ๋˜ฅ์ฐฌ ๊ธฐ๋Šฅ์ด ํ•˜๋‚˜ ๋‚˜์˜จ๋‹ค.๐Ÿ‘

  • ๋ชจ๋“  ๋ ˆ์ด์•„์›ƒ ํ‘œํ˜„์‹๋งˆ๋‹ค, ํ•ด๋‹น ์†์„ฑ ๋˜๋Š” ๋ฆฌ์Šค๋„ˆ๋ฅผ ์„ค์ •ํ•˜๋Š”๋ฐ ํ•„์š”ํ•œ framework ํ˜ธ์ถœ์„ ๋งŒ๋“œ๋Š” ๋ฐ”์ธ๋”ฉ ์–ด๋Œ‘ํ„ฐ๊ฐ€ ์กด์žฌํ•œ๋‹ค.
  • ์˜ˆ๋ฅผ ๋“ค์ž๋ฉด, BindingAdapter๋Š” setText() ๋ฉ”์„œ๋“œ ํ˜ธ์ถœํ•˜์—ฌ text์†์„ฑ์„ ์„ค์ •ํ•˜๊ฑฐ๋‚˜ setOnClickListener() ๋ฉ”์„œ๋“œ๋ฅผ ํ˜ธ์ถœํ•˜์—ฌ ํด๋ฆญ ๋ฆฌ์Šค๋„ˆ ์ด๋ฒคํŠธ๋ฅผ ์ถ”๊ฐ€ํ•  ์ˆ˜๋„ ์žˆ๋‹จ๊ฑฐ๋‹ค.๐Ÿ™Œ
  • android.databinding.adapter ํŒจํ‚ค์ง€ ๋‚ด์—์„œ ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•˜๋‹ค
  • ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์‚ฌ์šฉ์ž ์ง€์ • ์–ด๋Œ‘ํ„ฐ๋„ ์ถฉ๋ถ„ํžˆ ๋งŒ๋“ค ์ˆ˜ ์žˆ๋‹ค.
@BindingAdapter("app:goneUnless")
fun goneUnless(view: View, visible: Boolean) {
    view.visibility = if (visible) View.VISIBLE else View.GONE
}

๋ ˆ์ด์•„์›ƒ์—์„ 

<TextView
          layout_width="wrap_content"
          layout_height="wrap_content"
          ...
          app:goneUnless="@{true}" //์ด๋ ‡๊ฒŒ ์“ฐ๋ฉด ๋œ๋‹ค.
          />

์ด ์–ผ๋งˆ๋‚˜ ์‰ฝ๊ฒŒ ์“ฐ์ด๋Š”๊ฐ€..๐Ÿคฉ


profile
developer
post-custom-banner

0๊ฐœ์˜ ๋Œ“๊ธ€