Nos tutoriais anteriores desta lição, você aprimorou o código do aplicativo GuessTheWord. O aplicativo agora
usa objetos ViewModel
, para que os dados do aplicativo sobrevivam às mudanças de configuração
do dispositivo, como rotações de tela e mudanças na disponibilidade do teclado. Você também adicionou
LiveData
observável, para que as vistas sejam notificadas automaticamente quando os dados forem
observados.
Neste tutorial, você continuará trabalhando com o aplicativo GuessTheWord. Você vincula vistas às classes
ViewModel
no aplicativo para que as vistas em seu layout se comuniquem diretamente com os
objetos ViewModel
. (Até agora, em seu aplicativo, as vistas se comunicaram
indiretamente com o ViewModel
, por meio dos fragmentos do aplicativo). Depois de
integrar a vinculação de dados ao ViewModel
objetos, você não precisa mais de tratadores de
clique nos fragmentos do aplicativo, portanto, você os remove.
Você também altera o aplicativo GuessTheWord para usar LiveData
como a fonte de vinculação de
dados para notificar a IU sobre as alterações nos dados, sem usar métodos de observador
LiveData
.
ViewModel
em seu aplicativo.LiveData
em um ViewModel
.LiveData
.ViewModel
com vinculação de dados.LiveData
com vinculação de dados.ViewModel
, usando
controladores de IU (fragmentos) para retransmitir informações. Neste tutorial, você vincula as vistas do
aplicativo a objetos ViewModel
para que as vistas se comuniquem diretamente com os
objetos ViewModel
.LiveData
como a fonte de vinculação de dados. Após essa
alteração, os objetos LiveData
notificam a IU sobre as alterações nos dados e os métodos do
observador LiveData
não são mais necessários.Nos tutoriais da Lição 5, você desenvolve o aplicativo GuessTheWord, começando com o código inicial. GuessTheWord é um jogo de estilo charadas para dois jogadores, onde os jogadores colaboram para atingir a pontuação mais alta possível.
O primeiro jogador olha para as palavras no aplicativo e representa cada uma delas, tomando cuidado para não mostrar a palavra ao segundo jogador. O segundo jogador tenta adivinhar a palavra.
Para jogar, o primeiro jogador abre o aplicativo no dispositivo e vê uma palavra, por exemplo "guitarra", conforme mostrado na imagem abaixo.
O primeiro jogador representa a palavra, tomando cuidado para não dizer a palavra em si.
Neste tutorial, você aprimora o aplicativo GuessTheWord integrando vinculação de dados com
LiveData
em objetos ViewModel
. Isso automatiza a comunicação entre as vistas no
layout e os objetos ViewModel
, e permite simplificar seu código usando LiveData
.
Tela principal |
Tela do jogo |
Tela de pontuação |
Nesta tarefa, você localiza e executa seu código inicial para este tutorial. Você pode usar o aplicativo GuessTheWord que você construiu no tutorial anterior como seu código inicial ou pode baixar um aplicativo inicial.
Em um tutorial anterior, você usou a vinculação de dados com segurança de tipos para acessar as vistas no aplicativo GuessTheWord. Mas o verdadeiro poder da vinculação de dados está em fazer o que o nome sugere: Vinculando dados diretamente aos objetos de vistas em seu aplicativo.
Arquitetura atual do aplicativo
Em seu aplicativo, as vistas são definidas no layout XML e os dados para essas vistas são mantidos em
objetos ViewModel
. Entre cada vista e seu ViewModel
correspondente está um
controlador de IU, que atua como um retransmissor entre eles.
Por exemplo:
Button
no arquivo de layout
game_fragment.xml
. GameFragment
chama o ouvinte de clique correspondente em GameViewModel
. GameViewModel
.A vista Button
e o GameViewModel
não se comunicam diretamente - eles precisam do
ouvinte de cliques que está no GameFragment
.
ViewModel passado para a vinculação de dados
Seria mais simples se as vistas no layout se comunicassem diretamente com os dados nos objetos
ViewModel
, sem depender de controladores de IU como intermediários.
Os objetos ViewModel
contêm todos os dados da IU no aplicativo GuessTheWord. Ao passar objetos
ViewModel
para a vinculação de dados, você pode automatizar parte da comunicação entre as
vistas e os objetos ViewModel
.
Nesta tarefa, você associa as classes GameViewModel
e ScoreViewModel
com seus
layouts XML correspondentes. Você também configura vinculações de ouvinte para manipular eventos de clique.
Nesta etapa, você associa GameViewModel
ao arquivo de layout correspondente,
game_fragment.xml
.
game_fragment.xml
, adicione uma variável de vinculação de dados do tipo
GameViewModel
. Se houver erros no Android Studio, limpe e reconstrua o projeto.<layout ...>
<data>
<variable
name="gameViewModel"
type="com.example.android.guesstheword.screens.game.GameViewModel" />
</data>
<androidx.constraintlayout...
GameFragment
, passe o GameViewModel
para a vinculação de
dados.viewModel
ao binding.gameViewModel
, que
você declarou na etapa anterior. Coloque este código dentro de onCreateView()
, após o
viewModel
ser inicializado. Se houver erros no Android Studio, limpe e
reconstrua o projeto.binding.gameViewModel = viewModel
Vinculações de ouvinte são expressões de vinculação executadas quando
eventos como onClick()
, onZoomIn()
ou onZoomOut()
são acionados. As
vinculações do ouvinte são escritas como expressões lambda.
A vinculação de dados cria um ouvinte e define o ouvinte na exibição. Quando o evento ouvido acontece, o ouvinte avalia a expressão lambda. As vinculações de ouvinte funcionam com o Android Gradle Plugin versão 2.0 ou superior. Para saber mais, leia Layouts e expressões de vinculação.
Nesta etapa, você substitui os ouvintes de clique no GameFragment
pelos vínculos do ouvinte no
arquivo game_fragment.xml
.
game_fragment.xml
, adicione o atributo onClick
ao
skip_button
. Defina uma expressão de vinculação e chame o método
onSkip()
no GameViewModel
. Esta expressão de vinculação é chamada de
vinculação de ouvinte.
<Button
android:id="@+id/skip_button"
...
android:onClick="@{() -> gameViewModel.onSkip()}"
... />
correct_button
ao método
onCorrect
()
no GameViewModel
.<Button
android:id="@+id/correct_button"
...
android:onClick="@{() -> gameViewModel.onCorrect()}"
... />
end_game_button
ao método
onGameFinish
()
no método GameViewModel
.<Button
android:id="@+id/end_game_button"
...
android:onClick="@{() -> gameViewModel.onGameFinish()}"
... />
GameFragment
, remova as instruções que definem os ouvintes de clique e remova as funções
que os ouvintes de clique chamam. Você não precisa mais deles. Código para remover:
binding.correctButton.setOnClickListener { onCorrect() }
binding.skipButton.setOnClickListener { onSkip() }
binding.endGameButton.setOnClickListener { onEndGame() }
private fun onSkip() {
viewModel.onSkip()
}
private fun onCorrect() {
viewModel.onCorrect()
}
private fun onEndGame() {
gameFinished()
}
Nesta etapa, você associa ScoreViewModel
ao arquivo de layout correspondente,
score_fragment.xml
.
score_fragment.xml
, adicione uma variável de vinculação do tipo
ScoreViewModel
. Esta etapa é semelhante ao que você fez para GameViewModel
acima.
<layout ...>
<data>
<variable
name="scoreViewModel"
type="com.example.android.guesstheword.screens.score.ScoreViewModel" />
</data>
<androidx.constraintlayout.widget.ConstraintLayout
score_fragment.xml
, adicione o atributo onClick
ao
play_again_button
. Defina uma vinculação de ouvinte e chame o método
onPlayAgain()
no ScoreViewModel
.<Button
android:id="@+id/play_again_button"
...
android:onClick="@{() -> scoreViewModel.onPlayAgain()}"
... />
ScoreFragment
, dentro de onCreateView()
, inicialize o
viewModel
. Em seguida, inicialize a variável de vinculação
binding.scoreViewModel
.viewModel = ...
binding.scoreViewModel = viewModel
ScoreFragment
, remova o código que define o ouvinte de clique para o
playAgainButton
. Se o Android Studio mostrar um erro, limpe e reconstrua o projeto. Código para remover:
binding.playAgainButton.setOnClickListener { viewModel.onPlayAgain() }
ViewModel
. As vistas não se comunicam mais por meio dos
tratadores de clique de botão em ScoreFragment
.Quando um aplicativo usa vinculação de dados, o processo de compilação gera classes intermediárias que são usadas para vinculação de dados. Um aplicativo pode ter erros que o Android Studio não detecta até que você tente compilar o aplicativo, então você não vê avisos ou código vermelho enquanto está escrevendo o código. Mas, em tempo de compilação, você obtém erros crípticos que vêm das classes intermediárias geradas.
Se você receber uma mensagem de erro criptografada:
databinding
, há um erro com a vinculação de dados.onClick
que usam vinculação
de dados. Procure a função que a expressão lambda chama e verifique se ela existe.<data>
do XML, verifique a ortografia da variável de vinculação de dados.
Por exemplo, observe o erro ortografo do nome da função onCorrect()
no seguinte valor de
atributo:
android:onClick="@{() -> gameViewModel.onCorrectx()}"
Observe também o erro ortografo de gameViewModel
na seção <data>
do arquivo
XML:
<data>
<variable
name="gameViewModelx"
type="com.example.android.guesstheword.screens.game.GameViewModel" />
</data>
O Android Studio não detecta erros como esses até que você compile o aplicativo e, em seguida, o compilador
mostra uma mensagem de erro como a seguinte:
error: cannot find symbol import com.example.android.guesstheword.databinding.GameFragmentBindingImpl" symbol: class GameFragmentBindingImpl location: package com.example.android.guesstheword.databinding
A vinculação de dados funciona bem com LiveData
que é usado com objetos ViewModel
.
Agora que você adicionou vinculação de dados aos objetos ViewModel
, você está pronto para
incorporar o LiveData
.
Nesta tarefa, você altera o aplicativo GuessTheWord para usar LiveData
como a fonte de
vinculação de dados para notificar a IU sobre alterações nos dados, sem usar os métodos do observador
LiveData
.
Nesta etapa, você vincula a exibição de texto da palavra atual diretamente ao objeto LiveData
no ViewModel
.
game_fragment.xml
, adicione o atributo android:text
à vista de texto
word_text
.Defina-o como o objeto LiveData
, word
do GameViewModel
, usando a
variável de vinculação, gameViewModel
.
<TextView
android:id="@+id/word_text"
...
android:text="@{gameViewModel.word}"
... />
Observe que você não precisa usar word.value
. Em vez disso, você pode usar o objeto
LiveData
real. O objeto LiveData
exibe o valor atual da word
. Se o
valor de word
for nulo, o objeto LiveData
exibirá uma string vazia.
GameFragment
, em onCreateView()
, após inicializar o
gameViewModel
, defina a vista do fragmento como o proprietário do ciclo de vida da
vinculação binding
variável. Isso define o escopo do objeto LiveData
acima,
permitindo que o objeto atualize automaticamente as vistas no layout, game_fragment.xml
.
binding.gameViewModel = ...
binding.lifecycleOwner = viewLifecycleOwner
GameFragment
, remova o observador para a LiveData
word
. Código para remover:
viewModel.word.observe(viewLifecycleOwner, Observer { newWord ->
binding.wordText.text = newWord
})
Nesta etapa, você vincula o LiveData
score
à vista do texto da partitura no
fragmento da partitura.
score_fragment.xml
, adicione o atributo android:text
à
vista do texto da pontuação. Atribua scoreViewModel.score
ao atributo
text
. Como score
é um inteiro, converta-o em
uma string usando String.valueOf()
.<TextView
android:id="@+id/score_text"
...
android:text="@{String.valueOf(scoreViewModel.score)}"
... />
ScoreFragment
, após inicializar o scoreViewModel
, defina a
atividade atual como o proprietário do ciclo de vida da variável binding
. binding.scoreViewModel = ...
binding.lifecycleOwner = viewLifecycleOwner
ScoreFragment
, remova o observador para o objeto score
.Código para remover:
viewModel.score.observe(viewLifecycleOwner, Observer { newScore ->
binding.scoreText.text = newScore.toString()
})
No layout, você pode adicionar formatação de string junto com a vinculação de dados. Nesta tarefa, você formata a palavra atual para adicionar aspas ao redor dela. Você também formata a sequência de pontuação para prefixar a Current Score, conforme mostrado na imagem a seguir.
string.xml
, adicione as seguintes strings, que você usará para formatar as vistas de
texto de word
e score
. Os %s
e %d
são os espaços
reservados para a palavra e pontuação atuais.<string name="quote_format">\"%s\"</string>
<string name="score_format">Current Score: %d</string>
game_fragment.xml
, atualize o atributo text
da vista de texto
word_text
para usar o quote_format
recurso de
string. Passe gameViewModel.word
. Isso passa a palavra atual como um argumento para a string
de formatação.<TextView
android:id="@+id/word_text"
...
android:text="@{@string/quote_format(gameViewModel.word)}"
... />
score
semelhante ao word_text
. No
game_fragment.xml
, adicione o atributo text
à vista de texto
score_text
. Use o recurso de string
score_format
, que recebe um argumento numérico, representado pelo espaço
reservado %d
. Passe o objeto LiveData
, score
, como um argumento
para esta string de formatação.<TextView
android:id="@+id/score_text"
...
android:text="@{@string/score_format(gameViewModel.score)}"
... />
GameFragment
, dentro do método onCreateView()
, remova o código do
observador score
. Código para remover:
viewModel.score.observe(viewLifecycleOwner, Observer { newScore ->
binding.scoreText.text = newScore.toString()
})
Parabéns! Você integrou LiveData
e ViewModel
com vinculação de dados em seu
aplicativo. Isso permite que as vistas em seu layout se comuniquem diretamente com o ViewModel
,
sem usar tratadores de clique no fragmento. Você também usou objetos LiveData
como a fonte de
vinculação de dados para notificar automaticamente a IU sobre alterações nos dados, sem os métodos do
observador LiveData
.
Projeto Android Studio: GuessTheWord
ViewModel
e LiveData
.ViewModel
a um layout usando vinculação de dados. ViewModel
contêm os dados da IU. Ao passar objetos ViewModel
para a
vinculação de dados, você pode automatizar parte da comunicação entre as vistas e os objetos
ViewModel
.Como associar um ViewModel
a um layout:
ViewModel
. <data>
<variable
name="gameViewModel"
type="com.example.android.guesstheword.screens.game.GameViewModel" />
</data>
GameFragment
, passe o GameViewModel
para a vinculação de dados.binding.gameViewModel = viewModel
onClick()
são acionados. android:onClick="@{() -> gameViewModel.onSkip()}"
LiveData
podem ser usados como uma fonte de vinculação de dados
para notificar automaticamente a IU sobre as mudanças nos dados.LiveData
no ViewModel
. Quando
o LiveData
no ViewModel
muda, as vistas no layout podem ser atualizadas
automaticamente, sem os métodos do observador nos controladores de IU.android:text="@{gameViewModel.word}"
LiveData
funcionar, defina a atividade atual (o
controlador de IU) como o proprietário do ciclo de vida da variável binding
no controlador
de IU.binding.lifecycleOwner = this
%s
para strings e %d
para inteiros. text
da vista, passe o objeto LiveData
como um
argumento para a string de formatação. android:text="@{@string/quote_format(gameViewModel.word)}"
Documentação para desenvolvimento em Android:
Esta seção lista as possíveis tarefas de casa para os alunos que estão trabalhando neste tutorial como parte de um curso ministrado por um instrutor.
Qual das afirmações a seguir não é verdadeira sobre as vinculações do ouvinte?
Suponha que seu aplicativo inclua este recurso de
string:<string name="generic_name">Hello %s</string>
Qual das alternativas a seguir é a sintaxe correta para formatar a string, usando a expressão de vinculação de dados?
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}"
Quando uma expressão de vinculação de ouvinte é avaliada e executada?
LiveData
são alteradosonClick()
ocorreComece a próxima lição:
Para obter enlaces para outros tutoriais neste curso, consulte a página de destino dos tutoriais Fundamentos de Android em Kotlin.