Android Kotlin 기초 05.3: ViewModel 및 LiveData를 사용한 데이터 결합

이 Codelab은 Android Kotlin 기초 교육 과정의 일부입니다. Codelab을 순서대로 진행한다면 이 과정을 통해 최대한의 가치를 얻을 수 있을 것입니다. 모든 과정 Codelab은 Android Kotlin 기초 Codelab 방문 페이지에 나열되어 있습니다.

소개

이 과정의 이전 Codelab에서는 GuessTheWord 앱의 코드를 개선했습니다. 이제 앱이 ViewModel 객체를 사용하므로 화면 회전 및 키보드 가용성 변경과 같은 기기 설정 변경 후에도 앱 데이터가 유지됩니다. 또한 관찰 가능한 LiveData를 추가했으므로 관찰된 데이터가 변경되면 뷰에 자동으로 알림이 전송됩니다.

이 Codelab에서는 GuessTheWord 앱을 계속 사용합니다. 앱의 ViewModel 클래스에 뷰를 바인딩하여 레이아웃의 뷰가 ViewModel 객체와 직접 통신하도록 합니다. (이제는 앱에서 뷰까지 앱의 프래그먼트를 통해 ViewModel간접적으로 통신했습니다.) 데이터 결합을 ViewModel 객체와 통합한 후에는 더 이상 앱 프래그먼트에 클릭 핸들러가 필요하지 않으므로 이를 삭제합니다.

또한 LiveData 관찰자 메서드를 사용하지 않고 데이터 변경사항을 소스로 사용하여 LiveData에 데이터 변경사항을 UI에 알리도록 GuessTheWord 앱을 변경합니다.

기본 요건

  • Kotlin으로 기본 Android 앱을 만드는 방법
  • 활동 및 프래그먼트 수명 주기 작동 방식
  • 앱에서 ViewModel 객체를 사용하는 방법
  • ViewModelLiveData를 사용하여 데이터를 저장하는 방법
  • LiveData 데이터의 변경사항을 관찰하는 관찰자 메서드를 추가하는 방법

학습할 내용

  • 데이터 결합 라이브러리의 요소를 사용하는 방법
  • ViewModel를 데이터 결합과 통합하는 방법
  • LiveData를 데이터 결합과 통합하는 방법
  • 리스너 결합을 사용하여 프래그먼트의 클릭 리스너를 교체하는 방법
  • 데이터 결합 표현식에 문자열 서식을 추가하는 방법

실습할 내용

  • GuessTheWord 레이아웃의 뷰는 ViewModel 컨트롤러와 간접적으로 통신하며, UI 컨트롤러 (프래그먼트)를 사용하여 정보를 전달합니다. 이 Codelab에서는 앱의 뷰를 ViewModel 객체에 바인딩하여 뷰가 ViewModel 객체와 직접 통신하도록 합니다.
  • LiveData를 데이터 결합 소스로 사용하도록 앱을 변경합니다. 이 변경 후 LiveData 객체는 데이터 변경사항에 관해 UI에 알리며 LiveData 관찰자 메서드는 더 이상 필요하지 않습니다.

과정 5 Codelab에서는 시작 코드로 시작하여 GuessTheWord 앱을 개발합니다. GuessTheWord는 플레이어들이 가능한 최고 점수를 달성하기 위해 협력하는 2인용 차데드 스타일의 게임입니다.

첫 번째 플레이어는 앱의 단어를 보고 순서대로 하나씩 플레이하며 두 번째 플레이어에게 단어를 표시하지 않도록 합니다. 두 번째 플레이어는 단어를 추측하려고 합니다.

게임을 플레이하려면 첫 번째 플레이어가 기기에서 앱을 열면 아래 스크린샷과 같이 단어가 표시됩니다.

첫 번째 플레이어는 단어를 소리 내서 말하지만, 실제로 그 단어를 말하지는 않습니다.

  • 두 번째 플레이어가 단어를 올바르게 추측하면 첫 번째 플레이어가 확인 버튼을 눌러 숫자를 1씩 늘리고 다음 단어를 표시합니다.
  • 두 번째 플레이어가 단어를 추측할 수 없으면 첫 번째 플레이어가 건너뛰기 버튼을 누릅니다. 이 경우 숫자가 1씩 감소하고 다음 단어로 건너뜁니다.
  • 게임을 종료하려면 게임 종료 버튼을 누릅니다. (이 기능은 시리즈의 첫 번째 Codelab 시작 코드에는 없습니다.)

이 Codelab에서는 ViewModel 객체의 데이터 결합을 LiveData와 통합하여 GuessTheWord 앱을 개선합니다. 레이아웃의 뷰와 ViewModel 객체 간의 통신을 자동화하며, LiveData를 사용하여 코드를 단순화할 수 있습니다.

타이틀 스크린

게임 화면

점수 화면

이 작업에서는 이 Codelab의 시작 코드를 찾아 실행합니다. 이전 Codelab에서 빌드한 GuessTheWord 앱을 시작 코드로 사용하거나 시작 앱을 다운로드할 수 있습니다.

  1. (선택사항) 이전 Codelab의 코드를 사용하지 않는 경우 이 Codelab의 시작 코드를 다운로드하세요. 코드의 압축을 푼 후 Android 스튜디오에서 프로젝트를 엽니다.
  2. 앱을 실행하고 게임을 플레이합니다.
  3. 확인 버튼을 누르면 다음 단어가 표시되고 점수가 1씩 증가하는 반면 건너뛰기 버튼은 다음 단어를 표시하고 점수를 1씩 줄입니다. 게임 종료 버튼을 누르면 게임이 종료됩니다.
  4. 모든 단어를 순환하여 앱에서 점수 화면으로 자동으로 이동하는 것을 알 수 있습니다.

이전 Codelab에서는 데이터 결합을 GuessTheWord 앱에서 뷰에 액세스하는 유형의 안전한 방법으로 사용했습니다. 그러나 데이터 결합의 진정한 강점은 이름에서 알 수 있듯이 앱의 뷰 객체에 직접 데이터를 결합하는 것입니다.

현재 앱 아키텍처

앱에서 뷰는 XML 레이아웃에 정의되며 해당 뷰의 데이터는 ViewModel 객체에 보관됩니다. 각 뷰와 이에 대응하는 ViewModel 사이에는 뷰 간 릴레이 역할을 하는 UI 컨트롤러가 있습니다.

예를 들면 다음과 같습니다.

  • Got It 버튼은 game_fragment.xml 레이아웃 파일에서 Button 뷰로 정의됩니다.
  • 사용자가 Got It 버튼을 탭하면 GameFragment 프래그먼트의 클릭 리스너가 GameViewModel에서 해당 클릭 리스너를 호출합니다.
  • 점수가 GameViewModel에 업데이트됩니다.

Button 뷰와 GameViewModel는 직접 통신하지 않으므로 GameFragment에 클릭 리스너가 필요합니다.

데이터 결합에 전달된 ViewModel

UI 컨트롤러가 중개자로 의존하지 않고 레이아웃의 뷰가 ViewModel 객체의 데이터와 직접 통신하면 더 간단합니다.

ViewModel 객체는 GuessTheWord 앱의 모든 UI 데이터를 보유합니다. ViewModel 객체를 데이터 결합에 전달하면 뷰와 ViewModel 객체 간의 일부 커뮤니케이션을 자동화할 수 있습니다.

이 작업에서는 GameViewModelScoreViewModel 클래스를 해당 XML 레이아웃과 연결합니다. 리스너 이벤트를 설정하여 클릭 이벤트를 처리할 수도 있습니다.

1단계: GameViewModel의 데이터 결합 추가

이 단계에서는 GameViewModel를 상응하는 레이아웃 파일 game_fragment.xml와 연결합니다.

  1. game_fragment.xml 파일에서 GameViewModel 유형의 데이터 결합 변수를 추가합니다. Android 스튜디오에서 오류가 발생하면 프로젝트를 정리하고 다시 빌드합니다.
<layout ...>

   <data>

       <variable
           name="gameViewModel"
           type="com.example.android.guesstheword.screens.game.GameViewModel" />
   </data>
  
   <androidx.constraintlayout...
  1. GameFragment 파일에서 GameViewModel를 데이터 결합에 전달합니다.

    이렇게 하려면 viewModel를 이전 단계에서 선언한 binding.gameViewModel 변수에 할당합니다. viewModel이 초기화된 후 이 코드를 onCreateView() 내부에 배치합니다. Android 스튜디오에서 오류가 발생하면 프로젝트를 정리하고 다시 빌드합니다.
// Set the viewmodel for databinding - this allows the bound layout access 
// to all the data in the ViewModel
binding.gameViewModel = viewModel

2단계: 이벤트 처리에 리스너 결합 사용

리스너 결합onClick(), onZoomIn(), onZoomOut()와 같은 이벤트가 트리거될 때 실행되는 결합 표현식입니다. 리스너 결합은 람다 표현식으로 작성됩니다.

데이터 결합은 리스너를 생성하고 뷰에 리스너를 설정합니다. 수신 대기 이벤트가 발생하면 리스너는 람다 표현식을 평가합니다. 리스너 결합은 Android Gradle 플러그인 버전 2.0 이상에서 작동합니다. 자세한 내용은 레이아웃 및 결합 표현식을 참고하세요.

이 단계에서는 GameFragment의 클릭 리스너를 game_fragment.xml 파일의 리스너 결합으로 바꿉니다.

  1. game_fragment.xml에서 onClick 속성을 skip_button에 추가합니다. 결합 표현식을 정의하고 GameViewModel에서 onSkip() 메서드를 호출합니다. 이러한 결합 표현식을 리스너 결합이라고 합니다.
<Button
   android:id="@+id/skip_button"
   ...
   android:onClick="@{() -> gameViewModel.onSkip()}"
   ... />
  1. 마찬가지로 correct_button의 클릭 이벤트를 GameViewModelonCorrect() 메서드에 바인딩합니다.
<Button
   android:id="@+id/correct_button"
   ...
   android:onClick="@{() -> gameViewModel.onCorrect()}"
   ... />
  1. end_game_button의 클릭 이벤트를 GameViewModelonGameFinish() 메서드에 결합합니다.
<Button
   android:id="@+id/end_game_button"
   ...
   android:onClick="@{() -> gameViewModel.onGameFinish()}"
   ... />
  1. GameFragment에서 클릭 리스너를 설정하는 문을 삭제하고 클릭 리스너가 호출하는 함수를 삭제합니다. 더 이상 필요하지 않습니다.

삭제할 코드:

binding.correctButton.setOnClickListener { onCorrect() }
binding.skipButton.setOnClickListener { onSkip() }
binding.endGameButton.setOnClickListener { onEndGame() }

/** Methods for buttons presses **/
private fun onSkip() {
   viewModel.onSkip()
}
private fun onCorrect() {
   viewModel.onCorrect()
}
private fun onEndGame() {
   gameFinished()
}

3단계: ScoreViewModel의 데이터 결합 추가

이 단계에서는 ScoreViewModel를 상응하는 레이아웃 파일 score_fragment.xml와 연결합니다.

  1. score_fragment.xml 파일에서 ScoreViewModel 유형의 결합 변수를 추가합니다. 이 단계는 위의 GameViewModel에 실행한 과정과 유사합니다.
<layout ...>
   <data>
       <variable
           name="scoreViewModel"
           type="com.example.android.guesstheword.screens.score.ScoreViewModel" />
   </data>
   <androidx.constraintlayout.widget.ConstraintLayout
  1. score_fragment.xml에서 onClick 속성을 play_again_button에 추가합니다. 리스너 결합을 정의하고 ScoreViewModel에서 onPlayAgain() 메서드를 호출합니다.
<Button
   android:id="@+id/play_again_button"
   ...
   android:onClick="@{() -> scoreViewModel.onPlayAgain()}"
   ... />
  1. ScoreFragmentonCreateView() 내에서 viewModel를 초기화합니다. 그런 다음 binding.scoreViewModel 결합 변수를 초기화합니다.
viewModel = ...
binding.scoreViewModel = viewModel
  1. ScoreFragment에서 playAgainButton의 클릭 리스너를 설정하는 코드를 삭제합니다. Android 스튜디오에 오류가 표시되면 프로젝트를 정리하고 다시 빌드합니다.

삭제할 코드:

binding.playAgainButton.setOnClickListener {  viewModel.onPlayAgain()  }
  1. 앱을 실행합니다. 앱이 이전과 동일하게 작동하지만 이제 버튼 뷰가 ViewModel 객체와 직접 통신합니다. 뷰가 더 이상 ScoreFragment의 버튼 클릭 핸들러를 통해 통신하지 않습니다.

데이터 결합 오류 메시지 문제 해결

앱에서 데이터 결합을 사용하면 컴파일 프로세스에서 데이터 결합에 사용되는 중간 클래스를 생성합니다. 앱을 컴파일하려고 시도할 때까지 Android 스튜디오가 감지할 수 없는 오류가 있을 수 있으므로, 개발자가 코드를 작성하는 동안에는 경고 또는 빨간색 코드가 표시되지 않습니다. 그러나 컴파일 시 생성된 중간 클래스에서 발생하는 암호화된 오류가 발생합니다.

암호화 오류 메시지가 표시되는 경우 다음 안내를 따르세요.

  1. Android 스튜디오 Build 창의 메시지를 자세히 살펴보세요. databinding로 끝나는 위치가 표시되면 데이터 결합에 오류가 있는 것입니다.
  2. 레이아웃 XML 파일에서 데이터 결합을 사용하는 onClick 속성의 오류가 있는지 확인합니다. 람다 표현식이 호출하는 함수를 찾아 존재하는지 확인합니다.
  3. XML의 <data> 섹션에서 데이터 결합 변수의 철자를 확인합니다.

예를 들어 다음 속성 값에서 함수 이름 onCorrect()의 철자 오류에 유의하세요.

android:onClick="@{() -> gameViewModel.onCorrectx()}"

XML 파일의 <data> 섹션에서도 gameViewModel 철자가 틀렸습니다.

<data>
   <variable
       name="gameViewModelx"
       type="com.example.android.guesstheword.screens.game.GameViewModel" />
</data>

Android 스튜디오는 앱을 컴파일할 때까지 이러한 오류를 감지하지 않으며 컴파일러는 다음과 같은 오류 메시지를 표시합니다.

error: cannot find symbol
import com.example.android.guesstheword.databinding.GameFragmentBindingImpl"

symbol:   class GameFragmentBindingImpl
location: package com.example.android.guesstheword.databinding

데이터 결합은 ViewModel 객체와 함께 사용되는 LiveData에서 잘 작동합니다. 이제 ViewModel 객체에 데이터 결합을 추가했으므로 LiveData를 통합할 준비가 되었습니다.

이 작업에서는 LiveData 관찰자 메서드를 사용하지 않고 UI에 데이터 변경사항을 알리기 위해 LiveData를 데이터 결합 소스로 사용하도록 GuessTheWord 앱을 변경합니다.

1단계: game_fragment.xml 파일에 단어 LiveData 추가하기

이 단계에서는 현재 단어 텍스트 뷰를 ViewModelLiveData 객체에 직접 바인딩합니다.

  1. game_fragment.xml에서 word_text 텍스트 뷰에 android:text 속성을 추가합니다.

결합 변수 gameViewModel을 사용하여 GameViewModel에서 word로 설정된 LiveData 객체로 설정합니다.

<TextView
   android:id="@+id/word_text"
   ...
   android:text="@{gameViewModel.word}"
   ... />

word.value를 사용할 필요는 없습니다. 대신 실제 LiveData 객체를 사용하면 됩니다. LiveData 객체는 word의 현재 값을 표시합니다. word 값이 null이면 LiveData 객체는 빈 문자열을 표시합니다.

  1. GameFragmentonCreateView()에서 gameViewModel를 초기화한 후 현재 활동을 binding 변수의 수명 주기 소유자로 설정합니다. 이 메서드는 위의 LiveData 객체의 범위를 정의하여 객체가 game_fragment.xml 레이아웃에서 뷰를 자동으로 업데이트할 수 있도록 합니다.
binding.gameViewModel = ...
// Specify the current activity as the lifecycle owner of the binding.
// This is used so that the binding can observe LiveData updates
binding.lifecycleOwner = this
  1. GameFragment에서 LiveData word의 관찰자를 삭제합니다.

삭제할 코드:

/** Setting up LiveData observation relationship **/
viewModel.word.observe(this, Observer { newWord ->
   binding.wordText.text = newWord
})
  1. 앱을 실행하고 게임을 플레이합니다. 이제 현재 단어가 UI 컨트롤러에 관찰자 메서드 없이 업데이트됩니다.

2단계: Score_fragment.xml 파일에 점수 LiveData 추가하기

이 단계에서는 LiveData score를 점수 프래그먼트의 점수 텍스트 뷰에 바인딩합니다.

  1. score_fragment.xml에서 점수 텍스트 뷰에 android:text 속성을 추가합니다. text 속성에 scoreViewModel.score를 할당합니다. score은 정수이므로 String.valueOf()를 사용해 문자열로 변환합니다.
<TextView
   android:id="@+id/score_text"
   ...
   android:text="@{String.valueOf(scoreViewModel.score)}"
   ... />
  1. ScoreFragment에서 scoreViewModel를 초기화한 후 현재 활동을 binding 변수의 수명 주기 소유자로 설정합니다.
binding.scoreViewModel = ...
// Specify the current activity as the lifecycle owner of the binding.
// This is used so that the binding can observe LiveData updates
binding.lifecycleOwner = this
  1. ScoreFragment에서 score 객체의 관찰자를 삭제합니다.

삭제할 코드:

// Add observer for score
viewModel.score.observe(this, Observer { newScore ->
   binding.scoreText.text = newScore.toString()
})
  1. 앱을 실행하고 게임을 플레이합니다. 점수 프래그먼트의 점수는 점수 프래그먼트에서 관찰자 없이 올바르게 표시됩니다.

3단계: 데이터 결합으로 문자열 형식 추가

레이아웃에서 데이터 결합과 함께 문자열 형식을 추가할 수 있습니다. 이 작업에서는 현재 단어의 형식을 지정하여 주위에 따옴표를 추가합니다. 또한 다음 이미지에 표시된 것처럼 점수 문자열을 현재 점수라는 프리픽스로 지정합니다.

  1. string.xml에서 wordscore 텍스트 뷰의 형식을 지정하는 데 사용할 다음 문자열을 추가합니다. %s%d는 현재 단어와 현재 점수의 자리표시자입니다.
<string name="quote_format">\"%s\"</string>
<string name="score_format">Current Score: %d</string>
  1. game_fragment.xml에서 quote_format 문자열 리소스를 사용하도록 word_text 텍스트 뷰의 text 속성을 업데이트합니다. gameViewModel.word을 전달합니다. 그러면 현재 단어가 서식 문자열에 인수로 전달됩니다.
<TextView
   android:id="@+id/word_text"
   ...
   android:text="@{@string/quote_format(gameViewModel.word)}"
   ... />
  1. score 텍스트 뷰의 형식을 word_text와 비슷하게 지정합니다. game_fragment.xml에서 text 속성을 score_text 텍스트 뷰에 추가합니다. %d 자리표시자로 표시되는 숫자 인수 1개를 사용하는 문자열 리소스 score_format를 사용합니다. LiveData 객체 score을 이 형식 지정 문자열의 인수로 전달합니다.
<TextView
   android:id="@+id/score_text"
   ...
   android:text="@{@string/score_format(gameViewModel.score)}"
   ... />
  1. GameFragment 클래스의 onCreateView() 메서드 내에서 score 관찰자 코드를 삭제합니다.

삭제할 코드:

viewModel.score.observe(this, Observer { newScore ->
   binding.scoreText.text = newScore.toString()
})
  1. 앱을 정리, 재구성, 실행한 다음 게임을 플레이합니다. 현재 단어와 점수의 형식이 게임 화면에 표시됩니다.

수고하셨습니다. LiveDataViewModel를 앱에 데이터 결합과 통합했습니다. 이렇게 하면 레이아웃의 뷰가 프래그먼트에서 클릭 핸들러를 사용하지 않고도 ViewModel와 직접 통신할 수 있습니다. 또한 LiveData 객체를 데이터 결합 소스로 사용하여 LiveData 관찰자 메서드 없이 데이터 변경사항을 UI에 자동으로 알립니다.

Android 스튜디오 프로젝트: GuessTheWord

  • 데이터 결합 라이브러리는 ViewModel, LiveData 등의 Android 아키텍처 구성요소와 원활하게 연동됩니다.
  • 앱의 레이아웃은 이미 UI 컨트롤러의 수명 주기를 관리하고 데이터 변경사항에 관해 알리는 데 도움이 되는 아키텍처 구성요소의 데이터에 바인딩될 수 있습니다.

ViewModel 데이터 결합

  • 데이터 결합을 사용하여 ViewModel을 레이아웃과 연결할 수 있습니다.
  • ViewModel 객체에는 UI 데이터가 있습니다. ViewModel 객체를 데이터 결합에 전달하면 뷰와 ViewModel 객체 간의 일부 커뮤니케이션을 자동화할 수 있습니다.

ViewModel를 레이아웃과 연결하는 방법은 다음과 같습니다.

  • 레이아웃 파일에서 ViewModel 유형의 데이터 결합 변수를 추가합니다.
   <data>

       <variable
           name="gameViewModel"
           type="com.example.android.guesstheword.screens.game.GameViewModel" />
   </data>
  • GameFragment 파일에서 GameViewModel를 데이터 결합에 전달합니다.
binding.gameViewModel = viewModel

리스너 결합

  • 리스너 결합onClick()와 같은 클릭 이벤트가 트리거될 때 실행되는 레이아웃의 결합 표현식입니다.
  • 리스너 결합은 람다 표현식으로 작성됩니다.
  • 리스너 결합을 사용하여 UI 컨트롤러의 클릭 리스너를 레이아웃 파일의 리스너 결합으로 대체합니다.
  • 데이터 결합은 리스너를 생성하고 뷰에 리스너를 설정합니다.
 android:onClick="@{() -> gameViewModel.onSkip()}"

데이터 결합에 LiveData 추가하기

  • LiveData 객체를 데이터 결합 소스로 사용하여 데이터 변경을 UI에 자동으로 알릴 수 있습니다.
  • 뷰를 ViewModelLiveData 객체에 직접 결합할 수 있습니다. ViewModelLiveData가 변경되면 UI 컨트롤러의 관찰자 메서드 없이 레이아웃의 뷰를 자동으로 업데이트할 수 있습니다.
android:text="@{gameViewModel.word}"
  • LiveData 데이터 결합이 작동하도록 하려면 현재 활동 (UI 컨트롤러)을 UI 컨트롤러에서 binding 변수의 수명 주기 소유자로 설정합니다.
binding.lifecycleOwner = this

데이터 결합을 사용한 문자열 형식 지정

  • 데이터 결합을 사용하면 문자열의 경우 %s, 정수의 경우 %d 같은 자리표시자로 문자열 리소스의 형식을 지정할 수 있습니다.
  • 뷰의 text 속성을 업데이트하려면 LiveData 객체를 서식 문자열의 인수로 전달합니다.
 android:text="@{@string/quote_format(gameViewModel.word)}"

Udacity 과정:

Android 개발자 문서:

이 섹션에는 강사가 진행하는 과정의 일부로 이 Codelab을 통해 작업하는 학생들의 숙제 과제가 나와 있습니다. 강사는 다음을 처리합니다.

  • 필요한 경우 과제를 할당합니다.
  • 학생에게 과제 과제를 제출하는 방법을 알려주세요.
  • 과제 과제를 채점합니다.

강사는 이러한 추천을 원하는 만큼 사용할 수 있으며 다른 적절한 숙제를 할당해도 좋습니다.

이 Codelab을 직접 학습하고 있다면 언제든지 숙제를 통해 지식을 확인해 보세요.

답변

질문 1

리스너 결합과 관련하여 다음 설명 중 참이 아닌 것은 무엇인가요?

  • 리스너 결합은 이벤트가 발생할 때 실행되는 결합 표현식입니다.
  • 리스너 결합은 모든 버전의 Android Gradle 플러그인에서 작동합니다.
  • 리스너 결합은 람다 표현식으로 작성됩니다.
  • 리스너 결합은 메서드 참조와 비슷하지만, 리스너 결합을 사용하면 임의의 데이터 결합 표현식을 실행할 수 있습니다.

질문 2

앱에 다음 문자열 리소스가 포함되어 있다고 가정합니다.
<string name="generic_name">Hello %s</string>

다음 중 데이터 결합 표현식을 사용하여 문자열의 형식을 지정하기 위한 올바른 구문은 무엇인가요?

  • android:text= "@{@string/generic_name(user.name)}"
  • android:text= "@{string/generic_name(user.name)}"
  • android:text= "@{@generic_name(user.name)}"
  • android:text= "@{@string/generic_name,user.name}"

질문 3

리스너 결합 표현식은 언제 평가되고 실행되나요?

  • LiveData으로 보유한 데이터가 변경된 경우
  • 구성 변경으로 인해 활동이 다시 생성될 때
  • onClick()와 같은 이벤트가 발생할 때
  • 활동이 백그라운드로 전환될 때

다음 강의 시작: 5.4: LiveData 변환

이 과정의 다른 Codelab 링크는 Android Kotlin 기초 Codelab 방문 페이지를 참고하세요.