우리는 사실 이전 코드랩에서 데이터바인딩을 사용했지만 이는 뷰에 접근할 때, 안전한 방식으로만 사용했다.
하지만, 데이터바인딩의 정수는 이름에서 알 수 있듯이 데이터를 뷰 객체에 직접 바인딩하는 것이다.
현재 우리가 수정한 앱의 구조는 뷰들은 xml에 정의되어 있고, 뷰들을 위한 데이터는 ViewModel에서 가지고 있다.
그리고 각 뷰와 ViewModel 사이에는 UI controller가 있다.
이 때, UI controller를 중개인처럼 사용하지 않고 레이아웃의 뷰가 ViewModel 객체의 데이터와 직접 통신한다면 더 간단할 것이다.
ViewModel 객체를 데이터 바인딩으로 전달하면 뷰와 ViewModel 객체 간의 통신을 어느 정도 자동화할 수 있다.
Add data binding for the GameViewModel
1. game_fragment.xml 파일에 GameViewModel 타입의 데이터 바인딩 변수를 추가한다.
<layout ...>
<data>
<variable
name="gameViewModel"
type="com.example.android.guesstheword.screens.game.GameViewModel" />
</data>
<androidx.constraintlayout...
2. GameFragment 파일에서 GameViewModel을 데이터 바인딩으로 전달한다.
이를 진행하려면, viewModel을 binding.gameViewModel 변수에 할당해주어야 한다.
onCreateView안에서 viewModel 초기화 후 아래 코드를 넣는다.
// Set the viewmodel for databinding - this allows the bound layout access
// to all the data in the ViewModel
binding.gameViewModel = viewModel
Use event binding for event handling
리스너 바인딩은 onClick과 같은 이벤트가 발생될 때 실행되는 바인딩 표현식이다. 또한 이는 람다식으로 작성된다.
데이터 바인딩은 리스너를 만들고 뷰에 리스너를 설정한다. 리스너는 수신하기로 한 이벤트가 발생하면 람다식을 실행한다.
이번에는 GameFragment에 있는 리스너를 game_fragment.xml에 있는 리스너 바인딩으로 대체할 것이다.
1. game_fragment.xml에 skip button에 onClick 속성을 추가한다.
바인딩 표현식을 정의하고 GameViewModel에 있는 onSkip 메소드를 호출한다.
이 바인딩 표현식을 리스너 바인딩이라고 한다.
<Button
android:id="@+id/skip_button"
...
android:onClick="@{() -> gameViewModel.onSkip()}"
... />
2. 비슷하게 correct button의 클릭 이벤트도 GameViewModel의 onCorrect 메소드를 바인딩한다.
<Button
android:id="@+id/correct_button"
...
android:onClick="@{() -> gameViewModel.onCorrect()}"
... />
3. 마지막으로 남은 end game button도 GameViewModel의 onGameFinish 메소드를 바인딩한다.
<Button
android:id="@+id/end_game_button"
...
android:onClick="@{() -> gameViewModel.onGameFinish()}"
... />
4. 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()
}
Add data binding for the 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
2. score_fragment.xml의 play again button에 onClick 속성을 추가한다.
바인딩 표현식을 정의하고 ScoreViewModel의 onPlayAgain 메소드를 호출한다.
<Button
android:id="@+id/play_again_button"
...
android:onClick="@{() -> scoreViewModel.onPlayAgain()}"
... />
3. ScoreFragment의 onCreateView안에서 viewModel을 초기화한다. 이후 binding.scoreViewModel을 초기화한다.
viewModel = ...
binding.scoreViewModel = viewModel
4. ScoreFragment에서 play again button의 리스너를 설정하는 코드를 삭제한다.
binding.playAgainButton.setOnClickListener { viewModel.onPlayAgain() }
5. 앱을 실행한다. 동작은 이전과 같아야 한다. 하지만, 이제 버튼들은 ViewModel 객체와 직접 통신한다.
그리고 아래에 데이터 바인딩을 사용하며 나오는 에러 메시지를 해결하는 방법을 소개하고 있다.
xml에서 variable을 정의할 때 오타가 있거나 onClick 속성에서 호출하는 함수의 이름에 오타가 있을 경우
이를 안드로이드 스튜디오에서 사전에 검출해내지 못한다고 한다.
'Android' 카테고리의 다른 글
Codelab으로 DataBinding 알아보기 - 4. 정리(完) (1) | 2023.05.17 |
---|---|
Codelab으로 DataBinding 알아보기 - 3. Add LiveData to data binding (0) | 2023.05.14 |
Codelab으로 DataBinding 알아보기 - 1. 과정 소개 (0) | 2023.05.09 |
안드로이드 FCM 백그라운드 푸시 알림 받기 (4) | 2023.05.08 |
카카오톡 공유 앱 이름 바꾸기 (0) | 2023.05.06 |