Android Kotlin Fundamentals 05.3 #2 Data binding with ViewModel and LiveData - Add LiveData to databinding

DataBinding은 ViewModel객체와 함께 사용된 LiveData와 잘 동작한다. 현재 ViewModel을 데이터 바인딩 하고 있으니 이제 LiveData를 포함 시킬 준비가 되었다.

 

이번 태스크에서는 GuessTheWord 앱을 LiveData를 데이터 바인딩에 사용하여 data의 변경을 UI에 알려주는 작업을 해 볼 것이다. 이렇게 되면 LiveData를 observer 메소드를 통해 감시할 필요가 없게 된다.

 

Step 1: Add word LiveData to the game_fragment.xml file

 

이번 단계에서는 현재단어를 나타내는 TextView와 ViewModel의 LiveData를 바인딩 시켜 볼 것이다.

 

1. game_fragment.xml에서 word_text id를 가지는 TextView에 android:text를 추가해준다. android:text에 LiveData를 추가해주면 된다. 저번 태스크에서 GameViewModel을 바인딩 시켰으므로 gameViewModel의 word를 셋팅 해 준다.

 

- ViewModel을 layout에 바인딩

<layout ...>

   <data>

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

- 바인딩된 ViewModel의 LiveData를 셋팅

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

 

layout에 정의한 데이터를 보면 word.value를 사용하지 않는다. 대신 진짜 LiveData 객체를 사용할 수 있다. 이 LiveData객체는 word 변수의 현재 값를 나타낸다. 만약 word의 값이 null이라면, LiveData 객체는 빈 스트링값을 나타낼 것이다.

 

2. GameFragment의 onCreateView()안에서 gameViewModel이 초기화 된 후에 현재 액티비티를 binding객체의 lifecycle owner로 지정 해 준다. 이것은 LiveData의 범위를 정의하여 LiveData가 game_fragment.xml 안에서 view들을 자동으로 업데이트 할 수 있게 해준다.

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

 

3. GameFragment에서 Livedata word의 observer를 지운다. 아래의 코드를 지우면 된다.

/** Setting up LiveData observation relationship **/
viewModel.word.observe(this, Observer { newWord ->
   binding.wordText.text = newWord
})

 

4. 앱을 실행 시키고 게임을 플레이 해 본다. 현재 단어가 업데이트 되는 것은 UI Controller(GameFragment)안의 observer없이 업데이트 되는 것이다. 이것은 위에서 LiveData를 view에 직접 바인딩 했기 때문에 가능한 것이다!

 

Step 2: Add score LiveData to the score_fragment.xml file

 

이번 단계에서는 score관련 LiveData를 score fragment안의 score TextView에 바인딩 해 볼 것이다.

 

1. score_fragment.xml안에서 score text view에 android:text 속성을 추가한다. 그리고 scoreViewModel.score을 text속성에 셋팅 해 준다. score는 int값이기 때문에 String.valueOf()를 이용해서 변환 해 준다.

 

<TextView
   android:id="@+id/score_text"
   ...
   android:text="@{String.valueOf(scoreViewModel.score)}"
   ... />

 

2. ScoreFragment안에서 scoreViewModel이 초기화 된 후에 현재 fragment를 binding객체의 lifecycle owner로 지정 해 준다.

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

 

3. ScoreFragment안의 score객체를 감시하고 있던 observer를 제거 해 준다.

// Add observer for score
viewModel.score.observe(this, Observer { newScore ->
   binding.scoreText.text = newScore.toString()
})

 

4. 앱을 실행하고, 게임을 플레이 해 본다. 이제 observer를 LiveData객체에 따로 붙히지 않아도 view에 직접 바인딩 되기 때문에 게임이 잘 진행 된다.

 

Step 3: Add string formatting with data binding

layout안에서 데이터 바인딩과 함께 문자열 형식을 추가할 수 있다. 이번 태스크에서 현재 단어를 "현재단어"로 감싸는 작업을 해 볼 것이다. 하단의 Current Score : 7 과 같이 현재 점수를 나타내는 접두사를 추가 할 수 있다.

1. string.xml안에서 아래의 string value를 추가 해 준다. 해당 문자열은 word와 score를 포맷팅 하는데 사용될 것 이다. %s와 %d는 현재단어 (%s-문자열) 와 현재점수 (%d - 숫자)가 들어갈 자리를 표시하는 것 이다.

 

<string name="quote_format">\"%s\"</string>
<string name="score_format">Current Score: %d</string>

 

2. game_fragment.xml안에서 word_text의 text속성을 quote_format을 통해 업데이트 해 준다. 

 

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

 

3. score_text도 word_text와 유사하게 업데이트 하면 된다. 이때에는 score_format을 이용해서 업데이트 하면 된다.

<TextView
   android:id="@+id/score_text"
   ...
   android:text="@{@string/score_format(gameViewModel.score)}"
   ... />

 

4. game_fragment.xml의 score_text에 LiveData를 바인딩 했으니 GameFragment에서 score_text에 등록한 observer를 제거 해 준다.

viewModel.score.observe(this, Observer { newScore ->
   binding.scoreText.text = newScore.toString()
})

 

5. 프로젝트를 clean, rebuild하고 앱을 실행한다. 그리고 게임을 플레이 해 본다. 현재 단어와 점수들이 아래와 같이 포맷팅 되어 나타나게 된다.

 

댓글



Designed by JB FACTORY