이 Codelab은 Android Kotlin 기초 교육 과정의 일부입니다. Codelab을 순서대로 진행한다면 이 과정을 통해 최대한의 가치를 얻을 수 있을 것입니다. 모든 과정 Codelab은 Android Kotlin 기초 Codelab 방문 페이지에 나열되어 있습니다.
소개
이전 Codelab에서는 GuessTheWord 앱에서 ViewModel
을 사용하여 기기 설정 변경 시 앱의 데이터가 유지되도록 했습니다. 이 Codelab에서는 LiveData
를 ViewModel
클래스의 데이터와 통합하는 방법을 알아봅니다. Android 아키텍처 구성요소 중 하나인 LiveData
를 사용하면 기본 데이터베이스가 변경되면 뷰에 알리는 데이터 객체를 빌드할 수 있습니다.
LiveData
클래스를 사용하려면 앱 데이터의 변경사항을 관찰하는 활동(예: 활동 또는 프래그먼트)을 설정해야 합니다. LiveData
는 수명 주기를 인식하므로 활성 수명 주기 상태인 앱 구성요소 관찰자만 업데이트합니다.
기본 요건
- Kotlin으로 기본 Android 앱을 만드는 방법
- 앱의 대상 간에 이동하는 방법
- 활동 및 프래그먼트 수명 주기
- 앱에서
ViewModel
객체를 사용하는 방법 ViewModelProvider.Factory
인터페이스를 사용하여ViewModel
객체를 만드는 방법
학습할 내용
LiveData
객체가 유용한 이유는 무엇인가요?ViewModel
에 저장된 데이터에LiveData
를 추가하는 방법MutableLiveData
의 사용 방법 및 방법LiveData.
에서 변경사항을 관찰하는 관찰자 메서드를 추가하는 방법- 지원 속성을 사용하여
LiveData
를 캡슐화하는 방법 - UI 컨트롤러와 상응하는
ViewModel
간의 통신 방법
실습할 내용
- 단어와 점수에
LiveData
를 사용해 GuessTheWord 앱을 사용하세요. - 단어나 점수가 변경되면 이를 관찰하는 관찰자를 추가합니다.
- 변경된 값을 표시하는 텍스트 뷰를 업데이트합니다.
LiveData
관찰자 패턴을 사용하여 게임이 완료된 이벤트를 추가합니다.- Play Again 버튼을 구현합니다.
과정 5 Codelab에서는 시작 코드로 시작하여 GuessTheWord 앱을 개발합니다. GuessTheWord는 플레이어들이 가능한 최고 점수를 달성하기 위해 협력하는 2인용 차데드 스타일의 게임입니다.
첫 번째 플레이어는 앱의 단어를 보고 순서대로 하나씩 플레이하며 두 번째 플레이어에게 단어를 표시하지 않도록 합니다. 두 번째 플레이어는 단어를 추측하려고 합니다.
게임을 플레이하려면 첫 번째 플레이어가 기기에서 앱을 열면 아래 스크린샷과 같이 단어가 표시됩니다.
첫 번째 플레이어는 단어를 소리 내서 말하지만, 실제로 그 단어를 말하지는 않습니다.
- 두 번째 플레이어가 단어를 올바르게 추측하면 첫 번째 플레이어가 확인 버튼을 눌러 숫자를 1씩 늘리고 다음 단어를 표시합니다.
- 두 번째 플레이어가 단어를 추측할 수 없으면 첫 번째 플레이어가 건너뛰기 버튼을 누릅니다. 이 경우 숫자가 1씩 감소하고 다음 단어로 건너뜁니다.
- 게임을 종료하려면 게임 종료 버튼을 누릅니다. (이 기능은 시리즈의 첫 번째 Codelab 시작 코드에는 없습니다.)
이 Codelab에서는 사용자가 앱의 모든 단어를 순환할 때 게임을 종료하는 이벤트를 추가하여 GuessTheWord 앱을 개선합니다. 또한 사용자가 게임을 다시 플레이할 수 있도록 점수 프래그먼트에 Play Again 버튼을 추가합니다.
타이틀 스크린 | 게임 화면 | 점수 화면 |
이 작업에서는 이 Codelab의 시작 코드를 찾아 실행합니다. 이전 Codelab에서 빌드한 GuessTheWord 앱을 시작 코드로 사용하거나 시작 앱을 다운로드할 수 있습니다.
- (선택사항) 이전 Codelab의 코드를 사용하지 않는 경우 이 Codelab의 시작 코드를 다운로드하세요. 코드의 압축을 푼 후 Android 스튜디오에서 프로젝트를 엽니다.
- 앱을 실행하고 게임을 플레이합니다.
- Skip 버튼을 누르면 다음 단어가 표시되고 점수가 1씩 줄어드는 경우, Got It 버튼을 누르면 다음 단어가 표시되고 점수가 1씩 증가합니다. 게임 종료 버튼을 누르면 게임이 종료됩니다.
LiveData
는 수명 주기를 인식하는 관찰 가능한 데이터 홀더 클래스입니다. 예를 들어 GuessTheWord 앱에서 현재 점수를 중심으로 LiveData
를 래핑할 수 있습니다. 이 Codelab에서는 LiveData
의 몇 가지 특성을 알아봅니다.
LiveData
는 관찰 가능합니다. 즉,LiveData
객체에서 보유한 데이터가 변경되면 관찰자에 알림이 제공됩니다.LiveData
는 데이터를 보유합니다.LiveData
는 모든 데이터에 사용할 수 있는 래퍼입니다.LiveData
는 수명 주기를 인식합니다. 즉,STARTED
또는RESUMED
같은 활성 수명 주기 상태인 관찰자만 업데이트합니다.
이 작업에서는 GameViewModel
의 현재 점수 및 현재 단어 데이터를 LiveData
로 변환하여 모든 데이터 유형을 LiveData
객체로 래핑하는 방법을 알아봅니다. 이후 작업에서는 이 LiveData
객체에 관찰자를 추가하고 LiveData
를 관찰하는 방법을 알아봅니다.
1단계: LiveData를 사용하도록 점수 및 단어 변경
screens/game
패키지에서GameViewModel
파일을 엽니다.- 변수
score
및word
의 유형을MutableLiveData
로 변경합니다.MutableLiveData
은(는) 값을 변경할 수 있는LiveData
입니다.MutableLiveData
는 일반 클래스이므로 이 클래스에 보유되는 데이터의 유형을 지정해야 합니다.
// The current word
val word = MutableLiveData<String>()
// The current score
val score = MutableLiveData<Int>()
GameViewModel
의init
블록 내에서score
와word
를 초기화합니다.LiveData
변수의 값을 변경하려면 변수에setValue()
메서드를 사용합니다. Kotlin에서value
속성을 사용하여setValue()
를 호출할 수 있습니다.
init {
word.value = ""
score.value = 0
...
}
2단계: LiveData 객체 참조 업데이트
score
및 word
변수는 이제 LiveData
유형입니다. 이 단계에서는 value
속성을 사용하여 변수 참조를 변경합니다.
GameViewModel
의onSkip()
메서드에서score
를score.value
로 변경합니다.score
가null
일 수 있는 오류를 확인합니다. 이 오류는 다음에 해결합니다.- 오류를 해결하려면
onSkip()
의score.value
에null
검사를 추가합니다. 그런 다음score
에서minus()
함수를 호출합니다. 이 함수는null
안전을 사용하여 빼기를 실행합니다.
fun onSkip() {
if (!wordList.isEmpty()) {
score.value = (score.value)?.minus(1)
}
nextWord()
}
- 같은 방법으로
onCorrect()
메서드를 업데이트합니다.score
변수에null
검사를 추가하고plus()
함수를 사용합니다.
fun onCorrect() {
if (!wordList.isEmpty()) {
score.value = (score.value)?.plus(1)
}
nextWord()
}
GameViewModel
의nextWord()
메서드 내에서word
참조를word
.
value
로 변경합니다.
private fun nextWord() {
if (!wordList.isEmpty()) {
//Select and remove a word from the list
word.value = wordList.removeAt(0)
}
}
GameFragment
의updateWordText()
메서드 내에서 참조를viewModel
.word
에서viewModel
.
word
.
value.
로 변경합니다.
/** Methods for updating the UI **/
private fun updateWordText() {
binding.wordText.text = viewModel.word.value
}
GameFragment
의updateScoreText()
메서드 내에서 참조를viewModel
.score
에서viewModel
.
score
.
value.
로 변경합니다.
private fun updateScoreText() {
binding.scoreText.text = viewModel.score.value.toString()
}
GameFragment
의gameFinished()
메서드 내에서 참조를viewModel
.score
에서viewModel
.
score
.
value
로 변경합니다. 필수null
안전 확인을 추가합니다.
private fun gameFinished() {
Toast.makeText(activity, "Game has just finished", Toast.LENGTH_SHORT).show()
val action = GameFragmentDirections.actionGameToScore()
action.score = viewModel.score.value?:0
NavHostFragment.findNavController(this).navigate(action)
}
- 코드에 오류가 없는지 확인합니다. 앱을 컴파일하고 실행합니다. 앱의 기능이 이전과 동일해야 합니다.
이 작업은 점수 및 단어 데이터를 LiveData
객체로 변환한 이전 작업과 밀접한 관련이 있습니다. 이 작업에서는 Observer
객체를 이 LiveData
객체에 연결합니다.
GameFragment,
의onCreateView()
메서드 내에서 현재 점수인viewModel.score
의Observer
객체를LiveData
객체에 연결합니다.observe()
메서드를 사용하고viewModel
초기화 후에 코드를 삽입합니다. 람다 표현식을 사용하여 코드를 단순화합니다. 람다 표현식은 선언되지 않지만 즉시 표현식으로 전달되는 익명 함수입니다.
viewModel.score.observe(this, Observer { newScore ->
})
Observer
에 대한 참조를 확인합니다. Observer
를 클릭하고 Alt+Enter
(Mac은 Option+Enter
)를 누른 후 androidx.lifecycle.Observer
를 가져옵니다.
- 관측된
LiveData
객체에서 보유한 데이터가 변경되면 방금 만든 관찰자가 이벤트를 수신합니다. 관찰자 내에서TextView
점수를 새 점수로 업데이트합니다.
/** Setting up LiveData observation relationship **/
viewModel.score.observe(this, Observer { newScore ->
binding.scoreText.text = newScore.toString()
})
- 현재 단어
LiveData
객체에Observer
객체를 연결합니다. 이 방법은 현재 점수에Observer
객체를 연결할 때와 동일합니다.
/** Setting up LiveData observation relationship **/
viewModel.word.observe(this, Observer { newWord ->
binding.wordText.text = newWord
})
이제 score
또는 word
의 값이 변경되면 화면에 score
또는 word
가 자동으로 업데이트됩니다.
GameFragment
에서 메서드updateWordText()
및updateScoreText()
와 이 메서드의 모든 참조를 삭제합니다. 더 이상 필요하지 않습니다.LiveData
관찰자 메서드에서 텍스트 뷰가 업데이트되기 때문입니다.- 앱을 실행합니다. 게임 앱이 이전과 똑같이 작동하지만 이제는
LiveData
및LiveData
관찰자를 사용합니다.
캡슐화는 일부 객체에 대한 직접 액세스를 제한하는 방법입니다. 객체를 캡슐화할 때 비공개 내부 필드를 수정하는 공개 메서드 집합을 노출할 수 있습니다. 캡슐화를 사용하여 다른 클래스가 비공개 내부 필드를 조작하는 방식을 제어할 수 있습니다.
현재 코드에서 외부 클래스는 value
속성(예: viewModel.score.value
)을 사용하여 score
및 word
변수를 수정할 수 있습니다. 이 Codelab에서 개발 중인 앱에서는 중요하지 않을 수 있지만 프로덕션 앱에서는 ViewModel
객체의 데이터를 제어해야 합니다.
ViewModel
만 앱의 데이터를 수정해야 합니다. 하지만 UI 컨트롤러가 데이터를 읽어야 하므로 데이터 필드가 완전히 비공개될 수 없습니다. 앱 데이터를 캡슐화하려면 MutableLiveData
및 LiveData
객체를 모두 사용합니다.
MutableLiveData
vs. LiveData
:
- 이름에서 알 수 있듯이
MutableLiveData
객체의 데이터는 변경할 수 있습니다.ViewModel
내에서는 데이터를 수정할 수 있어야 하므로 데이터는MutableLiveData
를 사용합니다. LiveData
객체의 데이터를 읽을 수 있지만 변경할 수는 없습니다.ViewModel
외부에서는 데이터를 읽을 수 있지만 수정할 수는 없어야 하므로 데이터는LiveData
로 노출되어야 합니다.
이 전략을 실행하려면 Kotlin 지원 속성을 사용합니다. 지원 속성을 사용하면 정확한 객체가 아닌 getter에서 무언가를 반환할 수 있습니다. 이 작업에서는 score
및 word
객체의 지원 속성을 GuessTheWord 앱에 구현합니다.
점수 및 단어에 지원 속성 추가
GameViewModel
에서 현재score
객체private
를 만듭니다.- 지원 속성에 사용되는 이름 지정 규칙을 따르려면
score
를_score
로 변경합니다. 이제_score
속성이 내부적으로 사용되는 게임 점수의 변경 가능한 버전입니다. LiveData
유형의 공개 버전인score
를 만듭니다.
// The current score
private val _score = MutableLiveData<Int>()
val score: LiveData<Int>
- 초기화 오류가 표시됩니다. 이 오류는
GameFragment
내부에서score
가LiveData
참조이고score
가 더 이상 setter에 액세스할 수 없기 때문에 발생합니다. Kotlin의 getter 및 setter에 관한 자세한 내용은 Getter 및 setter를 참조하세요.
이 오류를 해결하려면GameViewModel
에서score
객체의get()
메서드를 재정의하고 지원 속성인_score
를 반환합니다.
val score: LiveData<Int>
get() = _score
GameViewModel
에서score
의 참조를 변경 가능한 내부 버전인_score
로 변경합니다.
init {
...
_score.value = 0
...
}
...
fun onSkip() {
if (!wordList.isEmpty()) {
_score.value = (score.value)?.minus(1)
}
...
}
fun onCorrect() {
if (!wordList.isEmpty()) {
_score.value = (score.value)?.plus(1)
}
...
}
score
객체의 경우와 마찬가지로word
객체의 이름을_word
로 바꾸고 지원 속성을 추가합니다.
// The current word
private val _word = MutableLiveData<String>()
val word: LiveData<String>
get() = _word
...
init {
_word.value = ""
...
}
...
private fun nextWord() {
if (!wordList.isEmpty()) {
//Select and remove a word from the list
_word.value = wordList.removeAt(0)
}
}
LiveData
객체 word
및 score
를 캡슐화했습니다.
사용자가 게임 종료 버튼을 탭하면 현재 앱이 점수 화면으로 이동합니다. 또한 플레이어가 단어를 모두 순환할 때 앱에서 점수 화면으로 이동할 수도 있습니다. 플레이어가 마지막 단어를 마치면 게임이 자동으로 종료되므로 사용자가 버튼을 탭하지 않아도 됩니다.
이 기능을 구현하려면 모든 단어가 표시되었을 때 트리거되고 ViewModel
에서 프래그먼트로 전달되는 이벤트가 필요합니다. 이를 위해 LiveData
관찰자 패턴을 사용하여 게임에서 완료된 이벤트를 모델링합니다.
관찰자 패턴
관찰자 패턴은 소프트웨어 디자인 패턴입니다. 객체 사이의 통신을 관찰 가능한("subject" 관찰 대상) 및 관찰자로 지정합니다. 관찰 가능 요소는 관찰자에게 상태 변화를 알리는 객체입니다.
이 앱에서 LiveData
의 경우 관찰 가능한 (제목)은 LiveData
객체이고 관찰자는 프래그먼트와 같은 UI 컨트롤러의 메서드입니다. 상태 변경은 LiveData
내부에 래핑된 데이터가 변경될 때마다 발생합니다. LiveData
클래스는 ViewModel
에서 프래그먼트로 통신하는 데 매우 중요합니다.
1단계: LiveData를 사용하여 게임 종료 이벤트 감지
이 작업에서는 LiveData
관찰자 패턴을 사용하여 게임에서 완료된 이벤트를 모델링합니다.
GameViewModel
에서_eventGameFinish
라는Boolean
MutableLiveData
객체를 만듭니다. 이 객체에는 게임이 완료된 이벤트가 포함됩니다._eventGameFinish
객체를 초기화한 후eventGameFinish
라는 지원 속성을 만들고 초기화합니다.
// Event which triggers the end of the game
private val _eventGameFinish = MutableLiveData<Boolean>()
val eventGameFinish: LiveData<Boolean>
get() = _eventGameFinish
GameViewModel
에서onGameFinish()
메서드를 추가합니다. 메서드에서 게임 종료 이벤트eventGameFinish
를true
로 설정합니다.
/** Method for the game completed event **/
fun onGameFinish() {
_eventGameFinish.value = true
}
- 단어 목록이 비어 있으면
GameViewModel
의nextWord()
메서드 내에서 게임을 종료합니다.
private fun nextWord() {
if (wordList.isEmpty()) {
onGameFinish()
} else {
//Select and remove a _word from the list
_word.value = wordList.removeAt(0)
}
}
GameFragment
의onCreateView()
내에서viewModel
를 초기화한 후 관찰자를eventGameFinish
에 연결합니다.observe()
메서드를 사용합니다. 람다 함수 내에서gameFinished()
메서드를 호출합니다.
// Observer for the Game finished event
viewModel.eventGameFinish.observe(this, Observer<Boolean> { hasFinished ->
if (hasFinished) gameFinished()
})
- 앱을 실행하고 게임을 플레이하며 모든 단어를 살펴봅니다. 게임 종료를 탭할 때까지 게임 프래그먼트에 머무르지 않고 앱에서 자동으로 점수 화면으로 이동합니다.
단어 목록이 비어 있으면eventGameFinish
가 설정되고 게임 프래그먼트에서 연결된 관찰자 메서드가 호출되고 앱이 화면 프래그먼트로 이동합니다. - 추가한 코드에 수명 주기 문제가 발생했습니다. 문제를 파악하려면
GameFragment
클래스의gameFinished()
메서드에서 탐색 코드를 주석 처리합니다. 메서드에서Toast
메시지를 유지해야 합니다.
private fun gameFinished() {
Toast.makeText(activity, "Game has just finished", Toast.LENGTH_SHORT).show()
// val action = GameFragmentDirections.actionGameToScore()
// action.score = viewModel.score.value?:0
// NavHostFragment.findNavController(this).navigate(action)
}
- 앱을 실행하고 게임을 플레이하며 모든 단어를 살펴봅니다. 예상되는 게임 동작인 '게임이 방금 완료되었습니다'라는 토스트 메시지가 게임 화면 하단에 잠시 나타납니다.
이제 기기나 에뮬레이터를 회전합니다. 토스트 메시지가 다시 표시됩니다. 기기를 몇 번 회전하면 매번 토스트 메시지가 표시될 것입니다. 이 버그는 게임이 끝나면 토스트 메시지가 한 번만 표시되어야 하기 때문입니다. 프래그먼트를 다시 만들 때마다 토스트 메시지가 표시되지 않아야 합니다. 다음 작업에서 이 문제를 해결합니다.
2단계: 게임 종료 이벤트 재설정하기
일반적으로 LiveData
는 데이터가 변경될 때만 관찰자에게 업데이트를 전달합니다. 이 동작의 예외로, 관찰자가 비활성에서 활성 상태로 변경되면 관찰자가 업데이트를 받게 됩니다.
이 때문에 게임 종료 토스트 메시지가 앱에서 반복적으로 트리거됩니다. 게임 프래그먼트가 화면 회전 후 다시 생성되면 비활성에서 활성 상태로 전환됩니다. 프래그먼트의 관찰자는 기존 ViewModel
에 다시 연결되고 현재 데이터를 수신합니다. gameFinished()
메서드가 다시 트리거되고 토스트 메시지가 표시됩니다.
이 작업에서는 이 문제를 해결하고 GameViewModel
에서 eventGameFinish
플래그를 재설정하여 토스트 메시지를 한 번만 표시합니다.
GameViewModel
에서onGameFinishComplete()
메서드를 추가하여 게임 완료 이벤트_eventGameFinish
를 재설정합니다.
/** Method for the game completed event **/
fun onGameFinishComplete() {
_eventGameFinish.value = false
}
GameFragment
의gameFinished()
끝에 있는viewModel
객체의onGameFinishComplete()
를 호출합니다.gameFinished()
의 탐색 코드를 지금은 주석으로 처리합니다.
private fun gameFinished() {
...
viewModel.onGameFinishComplete()
}
- 앱을 실행하고 게임을 플레이합니다. 모든 단어를 살펴본 다음 기기의 화면 방향을 변경합니다. 토스트 메시지는 한 번만 표시됩니다.
GameFragment
의gameFinished()
메서드 내에서 탐색 코드의 주석 처리를 삭제합니다.
Android 스튜디오에서 주석 처리를 삭제하려면 주석 처리된 줄을 선택하고Control+/
(Mac은Command+/
)를 누릅니다.
private fun gameFinished() {
Toast.makeText(activity, "Game has just finished", Toast.LENGTH_SHORT).show()
val action = GameFragmentDirections.actionGameToScore()
action.score = viewModel.score.value?:0
findNavController(this).navigate(action)
viewModel.onGameFinishComplete()
}
Android 스튜디오에서 메시지가 표시되면 androidx.navigation.fragment.NavHostFragment.findNavController
를 가져옵니다.
- 앱을 실행하고 게임을 플레이합니다. 모든 단어를 살펴본 후 앱이 최종 점수 화면으로 자동으로 이동하는지 확인합니다.
정답입니다. 앱은 LiveData
를 사용하여 게임이 완료된 이벤트를 트리거하여 GameViewModel
에서 단어 목록이 비어 있는 게임 프래그먼트와 통신합니다. 그런 다음 게임 프래그먼트가 점수 프래그먼트로 이동합니다.
이 작업에서는 점수를 ScoreViewModel
의 LiveData
객체로 변경하고 여기에 관찰자를 연결합니다. 이 작업은 GameViewModel
에 LiveData
를 추가할 때와 비슷합니다.
ScoreViewModel
를 변경하여 앱의 모든 데이터가 LiveData
을 사용하도록 합니다.
ScoreViewModel
에서score
변수 유형을MutableLiveData
로 변경합니다. 규칙에 따라 이름을_score
로 변경하고 지원 속성을 추가합니다.
private val _score = MutableLiveData<Int>()
val score: LiveData<Int>
get() = _score
ScoreViewModel
의init
블록 내에서_score
를 초기화합니다.init
블록에서 로그를 삭제하거나 그대로 둘 수 있습니다.
init {
_score.value = finalScore
}
ScoreFragment
의onCreateView()
내에서viewModel
를 초기화한 후 점수LiveData
객체의 관찰자를 연결합니다. 람다 표현식 내에서 점수 값을 점수 텍스트 뷰로 설정합니다.ViewModel
에서 점수 값으로 텍스트 뷰를 직접 할당하는 코드를 삭제합니다.
추가할 코드:
// Add observer for score
viewModel.score.observe(this, Observer { newScore ->
binding.scoreText.text = newScore.toString()
})
삭제할 코드:
binding.scoreText.text = viewModel.score.toString()
Android 스튜디오에서 메시지가 표시되면 androidx.lifecycle.Observer
를 가져옵니다.
- 앱을 실행하고 게임을 플레이합니다. 앱이 이전과 똑같이 작동하지만 이제는
LiveData
와 관찰자를 사용하여 점수를 업데이트합니다.
이 작업에서는 점수 화면에 Play Again 버튼을 추가하고 LiveData
이벤트를 사용하여 클릭 리스너를 구현합니다. 이 버튼을 통해 점수 화면에서 게임 화면으로 이동하는 이벤트가 트리거됩니다.
앱의 시작 코드에 Play Again 버튼이 포함되어 있지만 버튼이 숨겨져 있습니다.
res/layout/score_fragment.xml
에서play_again_button
버튼의visibility
속성 값을visible
로 변경합니다.
<Button
android:id="@+id/play_again_button"
...
android:visibility="visible"
/>
ScoreViewModel
에서_eventPlayAgain
라는Boolean
를 보유할LiveData
객체를 추가합니다. 이 객체는LiveData
이벤트를 저장하여 점수 화면에서 게임 화면으로 이동하는 데 사용됩니다.
private val _eventPlayAgain = MutableLiveData<Boolean>()
val eventPlayAgain: LiveData<Boolean>
get() = _eventPlayAgain
ScoreViewModel
에서_eventPlayAgain
이벤트를 설정하고 재설정하는 메서드를 정의합니다.
fun onPlayAgain() {
_eventPlayAgain.value = true
}
fun onPlayAgainComplete() {
_eventPlayAgain.value = false
}
ScoreFragment
에서eventPlayAgain
의 관찰자를 추가합니다.onCreateView()
끝의return
문 앞에 코드를 입력합니다. 람다 표현식 내에서 게임 화면으로 돌아가서eventPlayAgain
을 재설정합니다.
// Navigates back to game when button is pressed
viewModel.eventPlayAgain.observe(this, Observer { playAgain ->
if (playAgain) {
findNavController().navigate(ScoreFragmentDirections.actionRestart())
viewModel.onPlayAgainComplete()
}
})
Android 스튜디오에서 메시지가 표시되면 androidx.navigation.fragment.findNavController
을 가져옵니다.
ScoreFragment
의onCreateView()
내에서 PlayAgain 버튼에 클릭 리스너를 추가하고viewModel
.onPlayAgain()
를 호출합니다.
binding.playAgainButton.setOnClickListener { viewModel.onPlayAgain() }
- 앱을 실행하고 게임을 플레이합니다. 게임이 완료되면 점수 화면에 최종 점수와 다시 플레이하기 버튼이 표시됩니다. PlayAgain 버튼을 탭하면 앱이 게임 화면으로 이동하여 게임을 다시 플레이할 수 있습니다.
훌륭합니다. ViewModel
의 LiveData
객체를 사용하도록 앱의 아키텍처를 변경했으며 LiveData
객체에 관찰자를 연결했습니다. LiveData
는 LiveData
가 보유한 값이 변경되면 관찰자 객체에 알립니다.
Android 스튜디오 프로젝트: GuessTheWord
LiveData
LiveData
는 수명 주기를 인식하는 식별 가능한 데이터 홀더 클래스로, Android 아키텍처 구성요소 중 하나입니다.LiveData
를 사용하면 데이터가 업데이트될 때 UI가 자동으로 업데이트되도록 할 수 있습니다.LiveData
는 관찰 가능합니다. 즉, 활동 또는 프래그먼트와 같은 관찰자에LiveData
객체가 보유한 데이터가 변경되면 이를 알릴 수 있습니다.LiveData
데이터는 보유되며 모든 데이터에 사용할 수 있는 래퍼입니다.LiveData
는 수명 주기를 인식합니다. 즉,STARTED
또는RESUMED
같은 활성 수명 주기 상태인 관찰자만 업데이트합니다.
LiveData 추가
ViewModel
의 데이터 변수 유형을LiveData
또는MutableLiveData
로 변경합니다.
MutableLiveData
는 값을 변경할 수 있는 LiveData
객체입니다. MutableLiveData
는 일반 클래스이므로 이 클래스에 보유되는 데이터의 유형을 지정해야 합니다.
LiveData
가 보유한 데이터 값을 변경하려면LiveData
변수에setValue()
메서드를 사용합니다.
LiveData 캡슐화
ViewModel
내부의LiveData
는 수정할 수 있어야 합니다.ViewModel
외부에서는LiveData
를 읽을 수 있어야 합니다. 이는 Kotlin 지원 속성을 사용하여 구현할 수 있습니다.- Kotlin 지원 속성을 사용하면 정확한 객체가 아닌 getter에서 무언가를 반환할 수 있습니다.
LiveData
를 캡슐화하려면ViewModel
내에서private
MutableLiveData
를 사용하고ViewModel
외부에LiveData
지원 속성을 반환합니다.
관찰 가능한 LiveData
LiveData
는 관찰자 패턴을 따릅니다. \'observable"는LiveData
객체이고, 관찰자는 프래그먼트와 같은 UI 컨트롤러의 메서드입니다.LiveData
내부에 래핑된 데이터가 변경될 때마다 UI 컨트롤러의 관찰자 메서드에 알림이 전송됩니다.LiveData
를 관찰 가능하게 만들려면observe()
메서드를 사용하여 관찰자 (예: 활동 및 프래그먼트)의LiveData
참조에 관찰자 객체를 연결합니다.- 이
LiveData
관찰자 패턴을 사용하여ViewModel
에서 UI 컨트롤러로 통신할 수 있습니다.
Udacity 과정:
Android 개발자 문서:
기타:
- Kotlin의 지원 속성
이 섹션에는 강사가 진행하는 과정의 일부로 이 Codelab을 통해 작업하는 학생들의 숙제 과제가 나와 있습니다. 강사는 다음을 처리합니다.
- 필요한 경우 과제를 할당합니다.
- 학생에게 과제 과제를 제출하는 방법을 알려주세요.
- 과제 과제를 채점합니다.
강사는 이러한 추천을 원하는 만큼 사용할 수 있으며 다른 적절한 숙제를 할당해도 좋습니다.
이 Codelab을 직접 학습하고 있다면 언제든지 숙제를 통해 지식을 확인해 보세요.
답변
질문 1
데이터를 업데이트하지 않고도 외부 객체가 데이터를 읽을 수 있도록 ViewModel
에 저장된 LiveData
를 캡슐화하려면 어떻게 해야 하나요?
ViewModel
객체 내에서 데이터의 데이터 유형을private
LiveData
로 변경합니다. 지원 속성을 사용하여MutableLiveData
유형의 읽기 전용 데이터를 노출합니다.ViewModel
객체 내에서 데이터의 데이터 유형을private
MutableLiveData
로 변경합니다. 지원 속성을 사용하여LiveData
유형의 읽기 전용 데이터를 노출합니다.- UI 컨트롤러 내에서 데이터의 데이터 유형을
private
MutableLiveData
로 변경합니다. 지원 속성을 사용하여LiveData
유형의 읽기 전용 데이터를 노출합니다. ViewModel
객체 내에서 데이터의 데이터 유형을LiveData
로 변경합니다. 지원 속성을 사용하여LiveData
유형의 읽기 전용 데이터를 노출합니다.
질문 2
UI 컨트롤러가 다음 중 어떤 상태에 있는 경우에 LiveData
가 UI 컨트롤러 (예: 프래그먼트)를 업데이트하나요?
- 재개됨
- 백그라운드에 있음
- 일시중지됨
- 중지됨
질문 3
LiveData
관찰자 패턴에서 식별 가능한 항목 (관찰되는 항목)은 무엇인가요?
- 관찰자 메서드
LiveData
객체의 데이터- UI 컨트롤러
ViewModel
객체
다음 강의 시작:
이 과정의 다른 Codelab 링크는 Android Kotlin 기초 Codelab 방문 페이지를 참고하세요.