Unit 3: Navigation (6)

quokka·2021년 11월 14일
0

Android Basics in Kotlin

목록 보기
15/25
post-thumbnail

LiveData

LiveData는 수명 주기를 인식하는 observable 데이터 홀더 클래스이다.

  • LiveData는 데이터를 가지고 있다. 모든 유형의 데이터에 사용할 수 있는 wrapper.

  • LiveData is observable. 즉, LiveData 객체에서 보유한 데이터가 변경되면 observer에게 알림이 간다.

  • LiveData는 수명 주기를 인식합니다. LiveData에 observer를 연결하면 observer는 LifecycleOwner(일반적으로 activity 또는 fragment)와 연결된다. LiveData는 STARTED 또는 RESUMED 같은 활성 수명 주기 상태인 observer만 업데이트한다.

 

Unsramble 앱에서 화면에 새로운 단어를 표시할 때 updateNextWordOnScreen() 메서드가 호출되고, 이것은 onViewCreated(), restartGame(), onSkipWord(), onSubmitWord() 메서드에서 호출된다.

Livedata를 사용하면 UI를 업데이트하기 위해 여러 위치에서 이 메서드를 호출하지 않아도 된다.

현재 단어를 LiveData로

GameViewModel의 현재 단어를 LiveData로 변환하여 데이터를 LiveData로 래핑하는 방법을 알아본다. 이후 이 LiveData 객체에 관찰자를 추가하고 LiveData를 관찰하는 방법을 알아볼 것이다.

1. String -> MutableLiveData<String>

String 타입이었던 _currentScrambledWord를 MutableLiveData<String>타입으로 변경한다.

private val _currentScrambledWord = MutableLiveData<String>()

2. .value로 수정

_currentScrambledWord를 사용하는 곳이 있다면 _currentScrambledWord.value로 수정한다.

3. _score, _currentWordCount도 LiveData로 수정

마찬가지로 _score_currentWordCountMutableLiveData<>로 변경하고 사용되는 곳에 .value를 사용한다. (이제 정수 타입이 아니라 LiveData 타입이니까!)

4. += → plus(), ++ → inc()

null에 안전하게 덧셈처리 하려면 plus()를 사용한다.
_score+=SCORE_INCREASE_score.value = (_score.value)?.plus(SCORE_INCREASE)

증감연산자++도 null 안전하게 _currentWordCount.value = (_currentWordCount.value)?.inc()

 

LiveData 객체에 관찰자 연결 (onCreateView에서)

updateNextWordOnScreen()을 삭제하고 LiveData 관찰자에서 자동으로 업데이트한다.

GameFragmentonViewCreated()에서 observe()를 호출한다.

viewModel.currentScrambledWord.observe(
	viewLifecycleOwner, 
    	{newWord -> binding.textViewUnscrambledWord.text = newWord})

viewLifecycleOwner는 frament의 뷰 수명 주기를 나타낸다.
newWord에는 scamble된 새 단어가 포함된다.
✔ 람다 표현식은 항상 중괄호로 묶는다.

scorewordCount 도 마찬가지로 기존 binding 코드를 observe()로 변경한다.

 

데이터 결합

데이터 결합: 뷰 결합 binding과 개념은 비슷하지만 반대로 뷰(레이아웃 파일)에서 데이터를 참조하는 방식

이전에 배웠던 뷰 결합은 binding.textViewUnscrambledWord.text = viewModel.currentScrambledWord

레이아웃 파일에서 데이터 결합하면? android:text="@{gameViewModel.currentScrambledWord}"

1. gradle

build.gradle(Mudule)에서 builFeature 내부
viewBinding = truedataBinding = true로 변경

buildFeatures {
   dataBinding = true
}

2. data binding layout으로

game_fragment.xml은 ScrollView로 감싸져있다. ScrollView를 클릭 후 전구 모양을 누르면 Convert to data binding layout이 뜬다.
누르면 <layout> 태그가 ScrollView를 감싸고, 내부에 <data>도 추가된다.

3. binding 수정

game_fragment.ktonCreateView()에서 binding 변수를
binding = GameFragmentBinding.inflate(inflater, container, false)에서
binding = DataBindingUtil.inflate(inflater, R.layout.game_fragment, container, false)로 변경

4. <data> 태그

<data> 태그 내부에 데이터 바인딩할 속성을 선언한다.


<variable
          name="gameViewModel"
          type="com.example.android.unscramble.ui.game.GameViewModel" />
<variable
            name="maxNoOfWords"
            type="int" />

5. binding

onViewCreated()에서 변수 초기화

binding.gameViewModel = viewModel
binding.maxNoOfWords = MAX_NO_OF_WORDS

6. viewLifecyclerOwner

레이아웃에 수명 주기 소유자를 전달한다.

binding.lifecycleOwner = viewLifecycleOwner

 

결합 표현식

종속 변수 중 하나라도 변경되면 'DB 라이브러리'가 결합 표현식을 실행하고 이에 따라 뷰가 업데이트된다. 이러한 변경 감지는 데이터 결합 라이브러리를 사용할 때 무료로 제공되는 훌륭한 최적화 기능

예를 들어 아래 코드를 보면 결합 표현식은 @ 기호로 시작하고 중괄호 {}로 둘러싸인다. TextView 텍스트는 user 변수의 firstName 속성으로 설정된다.

<TextView android:layout_width="wrap_content"
          android:layout_height="wrap_content"
          android:text="@{user.firstName}" />

unscrambled word를 결합 표현식으로

game_fragment.xml에서 textView_unscrambled_word 텍스트 뷰에 아래 코드를 추가한다.

android:text="@{gameViewModel.currentScrambledWord}"

currentScrambledWord.observe() 코드 삭제

이제 LiveData 변경사항 업데이트가 레이아웃에 직접 수신되므로 fragment에 관찰자가 필요없다. 즉 GameFragment에서 viewModel.currentScrambledWord.observe()에 대한 코드를 삭제한다.

점수, 단어 수도 수정

점수와 단어 수도 결합 표현식으로 바꾼다.

이 코드 삭제

viewModel.score.observe(viewLifecycleOwner,
   { newScore ->
       binding.score.text = getString(R.string.score, newScore)
   })

viewModel.currentWordCount.observe(viewLifecycleOwner,
   { newWordCount ->
       binding.wordCount.text =
           getString(R.string.word_count, newWordCount, MAX_NO_OF_WORDS)
   })

0개의 댓글