Android/Android์˜ ๋ชจ๋“  ๊ฒƒ

๐Ÿ‘‹Android์˜ ๋ชจ๋“  ๊ฒƒ : 1๏ธโƒฃMVVM์„ ์œ„ํ•œ Databinding, LiveData ๊ฐœ๋…๊ณผ ์˜ˆ์ œ

DevGoni 2022. 4. 26. 14:19
728x90

https://goni95.tistory.com/173

 

๐Ÿ‘‹Android์˜ ๋ชจ๋“  ๊ฒƒ | Droid Knights 2021

๋ชฉ  ์ฐจ ์˜ˆ์ œ Android ๐Ÿ‘‹Android์˜ ๋ชจ๋“  ๊ฒƒ : 1๏ธโƒฃAndroid, 2๏ธโƒฃAndroid SDK, 3๏ธโƒฃPlatform Architecture ๐Ÿ‘‹Android์˜ ๋ชจ๋“  ๊ฒƒ ๊ฐœ๋… : 1๏ธโƒฃApp Manifest, 2๏ธโƒฃAndroid Context, 3๏ธโƒฃApp Components 1 O ๐Ÿ‘‹An..

goni95.tistory.com

 

 

Android์—์„œ ํ”„๋กœ์ ํŠธ๋ฅผ MVVM ์•„ํ‚คํ…์ฒ˜ ํŒจํ„ด์œผ๋กœ ์„ค๊ณ„ํ•˜๊ธฐ ์œ„ํ•ด ์•Œ์•„๋ณด๋ฉด ViewModel์ด View์— ๋Œ€ํ•œ ์˜์กด์„ฑ์„ ๊ฐ–์ง€ ์•Š๊ณ  ๋Š์Šจํ•˜๊ฒŒ ์—ฐ๊ฒฐ๋˜๋„๋ก Databinding ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๊ฐ€ ํ•„์ˆ˜์ ์œผ๋กœ ์‚ฌ์šฉ๋œ๋‹ค๋Š” ๋ง๊ณผ ํ•จ๊ป˜ ViewModel์ด ๋ฐ์ดํ„ฐ์˜ ๋ณ€๊ฒฝ์„ ์•Œ๋ฆฌ๋ฉด View๊ฐ€ ์ด๋ฅผ ๊ด€์ฐฐํ•˜๊ณ  ์žˆ๋‹ค UI๋ฅผ ์—…๋ฐ์ดํŠธ ํ•˜๋„๋ก LiveData, Rx, Coroutine Flow ๋“ฑ์ด ์–ธ๊ธ‰๋ฉ๋‹ˆ๋‹ค.

 

Databinding๊ณผ LiveData ๋ชจ๋‘ Jetpack์˜ ์•„ํ‚คํ…์ฒ˜(Architecture) ์นดํ…Œ๊ณ ๋ฆฌ์— ํฌํ•จ๋ฉ๋‹ˆ๋‹ค.

 

1๏ธโƒฃ Databinding(๋ฐ์ดํ„ฐ ๋ฐ”์ธ๋”ฉ)

๋ฐ์ดํ„ฐ ๋ฐ”์ธ๋”ฉ์€ Android 4.0 (API Level : 14) ์ด์ƒ ์•ˆ๋“œ๋กœ์ด๋“œ ๊ธฐ๊ธฐ๋ถ€ํ„ฐ ์ง€์›ํ•ฉ๋‹ˆ๋‹ค.

๋ฐ์ดํ„ฐ ๋ฐ”์ธ๋”ฉ์„ ์‚ฌ์šฉํ•˜๋ ค๋ฉด ์•ˆ๋“œ๋กœ์ด๋“œ ์ŠคํŠœ๋””์˜ค 1.5.0 ์ด์ƒ์˜ ๋ฒ„์ „์„ ์‚ฌ์šฉํ•ด์•ผ ํ•˜๋ฉฐ, ์ตœ์‹ ์˜ ๋ฐ์ดํ„ฐ ๋ฐ”์ธ๋”ฉ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์‚ฌ์šฉํ•˜๋ ค๋ฉด ์•ˆ๋“œ๋กœ์ด๋“œ ์ŠคํŠœ๋””์˜ค์™€ SDK ๋ฒ„์ „์„ ์ตœ์‹  ์ƒํƒœ๋กœ ์œ ์ง€ํ•˜๋Š” ๊ฒƒ์ด ์ข‹์Šต๋‹ˆ๋‹ค.

 

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

 

๋ฐ์ดํ„ฐ ๋ฐ”์ธ๋”ฉ์„ ํ†ตํ•ด boilerplate code๋ฅผ ์ค„์ด๊ณ  ์„ฑ๋Šฅ ํ–ฅ์ƒ๊ณผ ๋ฉ”๋ชจ๋ฆฌ ๋ˆ„์ˆ˜ ๋ฐ Null Pointer Exception์„ ๋ฐฉ์ง€ ๊ทธ๋ฆฌ๊ณ  MVVM ์•„ํ‚คํ…์ฒ˜ ํŒจํ„ด ์„ค๊ณ„๋ฅผ ์œ„ํ•ด ์‚ฌ์šฉํ•ด ํ…Œ์ŠคํŠธ ์šฉ์ด์„ฑ, ์œ ์ง€๋ณด์ˆ˜์„ฑ์„ ๋†’์ผ ์ˆ˜ ์žˆ์ง€๋งŒ ํด๋ž˜์Šค ํŒŒ์ผ ์ˆ˜๊ฐ€ ์ฆ๊ฐ€ํ•˜๊ณ  ๋นŒ๋“œ ์†๋„๊ฐ€ ๋Š๋ ค์งˆ ์ˆ˜ ์žˆ๋Š” ๋‹จ์ ์ด ์žˆ์Šต๋‹ˆ๋‹ค.

 

๊ธฐ์กด์—๋Š” TextView์— ViewModel๋กœ ๋ถ€ํ„ฐ title์ด๋ผ๋Š” ๋ฌธ์ž์—ด์„ ํ”„๋กœํผํ‹ฐ๋ฅผ ์ฐธ์กฐํ•˜์—ฌ ๋ณ€๊ฒฝํ•ด์•ผ ํ–ˆ์Šต๋‹ˆ๋‹ค.

val tileTv : TextView = findViewById(R.id.titleTextView)
titleTv.text = viewModel.title

 

๋ฐ์ดํ„ฐ ๋ฐ”์ธ๋”ฉ์„ ์‚ฌ์šฉํ•˜๋ฉด ๋ ˆ์ด์•„์›ƒ ํŒŒ์ผ์—์„œ ์ง์ ‘ ๋ฐ์ดํ„ฐ ๋ฐ”์ธ๋”ฉ ํ‘œํ˜„์‹์„ ์‚ฌ์šฉํ•ด ์„ ์–ธํ˜• ํ”„๋กœ๊ทธ๋ž˜๋ฐ ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

<?xml version="1.0" encoding="utf-8"?>
<layout  
    ...>
    
    <data>
        <variable
            name="viewModel"
            type="sang.gondroid.databindingexample.MainViewModel" />
    </data>

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

        <TextView
            android:id="@+id/TitleTextView"
            ...
            android:text="@{viewModel.title}"
            ... />

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

 

 

1. ๋ฐ์ดํ„ฐ ๋ฐ”์ธ๋”ฉ ์„ค์ •

๋ชจ๋“ˆ ์ˆ˜์ค€์˜ build.gradle์— ์ถ”๊ฐ€ํ•ฉ๋‹ˆ๋‹ค.

// 1. ์•ˆ๋“œ๋กœ์ด๋“œ ์ŠคํŠœ๋””์˜ค 4.0 ๋ฏธ๋งŒ์ธ ๊ฒฝ์šฐ 
android {
    ...
    buildFeatures {
        dataBinding = true
    }
}


// 2. ์•ˆ๋“œ๋กœ์ด๋“œ ์ŠคํŠœ๋””์˜ค 4.0 ์ด์ƒ์ธ ๊ฒฝ์šฐ
plugins {
    ...
    id 'kotlin-kapt'    // databinding [you should apply the kotlin-kapt plugin. / bindingAdapter]
}

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

 

 

2. ๋ฐ”์ธ๋”ฉ ํด๋ž˜์Šค ์ƒ์„ฑ

๋ฐ์ดํ„ฐ ๋ฐ”์ธ๋”ฉ์€ ๋ ˆ์ด์•„์›ƒ์˜ ๋ณ€์ˆ˜์™€ ๋ทฐ๋ฅผ ์ฐธ์กฐํ•  ์ˆ˜ ์žˆ๋Š” ๋ฐ”์ธ๋”ฉ ํด๋ž˜์Šค๋ฅผ ์ƒ์„ฑํ•˜๋ฉฐ ๋ฐ”์ธ๋”ฉ ํด๋ž˜์Šค๋Š” ViewDataBinding์„ ์ƒ์†ํ•ฉ๋‹ˆ๋‹ค.

 

xml ๋ ˆ์ด์•„์›ƒ ํŒŒ์ผ์˜ ์ƒ์œ„ ๋ ˆ์ด์•„์›ƒ์„ ํƒœ๊ทธ๋กœ ๊ฐ์‹ธ๋ฉด ์ž๋™์œผ๋กœ ๋ฐ”์ธ๋”ฉ ํด๋ž˜์Šค๊ฐ€ ์ƒ์„ฑ๋˜๋Š”๋ฐ ๋ฐ”์ธ๋”ฉ ํด๋ž˜์Šค ์ด๋ฆ„์€ ๋ ˆ์ด์•„์›ƒ ํŒŒ์ผ๋ช…์„ ํŒŒ์Šค์นผ ์ผ€์ด์Šค๋กœ ๋ณ€๊ฒฝํ•œ ๋’ค Binding ์ ‘๋ฏธ์–ด๋ฅผ ๋ถ™์—ฌ ์ƒ์„ฑ๋ฉ๋‹ˆ๋‹ค.

<?xml version="1.0" encoding="utf-8"?>
<layout>
    
    <androidx.constraintlayout.widget.ConstraintLayout
        ...>
        
        ...

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

tip : ๋ ˆ์ด์•„์›ƒ์— ๋Œ€ํ•œ ํ‘œํ˜„์€ ***Binding ํด๋ž˜์Šค๋กœ ์ž‘์„ฑ๋˜์ง€๋งŒ ์‹ค์ œ ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง ์ถ”์  ๋˜๋Š” ๋””๋ฒ„๊น…์„ ํ•˜๋ ค๋ฉด ***BindingImpl์„ ์ฐธ์กฐํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

 

 

3. ๋ฐ”์ธ๋”ฉ ํด๋ž˜์Šค๋กœ ๋ฐ”์ธ๋”ฉ ๊ฐ์ฒด ์ƒ์„ฑํ•˜๊ธฐ

DataBindingUtil ํด๋ž˜์Šค์˜ ๋ฉ”์„œ๋“œ๋ฅผ ํ™œ์šฉํ•ด ๋ฐ”์ธ๋”ฉ ๊ฐ์ฒด ์ƒ์„ฑ

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.lifecycleOwner = this
    }
}
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
saveInstanceState : Bundle?) : View? {
   
    binding = DataBindingUtil.inflate(inflater, R.layout.fragment_main, container, false)
    binding.lifecycleOwner = this
    return binding.root
}

 

inflate() ๋ฉ”์„œ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋ ˆ์ด์•„์›ƒ ์ „๊ฐœ์™€ ํ•จ๊ป˜ ๋ฐ”์ธ๋”ฉ ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•˜๋Š” ๋ฐฉ๋ฒ•

class MainActivity : AppCompatActivity() {
    private lateinit var binding: ActivityMainBinding

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        binding = ActivityMainBinding.inflate(layoutInflater)
        setContentView(binding.root)
        binding.lifecycleOwner = this
    }
}
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
saveInstanceState : Bundle?) : View? {
   
    binding = MainFragmentBinding.inflate(inflater, container, false)
    // binding = MainFragmentBinding.inflate(inflater)
    // binding = MainFragmentBinding.inflate(layoutInflater)
    binding.lifecycleOwner = this
    return binding.root
}

*์ „๊ฐœ : xml ๋ ˆ์ด์•„์›ƒ ํŒŒ์ผ๊ณผ ์ž์‹ View์˜ ์†์„ฑ์„ ์ฝ์–ด ์‹ค์ œ View ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•˜๋Š” ๋™์ž‘์„ ์˜๋ฏธํ•ฉ๋‹ˆ๋‹ค.

 

 

4. ๋ฐ”์ธ๋”ฉ ํด๋ž˜์Šค ์ด๋ฆ„ ์ •์˜

๊ธฐ๋ณธ์ ์œผ๋กœ ๋ฐ”์ธ๋”ฉ ํด๋ž˜์Šค ์ด๋ฆ„์€ ๋ ˆ์ด์•„์›ƒ ํŒŒ์ผ๋ช…์„ ๋ฐ”ํƒ•์œผ๋กœ ์ƒ์„ฑ๋˜์ง€๋งŒ ์ด๋ฅผ ๋ณ€๊ฒฝํ•˜๊ณ  ์‹ถ์€ ๊ฒฝ์šฐ <data> ํƒœ๊ทธ ๋‚ด์— class ์†์„ฑ์„ ์‚ฌ์šฉํ•˜์—ฌ ๋ณ€๊ฒฝํ•˜๋ฉด ๋ฉ๋‹ˆ๋‹ค.

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

    <data class="MainActivityBindingClass"/>

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

        ...

    </androidx.constraintlayout.widget.ConstraintLayout>
</layout>
class MainActivity : AppCompatActivity() {
    private lateinit var binding: MainActivityBindingClass

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        binding = DataBindingUtil.setContentView(this, R.layout.activity_main)
        binding.lifecycleOwner = this
    }
}

 

 

4. ID๋กœ View ์ฐธ์กฐ

๋ฐ”์ธ๋”ฉ ํด๋ž˜์Šค ๋‚ด๋ถ€์—์„œ ๋ฏธ๋ฆฌ findViewByID()๋ฅผ ํ˜ธ์ถœํ•œ ๊ฒฐ๊ณผ๋ฅผ ์บ์‹ฑํ•ด ๋‘๊ธฐ ๋•Œ๋ฌธ์— ๋ฐ”์ธ๋”ฉ ํด๋ž˜์Šค๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด findViewById()๋ฅผ ํ˜ธ์ถœํ•  ํ•„์š”๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค.

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

    <data class="MainActivityBindingClass"/>

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

        <TextView
            android:id="@+id/titleTextView"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintLeft_toLeftOf="parent"
            app:layout_constraintRight_toRightOf="parent"
            app:layout_constraintTop_toTopOf="parent" />

    </androidx.constraintlayout.widget.ConstraintLayout>
</layout>
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.lifecycleOwner = this

        binding.titleTextView.text = "์•ˆ๋…•"
    }
}

 

 

5. ๋ ˆ์ด์•„์›ƒ ๋ณ€์ˆ˜ ์„ ์–ธ๊ณผ ํด๋ž˜์Šค ์ฐธ์กฐ

๋ ˆ์ด์•„์›ƒ์— ๋ณ€์ˆ˜๋ฅผ ์„ ์–ธํ•˜๊ณ  ๋ณ€์ˆ˜์— ๊ฐ’์„ ๋Œ€์ž…ํ•˜๋Š” ๊ฒƒ์œผ๋กœ View์˜ ์ƒํƒœ๋ฅผ ๋ณ€๊ฒฝํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๋ณ€์ˆ˜๋ฅผ ์„ ์–ธํ•˜๊ธฐ ์œ„ํ•ด์„  <layout> ํƒœ๊ทธ ๋‚ด์˜ <data> ํƒœ๊ทธ๋ฅผ ์‚ฌ์šฉํ•˜๋ฉฐ <data> ํƒœ๊ทธ ๋‚ด์—์„œ ๋ณ€์ˆ˜๋ฅผ <variable> ํƒœ๊ทธ๋ฅผ ์‚ฌ์šฉํ•ด ์„ ์–ธํ•˜๋ฉด ๋ฉ๋‹ˆ๋‹ค.

<variable> ํƒœ๊ทธ๋Š” ๋ณ€์ˆ˜์˜ ์ด๋ฆ„์„ ์ •์˜ํ•˜๋Š” name๊ณผ ๋ณ€์ˆ˜์˜ ์ž๋ฃŒํ˜•์„ ์ •์˜ํ•˜๋Š” type ๋‘ ์†์„ฑ์„ ๊ฐ–์Šต๋‹ˆ๋‹ค.

 

์ฐธ์กฐํ•˜๊ณ  ์‹ถ์€ ํด๋ž˜์Šค๋ฅผ ๋ ˆ์ด์•„์›ƒ ํŒŒ์ผ์— ๋ถˆ๋Ÿฌ์˜ค๋ ค๋ฉด <import> ํƒœ๊ทธ๋ฅผ ์‚ฌ์šฉํ•ด ์„ ์–ธํ•˜๋ฉฐ ์ž๋ฃŒํ˜•์„ ์ •์˜ํ•˜๋Š” type ์†์„ฑ์„ ๊ฐ–์Šต๋‹ˆ๋‹ค.

๋งŒ์•ฝ ์ด๋ฆ„์ด ๋™์ผํ•œ ์„œ๋กœ ๋‹ค๋ฅธ ํด๋ž˜์Šค๋ฅผ ๋ถˆ๋Ÿฌ์˜ค๋Š” ๊ฒฝ์šฐ alias ์†์„ฑ์„ ํ†ตํ•ด ๋ ˆ์ด์•„์›ƒ ๋‚ด์—์„œ class ๋ช… ๋Œ€์‹  ์‚ฌ์šฉํ•  ์ด๋ฆ„์„ ์„ค์ •ํ•˜๋ฉด ๋ฉ๋‹ˆ๋‹ค.

 

ViewModel์„ ์‚ฌ์šฉํ•ด View์˜ ์ƒํƒœ๋ฅผ ๋ณ€๊ฒฝํ•˜๋Š” ์˜ˆ์ œ์ž…๋‹ˆ๋‹ค.

<?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="viewModel"
            type="sang.gondroid.databindingexample.MainViewModel" />
    </data>

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

        <TextView
            android:id="@+id/titleTextView"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@{viewModel.title}"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintLeft_toLeftOf="parent"
            app:layout_constraintRight_toRightOf="parent"
            app:layout_constraintTop_toTopOf="parent" />

    </androidx.constraintlayout.widget.ConstraintLayout>
</layout>
class MainActivity : AppCompatActivity() {
    private lateinit var viewModel: MainViewModel
    private lateinit var binding: ActivityMainBinding

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        binding = DataBindingUtil.setContentView(this, R.layout.activity_main)
        binding.lifecycleOwner = this

        viewModel = ViewModelProvider(this) [MainViewModel::class.java]
        binding.viewModel = viewModel
    }
}
class MainViewModel : ViewModel() {
    private val _title = MutableLiveData<String>()
    val title : LiveData<String>
        get() = _title

    init {
        viewModelScope.launch {
            for (i in 0.. 1000) {
                delay(1000)
                _title.value = "ํƒ€์ดํ‹€ $i"
            }
        }
    }
}

 

6. ๋ฐ”์ธ๋”ฉ ํ‘œํ˜„์‹

xml ๋ ˆ์ด์•„์›ƒ์—์„œ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ์—ฐ์‚ฐ์ž, Collections ํด๋ž˜์Šค๋ฅผ ์‚ฌ์šฉํ•œ ํ‘œํ˜„์‹์„ ์•Œ์•„๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

์ค‘์š”ํ•œ ์ ์€ ๋ฐ”์ธ๋”ฉ ํ‘œํ˜„์‹ ์ž‘์„ฑ ์‹œ <๋Š” &lt; ๋กœ ์ž…๋ ฅํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

  • ์‚ฐ์ˆ  ์—ฐ์‚ฐ์ž : +  -  /  *  %
  • ๋ฌธ์ž์—ด ์—ฐ๊ฒฐ : +
  • ๋…ผ๋ฆฌ ์—ฐ์‚ฐ์ž : &&  ||
  • ๋น„ํŠธ ์—ฐ์‚ฐ์ž : &  |  ^
  • ๋‹จํ•ญ ์—ฐ์‚ฐ์ž : +  -  !  ~
  • ๋น„ํŠธ ์ด๋™ ์—ฐ์‚ฐ์ž : >>  >>>  <<
  • ๋น„๊ต ์—ฐ์‚ฐ์ž : == >  <  >=  <=
  • Null ๋ณ‘ํ•ฉ ์—ฐ์‚ฐ์ž : ??
<data>
    <variable
        name="viewModel"
        type="sang.gondroid.databindingexample.MainViewModel" />

    <import type="android.view.View"/>
    <import type="sang.gondroid.databindingexample.View" alias="MyView"/>
 
    <variable
        name="index"
        type="Integer" /> 
    <import type="java.util.List"/>
    <variable
        name="list"
        type="List&lt;String>" />

    <import type="java.util.Map"/>
    <variable
        name="map"
        type="Map&lt;String, String>" />
</data>

android:text="@{String.valueOf(viewModel.index + 1}"

// import ํƒœ๊ทธ๋ฅผ ํ†ตํ•ด View ํด๋ž˜์Šค๋ฅผ ์ฐธ์กฐ
android:visibility="@{viewModel.num > 10 ? View.GONE : View.VISIBLE}"
android:text='@{"name : " + viewModel.name}'
android:text="@{viewModel.name ?? viewModel.nullValue}"

<!-- 
1. string ๋ฆฌ์†Œ์Šค ์ฐธ์กฐํ•˜๊ธฐ(strings.xml)
   <string name="nameFormat">%s %s</string>
   <string name="nameFormat">%2$s %1$s</string>    // ๋งค๊ฐœ๋ณ€์ˆ˜ ์ˆœ์„œ ๋ณ€๊ฒฝ ๊ฐ€๋Šฅ
-->
android:text="@{@string/nameFormat(firstName, lastName)}"

android:text="@{list[index]}"
android:text="@{list[0]}"

android:text='@{map["ad"]}'
android:text="@{map[`ad`]}"

 

2๏ธโƒฃ LiveData

 

 

 

3๏ธโƒฃ