ꡬκΈμμ μ 곡νλ κ΅μ‘μλ£λ₯Ό μ 리νκΈ° μν ν¬μ€νΈμ λλ€.
λ¨κΈ° κ²°μ μ λν μ΄λ¬ν μλ κΈ°μ μ λΆμ±λ‘ μ΄μ΄μ§ μ μμΌλ©° μ μ°νκ³ ν¨μ¨μ μΈ λ°©λ²μΌλ‘ μ±μ νμ₯νλ κ²μ μ΄λ ΅κ² λ§λ€ μ μμ΅λλ€.
Acitivty
νμΌμ λͺ¨λ λΉμ§λμ€ λ‘μ§ λ°°μΉ.μ°μν app architectureλ μ±μ΄ νμ₯ κ°λ₯νκ³ μμ μ μ΄λ©° κ΄λ¦¬νκΈ° μ½μ΅λλ€.
Acitivty
, Fragment
λ λ°μ΄ν° νμ, μ¬μ©μ μ
λ ₯, Android μμ€ν
μ΄λ²€νΈλ₯Ό λ΄λΉν©λλ€.
ViewModel
μλ UIλ₯Ό 그리λ λ° νμν λͺ¨λ λ°μ΄ν°μ μ΄λ₯Ό μ΅μ μνλ‘ μ μ§νλ κΈ°λ₯μ΄ ν¬ν¨λμ΄ μμ΅λλ€.
UI 컨νΈλ‘€λ¬λ μ£Όλ‘ μ¬μ©μμκ² μ 보λ₯Ό νμνκ³ μ΄λ²€νΈλ₯Ό μ²λ¦¬ μν μ νκΈ° λλ¬Έμ λ°μ΄ν°λ₯Ό κ΄λ¦¬λ ViewModel
μμ μ§νν©λλ€.
app/build.gradle νμΌμ μΆκ°ν΄ μ€λλ€.
dependencies {
implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:$lifecycle_version"
implementation "androidx.activity:activity-ktx:$activity_version"
}
Activity
, Fragment
λλ View
λ₯Ό μ°Έμ‘°νμ§ μμ΅λλ€.lifecycle
λ‘ scopeκ° μ§μ λ©λλ€.(Activity
, Fragment
μ μ‘΄μ¬.)ViewModel
ν΄λμ€λ μΆμ ν΄λμ€μ΄λ―λ‘ μλΈν΄λμ±ν΄μΌ ν©λλ€. λ μ΄μ μ¬μ©λμ§ μκ³ μλ©Έλ λ νΈμΆλλ onCleared()
λ©μλκ° μμ΅λλ€.
class ScoreViewModel : ViewModel() {
var scoreA : Int = 0
var scoreB : Int = 0
fun incrementScore(isTeamA: Boolean) {
if (isTeamA) {
scoreA++
}
else {
scoreB++
}
}
}
activity-ktx artifact ν¬ν¨λμ΄μλ by viewModels()
λ₯Ό μ¬μ©νμ¬ κ°μ Έμ΅λλ€.
class MainActivity : AppCompatActivity() {
// Delegate provided by androidx.activity.viewModels
val viewModel: ScoreViewModel by viewModels()
override fun onCreate(savedInstanceState: Bundle?) {
...
val scoreViewA: TextView = findViewById(R.id.scoreA)
scoreViewA.text = viewModel.scoreA.toString()
}
data binding μμ΄ μ¬μ©ν κ²½μ°.
data binding μ¬μ©ν κ²½μ°.
view
μ viewModel
κ°μ μΌλΆ ν΅μ μ μλν ν μ μμ΅λλ€.data ν
κ·Έ μμ ViewModel
μ μ§μ ν©λλ€.
<layout>
<data>
<variable>
name="viewModel"
type="com.example.kabaddikounter.ScoreViewModel" />
</data>
<ConstraintLayout ../>
</layout>
class MainActivity : AppCompatActivity() {
val viewModel: ScoreViewModel by viewModels()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val binding: ActivityMainBinding = DataBindingUtil.setContentView(this,
R.layout.activity_main)
binding.viewModel = viewModel
...
<TextView
android:id="@+id/scoreViewA"
android:text="@{viewModel.scoreA.toString()}" />
...
View
κ° μΈμ€ν΄μ€νλ λλ§ μ€μ λκΈ° λλ¬Έμ ν΄λ¦ μ΄λ²€νΈκ° μΌμ΄λ¬μ λ μ
λ°μ΄νΈκ° νμν©λλ€. λ€μ LiveData
μμ μ΄ λ¬Έμ λ₯Ό λ€λ£° κ²μ
λλ€.
override fun onCreate(savedInstanceState: Bundle?) {
...
val binding: ActivityMainBinding = DataBindingUtil.setContentView(this,
R.layout.activity_main)
binding.plusOneButtonA.setOnClickListener {
viewModel.incrementScore(true)
binding.scoreViewA.text = viewModel.scoreA.toString()
}
}
observer
κ°μ²΄κ° 주체μ μν λ³κ²½μ΄ μμ λ μ리기 μν΄ κ°μ²΄ λͺ©λ‘μ μ μ§νλ κ³³μ
λλ€.observer
λ 주체λ‘λΆν° μν λ³κ²½μ μμ νμ¬ μ μ ν μ½λλ₯Ό μ€νν©λλ€.observer
λ μΈμ λ μ§ μΆκ°νκ±°λ μ κ±°ν μ μμ΅λλ€.observe
ν μ μλ lifecycle-aware λ°μ΄ν° νλWrapper
ViewModel
μμ κ°λ³ λ°μ΄ν° νλλ₯Ό 보κ΄νλ λ° μμ£Ό μ¬μ©ν©λλ€.observer
(Activity
, Fragment
μμ μ¬μ©)λ₯Ό μΆκ°νκ±°λ μ κ±°ν μ μλ λ©μλ.LiveData(immutable): getValue()
MutableLiveData: getValue(), postValue(value: T), setValue(value: T)
μΌλ°μ μΌλ‘ MutableLiveData
λ ViewModel
μμ private νκ² μ¬μ©νμ¬ λ
ΈμΆ μν€μ§ μκ³ λ³κ²½ λΆκ°λ₯ν LiveData
λ₯Ό observer
μκ² λ
ΈμΆν©λλ€.
class ScoreViewModel : ViewModel() {
private val _scoreA = MutableLiveData<Int>(0)
val scoreA: LiveData<Int>
get() = _scoreA
fun incrementScore(isTeamA: Boolean) {
if (isTeamA) {
_scoreA.value = _scoreA.value!! + 1
}
...
ViewModel
λ©μλλ₯Ό νΈμΆνλ ν΄λ¦ μ΄λ²€νΈλ₯Ό μ€μ ν©λλ€.
binding.plusOneButtonA.setOnClickListener {
viewModel.incrementScore(true)
}
ν Aμ μ μλ₯Ό μ
λ°μ΄νΈνκΈ° μν΄ observer
λ₯Ό μμ±ν©λλ€.
val scoreA_Observer = Observer<Int> { newValue ->
binding.scoreViewA.text = newValue.toString()
}
ViewModel
μ scoreA LiveData
μ observe
λ₯Ό μΆκ°ν©λλ€.
viewModel.scoreA.observe(this, scoreA_Observer)
LiveData
μ λ°μΈλ©νλ©΄ μ½λμμ observer
κ° νμνμ§ μμ μ½λμ μμ μ€ μΌ μ μμ΅λλ€.<layout>
<data>
<variable>
name="viewModel"
type="com.example.kabaddikounter.ScoreViewModel" />
</data>
<ConstraintLayout ..>
<TextView ...
android:id="@+id/scoreViewA"
android:text="@{viewModel.scoreA.toString()}" />
...
</ConstraintLayout>
</layout>
class MainActivity : AppCompatActivity() {
val viewModel: ScoreViewModel by viewModels()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val binding: ActivityMainBinding = DataBindingUtil
.setContentView(this, R.layout.activity_main)
binding.viewModel = viewModel
binding.lifecycleOwner = this
binding.plusOneButtonA.setOnClickListener {
viewModel.incrementScore(true)
}
...
class ScoreViewModel : ViewModel() {
private val _scoreA = MutableLiveData<Int>(0)
val scoreA : LiveData<Int>
get() = _scoreA
private val _scoreB = MutableLiveData<Int>(0)
val scoreB : LiveData<Int>
get() = _scoreB
fun incrementScore(isTeamA: Boolean) {
if (isTeamA) {
_scoreA.value = _scoreA.value!! + 1
} else {
_scoreB.value = _scoreB.value!! + 1
}
}
}
observer
μκ² μ λ¬νκΈ° μ΄μ μ LiveData
κ°μ²΄μ μ μ₯λ κ°μ λ³κ²½ν μ μμ΅λλ€.
λ€λ₯Έ κ°μ κΈ°λ°μΌλ‘ νλ λ€λ₯Έ LiveData
μΈμ€ν΄μ€λ₯Ό λ°νν μ μμ΅λλ€.
LiveData
λ μλ‘μ΄ LiveData
κ°μ²΄λ‘ λ³νλ μ μμ΅λλ€.
observer
κ° λ°νλ κ²°κ³Όλ₯Ό observing
νμ§ μλ ν λ³νμ κ³μ°λμ§ μμ΅λλ€.
val result: LiveData<String> = Transformations.map(viewModel.scoreA) {
x -> if (x > 10) "A Wins" else ""
}