#1 ๊ฐ์
#1-1 LiveData
LiveData ๊ฐ์ | Android ๊ฐ๋ฐ์ | Android Developers
LiveData๋ฅผ ์ฌ์ฉํ์ฌ ์๋ช ์ฃผ๊ธฐ๋ฅผ ์ธ์ํ๋ ๋ฐฉ์์ผ๋ก ๋ฐ์ดํฐ๋ฅผ ์ฒ๋ฆฌํฉ๋๋ค.
developer.android.com
LiveData. ๋ฌธ์์ ์ธ ์ ์๋ Data์ ๋ณ๊ฒฝ์ ๊ด์ฐฐํ ์ ์๋ ๋ฐ์ดํฐ ํ๋ ํด๋์ค๊ณ , ๋ง ๊ทธ๋๋ก ํด์ํ๋ฉด ์ด์์๋(live) ๋ฐ์ดํฐ(data)๋ค. Activity, Fragment, Service์ ์๋ Data, ์๋ฅผ ๋ค์ด ์ด๋ค ๋ณ์ A๊ฐ ์๊ณ ๊ทธ A๋ฅผ ์ด๋ค TextView์ ํ์ํด๋์ ์ํฉ์ ์๊ฐํด ๋ณด์. A์ ๊ฐ์ด ๋ณ๊ฒฝ๋๋ฉด, TextView์ ๋ณ๊ฒฝ๋ A๊ฐ์ ๋ค์ ํ ๋นํด์ผํ๋ค. LiveData๋ ๊ทธ ๊ท์ฐฎ์ ํ ๋น ๊ณผ์ ์ ํ๋ก๊ทธ๋๋จธ๊ฐ ์๋ตํ ์ ์๊ฒ ๋ง๋ค์ด์ค๋ค. LiveData๋ ๋ณ๊ฒฝ๋ A์ ๊ฐ์ ํ๋ฉด(View)์ ์๋ฌต์ ์ผ๋ก ์
๋ฐ์ดํธํ๋ค. ์ด๊ธฐ ์ค์ ๋ง ๋ง์ณ๋์ผ๋ฉด ๊ทธ ์ดํ๋ก๋ 'binding.text = getA().toString()'์ ๊ฐ์ ์ฝ๋๋ฅผ ์๋์ผ๋ก ์ํํ๋ค๋ ์๊ธฐ๋ค. ์์์ ๋ณ๊ฒฝ๋ ์์ ์ ๊ฐ์ View์ ๊ฐฑ์ ํ๋ค๋, ๋ง ๊ทธ๋๋ก ๋ฐ์ดํฐ๊ฐ ์ด์์๋ค๊ณ ํํํ ๋งํ๋ค.
#1-2 LiveData๋ฅผ ์ ๋ชฉ์์ผ๋ณผ ์ฑ
[Android] View Model - ๊ธฐ์ด
#1 View Model์ ํ์์ฑ#1-1 ์์ ๋ฒํผ์ ๋๋ฅด๋ฉด TextView์ text๊ฐ 1์ฉ ์ฆ๊ฐํ๋ ์์ ์ฑ์ด๋ค. MainActivity.kt ์ฝ๋๋ ๋ค์๊ณผ ๊ฐ๋ค. // package com.example.viewmodelbasics import androidx.appcompat.app.AppCompatActivity import andro
kenel.tistory.com
์ด์ , ์ ๊ฒ์๊ธ์ '#3 ์์ฑ๋ ์ฑ'์ด LiveData๋ฅผ ์ฌ์ฉํ๊ฒ ์์ ํด๋ณธ๋ค. ์๋์ ์๋ ๋ชจ๋ ์ฝ๋๋ ์ด ์ฑ์ ์ฝ๋๋ฅผ ๊ธฐ๋ฐ์ผ๋ก ์์ ํ ๊ฒ์ด๋ค.
#2 LiveData ์ฌ์ฉํ๊ธฐ
#2-1 build.gradle.kts (Module :app) ์์
plugins {
...
}
android {
...
}
dependencies {
...
val lifecycle_version = "2.5.1"
implementation("androidx.lifecycle:lifecycle-livedata-ktx:$lifecycle_version") // LiveData
}
๋จผ์ , LiveData ์ถ์ํด๋์ค๋ฅผ ๋ถ๋ฌ์ค๊ธฐ ์ํ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ถ๊ฐํ๋ค. ๋ชจ๋ ์์ค gradle์ ์์ ๊ฐ์ ๊ตฌ๋ฌธ์ ์ถ๊ฐํ๋ค. ํด๋น ๊ตฌ๋ฌธ์ ์ฌ๊ธฐ์์ ๊ฐ์ ธ์จ ๊ตฌ๋ฌธ์ด๋ค.
#2-2 MainActivityViewModel.kt ์์
...
import androidx.lifecycle.MutableLiveData
...
class MainActivityViewModel : ViewModel() {
private var count : MutableLiveData<Int> = MutableLiveData(0)
fun getCurrentCount(): MutableLiveData<Int> {
return count
}
fun updateCount(){
count.value = (count.value)?.plus(1)
}
}
๋ณ์ count๋ฅผ Intํ์ด ์๋๋ผ, MutableLiveData<Int>ํ์ผ๋ก ๋ณ๊ฒฝํ๋ค. ํด๋์ค MutableLiveData๋ ์ถ์ํด๋์ค์ธ LiveData์ subclass๋ค. MutableMap๊ณผ Map์ ๊ด๊ณ์ ๊ฐ๋ค. ์ถ์ํด๋์ค๋ ๊ฐ์ฒด๋ฅผ ์์ฑํ ์ ์๊ธฐ์ MutableLiveData์ ๊ฐ์ฒด๋ก ๋ง๋ ๊ฒ์ด๋ค.
getCurrentCount()์ ๋ฐํํ์ ์์ ํ๋ค. getUpdatedCount()๋ updateCount()๋ก ์ด๋ฆ์ ๋ฐ๊พธ๊ณ ๋ด์ฉ๋ ๋ณ๊ฒฝํ๋ค. count.value += 1๊ณผ ๊ฐ์ด ์งง๊ฒ ์ ์ ์ ์๋ ์ด์ ๋ count.value๊ฐ null๊ฐ์ผ ๊ฐ๋ฅ์ฑ์ด ์๊ธฐ ๋๋ฌธ์ด๋ค. ๋ฐ๋ผ์ null-safe ์ฐ์ฐ์ ์ํํ๋ plus() ํจ์๋ฅผ ์ฌ์ฉํ๋ค. count.value๊ฐ null์ด๋ผ๋ฉด .plus(1)์ ํธ์ถ๋์ง ์์ ๊ฒ์ด๋ค.
MainActivity.kt๋ฅผ ์์ ํ๊ธฐ ์ ์ LiveData๊ฐ ์ด๋ป๊ฒ '์ด์์์(Live) ์ ์๋์ง' ์์๋ณธ๋ค.
#2-3 LiveData.observe() ์ดํด๋ณด๊ธฐ
...
public abstract class LiveData<T> {
...
@MainThread
public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<? super T> observer) {
assertMainThread("observe");
if (owner.getLifecycle().getCurrentState() == DESTROYED) {
// ignore
return;
}
LifecycleBoundObserver wrapper = new LifecycleBoundObserver(owner, observer);
ObserverWrapper existing = mObservers.putIfAbsent(observer, wrapper);
if (existing != null && !existing.isAttachedTo(owner)) {
throw new IllegalArgumentException("Cannot add the same observer"
+ " with different lifecycles");
}
if (existing != null) {
return;
}
owner.getLifecycle().addObserver(wrapper);
}
...
}
๋น์ฐํ, LiveData๊ฐ ์ ๋ง๋ก ์ด์์์๋ฆฌ๋ ์๋ค. ๊ทธ๋ ๋ค๋ฉด LiveData๋ ์ด๋ป๊ฒ ๋ณ๊ฒฝ๋ ์์ ์ ๊ฐ์ View์ ๊ฐฑ์ ํ๋๊ฐ? ๋ฐ๋ก LiveData.observe() ๋ฉ์๋์ ์ํด์๋ค. 'observe'๋ผ๋ ๋จ์ด ์ ์ ๊ทธ๋๋ก, LiveData์ ๋ณํ๋ฅผ '๊ด์ฐฐ'ํ๋ ๋ฉ์๋๋ค. ์ด ๋ฉ์๋๋ ์ฒซ๋ฒ์งธ ์ธ์๋ก LifecycleOwner, ๋๋ฒ์งธ ์ธ์๋ก Observer๋ฅผ ๋ฐ๋๋ค.
LifecycleOwner ์ธํฐํ์ด์ค๋ ๋จ์ผ ๋ฉ์๋ ์ธํฐํ์ด์ค๋ค. ์ด๋ Activity, Fragment, Service์ ๊ฐ์ด ์๋ช
์ฃผ๊ธฐ(Lifecycle)๋ฅผ ์์ ํ(Owner) ํด๋์ค ์ ๋ถ๊ฐ ๊ตฌํ(implement)ํ๊ณ ์๋ ์ธํฐํ์ด์ค๋ค. ์ด ์ธํฐํ์ด์ค์ ๋จ์ผ ๋ฉ์๋๋ LifecycleOwner.getLifecycle(): LifeCycle๋ก ์๋ช
์ฃผ๊ธฐ๋ฅผ ๋ฐํํ๋ค. ์ด ์ธ์์ ์กด์ฌ ์ด์ ๋, LivaData์ ๋ฉ๋ชจ๋ฆฌ ๋์ ๋ฐฉ์ง๋ฅผ ์ํจ์ด๋ค. LiveData์ ๋ชฉ์ ์ ๋ณ๊ฒฝ๋ ์์ ์ ๊ฐ์ View์ ๊ฐฑ์ ํ๋ ๊ฒ์ด๋ค. ๋ฐ๋ผ์, View์ LiveData๊ฐ ๋
ธ์ถ๋๋ ์ํ๊ฐ ์๋๋ผ๋ฉด, ๊ตณ์ด ๊ฐฑ์ ์ ํ๋ฉฐ ์์๋ญ๋น๋ฅผ ํ ํ์๊ฐ ์๋ค. ๋ง์น ์จ๊ฒจ์ง TextView์ ๊ฐ์ ํ์ํ๋ ๊ฒ๊ณผ ๊ฐ์ ํ์๊ธฐ ๋๋ฌธ์ด๋ค. ๊ทธ๋ฆฌ๊ณ View์ LiveData๊ฐ ๋
ธ์ถ๋๊ณ ์๋์ง ์๋์ง๋ ์๋ช
์ฃผ๊ธฐ๋ฅผ ์ฐธ์กฐ(Lifecycle.getCurrentState())ํด ์ ์ ์๋ค.
๋๋ฒ์งธ ์ธ์์ธ Observer ์ธํฐํ์ด์ค ๋ํ ๋จ์ผ ๋ฉ์๋ ์ธํฐํ์ด์ค๋ค. ๊ทธ ๋จ์ผ ๋ฉ์๋๋ Observer<T>.onChanged(value: T)๋ก, LiveData ๊ฐ์ฒด์ ๋ฐ์ดํฐ ๋ณ๊ฒฝ ์ ๋ฐ์ํ๋ ์์
์ ์ ์ํ๋ค.
์ด LiveData.observe()๋ฅผ MainActivity.kt์์ ๊ตฌํํด๋ณด๊ฒ ๋ค.
#2-4 MainActivity.kt ์์
...
import androidx.lifecycle.Observer
...
class MainActivity : AppCompatActivity() {
...
override fun onCreate(savedInstanceState: Bundle?) {
...
val countObserver = object : Observer<Int> {
override fun onChanged(newValue: Int) {
binding.countText.text = newValue.toString()
}
}
viewModel.getCurrentCount().observe(this, countObserver)
binding.countButton.setOnClickListener {
viewModel.updateCount()
}
}
}
LiveData.observe()์ ์ฒซ๋ฒ์งธ ์ธ์๋ก LifecycleOwner๋ฅผ ์ด๋ฏธ ๊ตฌํํ๊ณ ์๋ MainActivity ์์ฒด(this)๋ฅผ ๋ฃ๋๋ค. ๋๋ฒ์งธ ์ธ์๋ก๋ Observer์ ๊ตฌํ ํด๋์ค๋ฅผ ๋ฃ์ผ๋ฉด ๋๋ค. getUpdatedCount() ๋ฉ์๋๋ updateCount() ๋ฉ์๋๋ก ์ด๋ฆ๊ณผ ๊ธฐ๋ฅ์ ๋ฐ๊ฟจ์ผ๋ฏ๋ก, binding.countButton์ setOnClickListener { ... } ๋ธ๋ก์ ๋ด์ฉ๋ ๊ทธ์ ๋ง์ถฐ ์์ ํ๋ค.
Observer ๊ตฌํ ํด๋์ค ๋ถ๋ถ์ ๊ฐ๋
์ฑ์ด ์ฝ๊ฐ ๊ฑฐ์ฌ๋ฆฌ๋ฏ๋ก,
/*
val countObserver = object : Observer<Int> {
override fun onChanged(newValue: Int) {
binding.countText.text = newValue.toString()
}
}
viewModel.getCurrentCount().observe(this, countObserver)
*/
viewModel.getCurrentCount().observe(this, Observer {
binding.countText.text = it.toString()
})
์ ๊ฐ์ด ์ต๋ช
ํด๋์ค(ํด๋์ค ์ ์์ ๊ฐ์ฒดํ๋ฅผ ๋์์ ํ๋ ํด๋์ค)๋ฅผ ์ฌ์ฉํด ์ฝ๋๋ฅผ ์ค์ธ๋ค.
์ด์ count์ ๊ฐ์ด ๋ณ๊ฒฝ๋์ด๋ ๊ทธ ๊ฐ์ ๋ด๊ฐ View์ ๋ช
์์ ์ผ๋ก ์ฌํ ๋นํ ํ์๊ฐ ์๋ค. LiveData.observe()๊ฐ ์์์ ์ผ๋ก ์ฌํ ๋นํด์ค ๊ฒ์ด๊ธฐ ๋๋ฌธ์ด๋ค. ํ๋ก์ ํธ์ ํฌ๊ธฐ๊ฐ ์์ ํ์ฌ ๊ฒ์๊ธ์ ์ฑ์์๋ ํฌ๊ฒ ์๋ฟ์ง ์์ง๋ง, ํ๋ก์ ํธ์ ํฌ๊ธฐ๊ฐ ์ปค์ง์๋ก LiveData์ ์ด์ ์ด ์ฒด๊ฐ๋ ๊ฒ์ด๋ค.
#3 ์์ฝ
LiveData๋ onChangeListener()์ ์ธ๋ จ๋ ์ฌ์ฉ์ด๋ค.
#4 ์์ฑ๋ ์ฑ
android-practice/live-data/LiveDataBasics at master · Kanmanemone/android-practice
Contribute to Kanmanemone/android-practice development by creating an account on GitHub.
github.com
'๊นจ์ ๊ฐ๋ ๐ > Android' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
| [Android] LiveData - ์์์ ์ผ๋ก '๊ด์ฐฐ'ํ๊ธฐ (0) | 2024.01.19 |
|---|---|
| [Android] ViewModel - View์ ๊ฐ์ฒด(ViewModel) ์ ๋ฌ (0) | 2024.01.18 |
| [Android] ViewModel - ๋ทฐ ๋ชจ๋ธ์ ์ธ์(Argument) ์ ๋ฌ (ViewModelFactory) (0) | 2024.01.15 |
| [Android] ViewModel - ๊ธฐ์ด (0) | 2024.01.13 |
| [Android] Data Binding - View์ ๊ฐ์ฒด ์ ๋ฌ (0) | 2024.01.12 |