이 Codelab은 Android Kotlin 기초 과정의 일부입니다. Codelab을 순서대로 진행하면 이 과정의 학습 효과를 극대화할 수 있습니다. 모든 과정 Codelab은 Android Kotlin 기본사항 Codelab 방문 페이지에 나열되어 있습니다.
소개
이전 Codelab에서는 GuessTheWord 앱에서 ViewModel
을 사용하여 기기 구성 변경 후에도 앱의 데이터가 유지되도록 했습니다. 이 Codelab에서는 LiveData
를 ViewModel
클래스의 데이터와 통합하는 방법을 알아봅니다. LiveData
는 Android 아키텍처 구성요소 중 하나로, 기본 데이터베이스가 변경될 때 뷰에 알리는 데이터 객체를 빌드할 수 있습니다.
LiveData
클래스를 사용하려면 앱 데이터의 변경사항을 관찰하는 '관찰자' (예: 활동 또는 프래그먼트)를 설정합니다. LiveData
는 수명 주기를 인식하므로 활성 수명 주기 상태에 있는 앱 구성요소 관찰자만 업데이트합니다.
기본 요건
- Kotlin으로 기본 Android 앱을 만드는 방법
- 앱의 대상 간에 이동하는 방법
- 활동 및 프래그먼트 수명 주기
- 앱에서
ViewModel
객체를 사용하는 방법 ViewModelProvider.Factory
인터페이스를 사용하여ViewModel
객체를 만드는 방법
학습할 내용
LiveData
객체를 유용하게 만드는 요소ViewModel
에 저장된 데이터에LiveData
를 추가하는 방법MutableLiveData
을 사용하는 경우와 방법LiveData.
에서 변경사항을 관찰하는 관찰자 메서드를 추가하는 방법- 지원 속성을 사용하여
LiveData
를 캡슐화하는 방법 - UI 컨트롤러와 해당
ViewModel
간에 통신하는 방법
실습할 내용
- GuessTheWord 앱에서 단어와 점수에
LiveData
를 사용합니다. - 단어나 점수가 변경될 때 이를 감지하는 관찰자를 추가합니다.
- 변경된 값을 표시하는 텍스트 뷰를 업데이트합니다.
LiveData
옵저버 패턴을 사용하여 게임 종료 이벤트를 추가합니다.- 다시 재생 버튼을 구현합니다.
5단원 Codelab에서는 시작 코드로 시작하여 GuessTheWord 앱을 개발합니다. GuessTheWord는 플레이어들이 가능한 최고 점수를 달성하기 위해 협력하는 2인용 제스처 스타일 게임입니다.
첫 번째 플레이어는 앱의 단어를 보고 두 번째 플레이어에게 단어를 보여주지 않으면서 각 단어를 차례로 연기합니다. 두 번째 플레이어가 단어를 추측합니다.
게임을 플레이하려면 첫 번째 플레이어가 기기에서 앱을 열고 아래 스크린샷과 같이 '기타'와 같은 단어를 확인합니다.
첫 번째 플레이어는 단어를 실제로 말하지 않도록 주의하면서 단어를 연기합니다.
- 두 번째 플레이어가 단어를 맞히면 첫 번째 플레이어가 맞혔어요 버튼을 눌러 카운트를 1만큼 늘리고 다음 단어를 표시합니다.
- 두 번째 플레이어가 단어를 맞히지 못하면 첫 번째 플레이어가 건너뛰기 버튼을 눌러 카운트를 1만큼 줄이고 다음 단어로 건너뜁니다.
- 게임을 종료하려면 게임 종료 버튼을 누릅니다. (이 기능은 시리즈의 첫 번째 Codelab의 시작 코드에 없습니다.)
이 Codelab에서는 사용자가 앱의 모든 단어를 순환할 때 게임을 종료하는 이벤트를 추가하여 GuessTheWord 앱을 개선합니다. 또한 사용자가 게임을 다시 플레이할 수 있도록 점수 프래그먼트에 다시 플레이 버튼을 추가합니다.
타이틀 스크린 | 게임 화면 | 점수 화면 |
이 작업에서는 이 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
객체에 연결합니다.
onCreateView()
메서드 내의GameFragment,
에서 현재 점수viewModel.score
의LiveData
객체에Observer
객체를 연결합니다.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()
})
Observer
객체를 현재 단어LiveData
객체에 연결합니다.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
속성을 사용하여 score
및 word
변수를 수정할 수 있습니다(예: viewModel.score.value
사용). 이 Codelab에서 개발하는 앱에서는 문제가 되지 않을 수 있지만 프로덕션 앱에서는 ViewModel
객체의 데이터를 제어해야 합니다.
ViewModel
만 앱의 데이터를 수정해야 합니다. 하지만 UI 컨트롤러는 데이터를 읽어야 하므로 데이터 필드를 완전히 비공개로 설정할 수는 없습니다. 앱의 데이터를 캡슐화하려면 MutableLiveData
및 LiveData
객체를 모두 사용합니다.
MutableLiveData
대 LiveData
:
MutableLiveData
객체의 데이터는 이름에서 알 수 있듯이 변경할 수 있습니다.ViewModel
내에서는 데이터를 수정할 수 있어야 하므로MutableLiveData
을 사용합니다.LiveData
객체의 데이터는 읽을 수 있지만 변경할 수는 없습니다.ViewModel
외부에서는 데이터를 읽을 수 있지만 수정할 수는 없어야 하므로 데이터는LiveData
로 노출되어야 합니다.
이 전략을 실행하려면 Kotlin 지원 속성을 사용합니다. 지원 속성을 사용하면 정확한 객체가 아닌 getter에서 무언가를 반환할 수 있습니다. 이 작업에서는 GuessTheWord 앱에서 score
및 word
객체의 지원 속성을 구현합니다.
점수와 단어에 지원 속성 추가
GameViewModel
에서 현재score
객체를private
로 만듭니다.- 지원 속성에 사용된 이름 지정 규칙을 따르려면
score
를_score
로 변경하세요. 이제_score
속성은 내부적으로 사용되는 게임 점수의 변경 가능한 버전입니다. score
이라는LiveData
유형의 공개 버전을 만듭니다.
// The current score
private val _score = MutableLiveData<Int>()
val score: LiveData<Int>
- 초기화 오류가 표시됩니다. 이 오류는
GameFragment
내에서score
이LiveData
참조이고score
이 더 이상 setter에 액세스할 수 없기 때문에 발생합니다. Kotlin의 게터 및 세터에 관한 자세한 내용은 게터 및 세터를 참고하세요.
오류를 해결하려면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)
}
...
}
word
객체를_word
로 이름을 바꾸고score
객체에서와 같이 지원 속성을 추가합니다.
// 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
관찰자 패턴을 사용하여 게임 종료 이벤트를 모델링합니다.
관찰자 패턴
관찰자 패턴은 소프트웨어 디자인 패턴입니다. 객체 간 통신 (관찰 대상인 관찰 가능과 관찰자)을 지정합니다. 관찰 대상은 상태 변경사항을 관찰자에게 알리는 객체입니다.
이 앱의 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단계: game-finished 이벤트 재설정
일반적으로 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
를 추가할 때 실행한 작업과 유사합니다.
앱의 모든 데이터가 LiveData
을 사용하도록 완전성을 위해 ScoreViewModel
을 변경합니다.
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
와 관찰자를 사용하여 점수를 업데이트합니다.
이 작업에서는 점수 화면에 다시 플레이 버튼을 추가하고 LiveData
이벤트를 사용하여 클릭 리스너를 구현합니다. 버튼을 누르면 점수 화면에서 게임 화면으로 이동하는 이벤트가 트리거됩니다.
앱의 시작 코드에는 다시 플레이 버튼이 포함되어 있지만 버튼은 숨겨져 있습니다.
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
는 관찰자 패턴을 따릅니다. '관찰 대상'은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 방문 페이지를 참고하세요.