이전 코드랩에서 GuessTheWord App을 구현 할 때, view에 접근하기 위해 data binding을 type-safe 방식으로 사용 하였습니다. 그러나 data binding의 진정한 힘은 view 객체에 데이터를 직접 바인딩 하는 것 입니다.
이전에는 아래와 같이 binding 객체의 scoreText에 접근해서 text를 셋팅 해 주었습니다.
viewModel.score.observe(this, Observer { newScore ->
binding.scoreText.text = newScore.toString();
})
Current app architecture
현재 앱의 구조에 대해 살펴 보겠습니다. 앱에서 View들은 XML문서에 정의되어 있습니다. 그리고 view에 나타내기 위한 data들은 ViewModel에서 관리합니다. 각 view와 연관된 Viewmodel 사이에 UI Controller가있습니다.
예를 들어서
- Got it 버튼은 game_fragment.xml안에 Button View로 정의되어 있습니다.
- 사용자가 Got It 버튼을 눌렀을 때, GameFragment안의 클릭 리스너는 연관된 ViewModel의 클릭 리스너를 호출 합니다.
- 그러면 GameViewModel에서 score가 업데이트 됩니다.
//GameFragment의 클릭 리스너
binding.correctButton.setOnClickListener { onCorrect() }
//GameViewModel의 클릭 리스너
fun onCorrect() {
if (!wordList.isEmpty()) {
score.value?.plus(1)
}
nextWord()
}
Button과 GameViewModel은 직접적으로 커뮤니케이션 하지 않습니다. Button과 ViewModel 커뮤니케이션 하기 위해서는 현재 GameFragment 안에 있는 클릭 리스너가 필요 합니다.
ViewModel passed into the data binding
GameFragment와 같은 UI controller를 거치지 않고, View와 ViewModel이 직접적으로 커뮤니케이션 할 수 있다면 앱은 조금 더 심플해 질것 입니다.
VIewModel 객체는 모든 UI 관련 데이터를 가지고 있습니다. ViewModel 객체를 databinding으로 전달하면 view들과 ViewModel 객체간 커뮤니케이션 중 일부를 자동화 할 수 있습니다.
이번 태스크에서는 GameViewModel과 ScoreViewModle을 관련 레이아웃들과 연결 시켜 볼 것입니다. click이벤트를 다루는 리스너들도 데이터 바인딩 설정을 할 것입니다.
Step 1: Add data binding for the GameViewModel
이번 단계에서 GameViewModel을 game_fragment.xml과 연결 시켜 보겠습니다.
1. game_fragment.xml에서 GameViewModel 타입의 data-binding 변수를 추가 해 주세요. 만약 에러가 난다면 AndroidStudio에서 프로젝트를 clean하고 rebuild 해주세요.
<layout ...>
<data>
<variable
name="gameViewModel"
type="com.example.android.guesstheword.screens.game.GameViewModel" />
</data>
<androidx.constraintlayout...
2. GameFragment에서 GameViewModel을 databinding으로 전달 합니다. viewModel을 바로 위에서 선언한 binding.gameViewModel에 할당해 줘야 합니다. 해당 코드는 onCreateView()안 viewModel이 초기화 된 후에 위치하도록 합니다. 만약 에러가 발생하면 clean - rebuild 해주세요.
viewModel = ViewModelProviders.of(this).get(GameViewModel::class.java)
// Set the viewmodel for databinding - this allows the bound layout access
// to all the data in the ViewModel
binding.gameViewModel = viewModel
Step 2 : Use listener bindings for event handling
Listener bindings는 onClick(), onZoomIn() 또는 onZoomOut과 같은 이벤트가 트리거될 때 실행되는 바인딩 표현식 입니다.
Data binding은 리스너를 생성하고, 리스너를 view에 붙힙니다. 그리고 이벤트가 발생 했을 때, 이를 수신하고, 람다 표현식을 실행 시킵니다. Listener binding은 Android Gradle Plugin 버전 2.0 이상 부터 동작 합니다. 조금 더 배우기 위해 아래 url을 참조 하세요.
https://developer.android.com/topic/libraries/data-binding/expressions#listener_bindings
이번 스텝에서 GameFragment에 정의된 click 리스너들을 game_fragment의 listener binding으로 교체 해 보겠습니다.
1. game_fragment.xml에서 skip_button의 onClick속성에 binding 표현식과 GameViewModel의 onSkip()을 호출하는 코드를 추가 해주세요. 이와 같은 binding 표현식을 listener binding이라고 부릅니다.
<Button
android:id="@+id/skip_button"
...
android:onClick="@{() -> gameViewModel.onSkip()}"
... />
2. onCorrect() 또한 correct_buttion에서 listener binding 시켜 주세요.
<Button
android:id="@+id/correct_button"
...
android:onClick="@{() -> gameViewModel.onCorrect()}"
... />
3. onGameFinish() 또한 마찬가지 입니다. end_game_buttion의 onClick속성에서 listener binding 시켜 주세요.
<Button
android:id="@+id/end_game_button"
...
android:onClick="@{() -> gameViewModel.onGameFinish()}"
... />
Step3 : Add data binding for the ScoreViewModel
이번 단계에서는 ScoreViewModel을 연관된 layout file인 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
2. score_fragment.xml에서 play_again_buttion의 onClick 속성에 listener binding을 정의하고 ScoreViewModel의 onPlayAgain()이 호출 되도록 해 줍니다.
<Button
android:id="@+id/play_again_button"
...
android:onClick="@{() -> scoreViewModel.onPlayAgain()}"
... />
3. In ScoreFragment의 onCreateView()안에서 viewModel을 초기화 해 주고, 그런 다음 binding.scoreViewModel 변수에 해당 ViewModel을 할당 해 줍니다.
viewModel = ViewModelProviders.of(this).get(ScoreViewModel::class.java)
binding.scoreViewModel = viewModel
4. ScoreFragment에서 PlayAgainButtion에 click listener를 셋팅한 부분을 제거해 줍니다. 만약 에러가 발생 한다면 프로젝트를 clean - rebuild 해 주세요.
아래 부분을 제거 하시면 됩니다.
binding.playAgainButton.setOnClickListener { viewModel.onPlayAgain() }
5. 앱은 이전과 같이 동작하지만, 현재 우리의 앱은 view와 viewModel이 직접적으로 통신하고 있습니다. view는 더이상 ui controller을 통해 viewModel과 통신하지 않습니다.
'study' 카테고리의 다른 글
안드로이드 DataBinding, MVVM 구구단 (0) | 2019.12.12 |
---|---|
Android Kotlin Fundamentals 05.3 #2 Data binding with ViewModel and LiveData - Add LiveData to databinding (0) | 2019.12.11 |
Android Kotlin Fundamentals 05.2 #8 :Summary (0) | 2019.12.08 |
파이썬 #1) VSCODE에서 에서 파이썬 개발하기 (0) | 2019.12.06 |
Android Kotlin Fundamentals 05.2 #7 :Task: Add the Play Again button (0) | 2019.12.02 |