Conceitos básicos do Kotlin para Android 05.2: LiveData e observadores do LiveData

Este codelab faz parte do curso Conceitos básicos do Kotlin para Android. Você vai aproveitar mais este curso se fizer os codelabs em sequência. Todos os codelabs do curso estão listados na página inicial dos codelabs de princípios básicos do Kotlin para Android.

Introdução

No codelab anterior, você usou um ViewModel no app GuessTheWord para permitir que os dados do app sobrevivessem a mudanças na configuração do dispositivo. Neste codelab, você vai aprender a integrar o LiveData com os dados nas classes ViewModel. O LiveData, um dos Componentes da arquitetura do Android, permite criar objetos de dados que notificam as visualizações quando o banco de dados muda.

Para usar a classe LiveData, configure "observadores" (por exemplo, atividades ou fragmentos) que observam mudanças nos dados do app. O LiveData é compatível com o ciclo de vida, então ele só atualiza os observadores de componentes do app que estão em um estado ativo do ciclo de vida.

O que você já precisa saber

  • Como criar apps Android básicos em Kotlin.
  • Como navegar entre os destinos do app.
  • Ciclo de vida de atividades e fragmentos.
  • Como usar objetos ViewModel no app.
  • Como criar objetos ViewModel usando a interface ViewModelProvider.Factory.

O que você vai aprender

  • O que torna os objetos LiveData úteis.
  • Como adicionar LiveData aos dados armazenados em um ViewModel.
  • Quando e como usar o MutableLiveData.
  • Como adicionar métodos do observador para observar mudanças no LiveData.
  • Como encapsular LiveData usando uma propriedade de apoio.
  • Como se comunicar entre um controlador de UI e o ViewModel correspondente.

Atividades deste laboratório

  • Use LiveData para a palavra e a pontuação no app GuessTheWord.
  • Adicione observadores que notam quando a palavra ou a pontuação muda.
  • Atualize as visualizações de texto que mostram valores alterados.
  • Use o padrão de observador LiveData para adicionar um evento de jogo concluído.
  • Implemente o botão Jogar novamente.

Nos codelabs da lição 5, você vai desenvolver o app GuessTheWord, começando com o código inicial. O GuessTheWord é um jogo de charadas para dois jogadores em que eles colaboram para conseguir a maior pontuação possível.

O primeiro jogador olha as palavras no app e representa cada uma delas, sem mostrar a palavra para o segundo jogador. O segundo jogador tenta adivinhar a palavra.

Para jogar, o primeiro jogador abre o app no dispositivo e vê uma palavra, por exemplo, "guitarra", como mostrado na captura de tela abaixo.

O primeiro jogador representa a palavra, tomando cuidado para não dizer a palavra em si.

  • Quando o segundo jogador acerta a palavra, o primeiro pressiona o botão Entendi, que aumenta a contagem em um e mostra a próxima palavra.
  • Se o segundo jogador não conseguir adivinhar a palavra, o primeiro jogador pressiona o botão Pular, que diminui a contagem em um e pula para a próxima palavra.
  • Para encerrar o jogo, pressione o botão Encerrar jogo. Essa funcionalidade não está no código inicial do primeiro codelab da série.

Neste codelab, você vai melhorar o app GuessTheWord adicionando um evento para encerrar o jogo quando o usuário passar por todas as palavras no app. Você também vai adicionar um botão Jogar novamente no fragmento de pontuação para que o usuário possa jogar de novo.

Créditos

Tela do jogo

Tela de pontuação

Nesta tarefa, você vai localizar e executar o código inicial deste codelab. Você pode usar o app GuessTheWord criado no codelab anterior como código inicial ou baixar um app inicial.

  1. (Opcional) Se você não estiver usando o código do codelab anterior, faça o download do código inicial para este codelab. Descompacte o código e abra o projeto no Android Studio.
  2. Execute o app e jogue.
  3. O botão Pular mostra a próxima palavra e diminui a pontuação em um, e o botão Entendi mostra a próxima palavra e aumenta a pontuação em um. O botão Encerrar jogo encerra a partida.

LiveData é uma classe armazenadora de dados observáveis compatível com o ciclo de vida. Por exemplo, você pode incluir um LiveData na pontuação atual do app GuessTheWord. Neste codelab, você vai aprender sobre várias características do LiveData:

  • O LiveData é observável, o que significa que um observador é notificado quando os dados contidos no objeto LiveData mudam.
  • O LiveData armazena dados. LiveData é um wrapper que pode ser usado com qualquer tipo de dados.
  • O LiveData é compatível com o ciclo de vida, o que significa que ele só atualiza os observadores que estão em um estado ativo do ciclo de vida, como STARTED ou RESUMED.

Nesta tarefa, você vai aprender a unir qualquer tipo de dados em objetos LiveData convertendo a pontuação atual e os dados da palavra atual no GameViewModel para LiveData. Em uma tarefa posterior, você adicionará um observador a esses objetos LiveData e aprenderá a observar o LiveData.

Etapa 1: mudar a pontuação e a palavra para usar LiveData

  1. No pacote screens/game, abra o arquivo GameViewModel.
  2. Mude o tipo das variáveis score e word para MutableLiveData.

    MutableLiveData é um LiveData cujo valor pode ser mudado. MutableLiveData é uma classe genérica, então é necessário especificar o tipo de dados que ela contém.
// The current word
val word = MutableLiveData<String>()
// The current score
val score = MutableLiveData<Int>()
  1. Em GameViewModel, dentro do bloco init, inicialize score e word. Para mudar o valor de uma variável LiveData, use o método setValue() na variável. Em Kotlin, você pode chamar setValue() usando a propriedade value.
init {

   word.value = ""
   score.value = 0
  ...
}

Etapa 2: atualizar a referência do objeto LiveData

As variáveis score e word agora são do tipo LiveData. Nesta etapa, você muda as referências a essas variáveis usando a propriedade value.

  1. Em GameViewModel, no método onSkip(), mude score para score.value. Observe o erro sobre score possivelmente ser null. Você vai corrigir esse erro em seguida.
  2. Para resolver o erro, adicione uma verificação de null a score.value em onSkip(). Em seguida, chame a função minus() em score, que realiza a subtração com segurança de null.
fun onSkip() {
   if (!wordList.isEmpty()) {
       score.value = (score.value)?.minus(1)
   }
   nextWord()
}
  1. Atualize o método onCorrect() da mesma forma: adicione uma verificação null à variável score e use a função plus().
fun onCorrect() {
   if (!wordList.isEmpty()) {
       score.value = (score.value)?.plus(1)
   }
   nextWord()
}
  1. No GameViewModel, no método nextWord(), mude a referência word para word.value.
private fun nextWord() {
   if (!wordList.isEmpty()) {
       //Select and remove a word from the list
       word.value = wordList.removeAt(0)
   }
}
  1. No GameFragment, no método updateWordText(), mude a referência de viewModel.word para viewModel.word.value.
/** Methods for updating the UI **/
private fun updateWordText() {
   binding.wordText.text = viewModel.word.value
}
  1. No método updateScoreText() do GameFragment, mude a referência de viewModel.score para viewModel.score.value.
private fun updateScoreText() {
   binding.scoreText.text = viewModel.score.value.toString()
}
  1. No GameFragment, no método gameFinished(), mude a referência de viewModel.score para viewModel.score.value. Adicione a verificação de segurança null necessária.
private fun gameFinished() {
   Toast.makeText(activity, "Game has just finished", Toast.LENGTH_SHORT).show()
   val action = GameFragmentDirections.actionGameToScore()
   action.score = viewModel.score.value?:0
   NavHostFragment.findNavController(this).navigate(action)
}
  1. Verifique se não há erros no código. Compile e execute o app. A funcionalidade dele deve ser a mesma de antes.

Essa tarefa está intimamente relacionada à anterior, em que você converteu os dados de pontuação e palavras em objetos LiveData. Nesta tarefa, você vai anexar objetos Observer aos objetos LiveData.

  1. Em GameFragment,, dentro do método onCreateView(), anexe um objeto Observer ao objeto LiveData da pontuação atual, viewModel.score. Use o método observe() e coloque o código após a inicialização do viewModel. Use uma expressão lambda para simplificar o código. Uma expressão lambda é uma função anônima que não é declarada, mas é transmitida imediatamente como uma expressão.
viewModel.score.observe(this, Observer { newScore ->
})

Resolva a referência a Observer. Para fazer isso, clique em Observer, pressione Alt+Enter (Option+Enter em um Mac) e importe androidx.lifecycle.Observer.

  1. O observador que você acabou de criar recebe um evento quando os dados contidos no objeto LiveData observado mudam. Dentro do observador, atualize a pontuação TextView com a nova pontuação.
/** Setting up LiveData observation relationship **/
viewModel.score.observe(this, Observer { newScore ->
   binding.scoreText.text = newScore.toString()
})
  1. Anexe um objeto Observer ao objeto LiveData da palavra atual. Faça isso da mesma forma que anexou um objeto Observer à pontuação atual.
/** Setting up LiveData observation relationship **/
viewModel.word.observe(this, Observer { newWord ->
   binding.wordText.text = newWord
})

Quando o valor de score ou word muda, o score ou word exibido na tela é atualizado automaticamente.

  1. Em GameFragment, exclua os métodos updateWordText() e updateScoreText() e todas as referências a eles. Eles não são mais necessários porque as visualizações de texto são atualizadas pelos métodos de observador LiveData.
  2. Execute o app. Ele vai funcionar exatamente como antes, mas agora usa observadores LiveData e LiveData.

O encapsulamento é uma maneira de restringir o acesso direto a alguns dos campos de um objeto. Ao encapsular um objeto, você expõe um conjunto de métodos públicos que modificam os campos internos particulares. Usando o encapsulamento, você controla como outras classes manipulam os campos internos.

No seu código atual, qualquer classe externa pode modificar as variáveis score e word usando a propriedade value, por exemplo, usando viewModel.score.value. Isso pode não importar no app que você está desenvolvendo neste codelab, mas, em um app de produção, é importante ter controle sobre os dados nos objetos ViewModel.

Somente o ViewModel pode editar os dados no app. No entanto, os controladores de interface precisam ler os dados, então os campos de dados não podem ser completamente particulares. Para encapsular os dados do app, use objetos MutableLiveData e LiveData.

MutableLiveData x LiveData:

  • Os dados em um objeto MutableLiveData podem ser alterados, como o nome sugere. No ViewModel, os dados precisam ser editáveis. Portanto, eles usam MutableLiveData.
  • Os dados em um objeto LiveData podem ser lidos, mas não alterados. Fora do ViewModel, os dados precisam ser legíveis, mas não editáveis, portanto, os dados precisam ser expostos como LiveData.

Para realizar essa estratégia, use uma propriedade de apoio do Kotlin. Uma propriedade de apoio permite que você retorne algo de um getter diferente do objeto exato. Nesta tarefa, você vai implementar uma propriedade de suporte para os objetos score e word no app GuessTheWord.

Adicionar uma propriedade de apoio à pontuação e à palavra

  1. Em GameViewModel, faça com que o objeto score atual seja private.
  2. Para seguir a convenção de nomenclatura usada em propriedades de apoio, mude score para _score. A propriedade _score agora é a versão mutável da pontuação do jogo, para ser usada internamente.
  3. Crie uma versão pública do tipo LiveData, chamada score.
// The current score
private val _score = MutableLiveData<Int>()
val score: LiveData<Int>
  1. Você vai encontrar um erro de inicialização. Esse erro ocorre porque, dentro do GameFragment, o score é uma referência LiveData, e o score não pode mais acessar o setter. Para saber mais sobre getters e setters em Kotlin, consulte Getters e setters.

    Para resolver o erro, substitua o método get() do objeto score em GameViewModel e retorne a propriedade de suporte, _score.
val score: LiveData<Int>
   get() = _score
  1. No GameViewModel, mude as referências de score para a versão mutável interna, _score.
init {
   ...
   _score.value = 0
   ...
}

...
fun onSkip() {
   if (!wordList.isEmpty()) {
       _score.value = (score.value)?.minus(1)
   }
  ...
}

fun onCorrect() {
   if (!wordList.isEmpty()) {
       _score.value = (score.value)?.plus(1)
   }
   ...
}
  1. Renomeie o objeto word para _word e adicione uma propriedade de apoio a ele, como fez com o objeto score.
// The current word
private val _word = MutableLiveData<String>()
val word: LiveData<String>
   get() = _word
...
init {
   _word.value = ""
   ...
}
...
private fun nextWord() {
   if (!wordList.isEmpty()) {
       //Select and remove a word from the list
       _word.value = wordList.removeAt(0)
   }
}

Muito bem! Você encapsulou os objetos LiveData word e score.

O app atual navega até a tela de pontuação quando o usuário toca no botão Encerrar jogo. Você também quer que o app navegue até a tela de pontuação quando os jogadores tiverem passado por todas as palavras. Depois que os jogadores terminarem a última palavra, você vai querer que o jogo termine automaticamente para que o usuário não precise tocar no botão.

Para implementar essa funcionalidade, você precisa de um evento que seja acionado e comunicado ao fragmento do ViewModel quando todas as palavras forem mostradas. Para isso, use o padrão de observador LiveData para modelar um evento de jogo concluído.

O padrão de observador

O padrão de observador é um padrão de design de software. Ele especifica a comunicação entre objetos: um observável (o "assunto" da observação) e observadores. Um observável é um objeto que notifica os observadores sobre as mudanças no estado dele.

No caso do LiveData neste app, o observável (assunto) é o objeto LiveData, e os observadores são os métodos nos controladores de UI, como fragmentos. Uma mudança de estado acontece sempre que os dados envolvidos em LiveData mudam. As classes LiveData são cruciais para a comunicação da ViewModel com o fragmento.

Etapa 1: usar LiveData para detectar um evento de fim de jogo

Nesta tarefa, você vai usar o padrão de observador LiveData para modelar um evento de jogo concluído.

  1. Em GameViewModel, crie um objeto Boolean MutableLiveData chamado _eventGameFinish. Esse objeto vai conter o evento de término do jogo.
  2. Depois de inicializar o objeto _eventGameFinish, crie e inicialize uma propriedade de suporte chamada eventGameFinish.
// Event which triggers the end of the game
private val _eventGameFinish = MutableLiveData<Boolean>()
val eventGameFinish: LiveData<Boolean>
   get() = _eventGameFinish
  1. Em GameViewModel, adicione um método onGameFinish(). No método, defina o evento de jogo concluído, eventGameFinish, como true.
/** Method for the game completed event **/
fun onGameFinish() {
   _eventGameFinish.value = true
}
  1. Em GameViewModel, dentro do método nextWord(), encerre o jogo se a lista de palavras estiver vazia.
private fun nextWord() {
   if (wordList.isEmpty()) {
       onGameFinish()
   } else {
       //Select and remove a _word from the list
       _word.value = wordList.removeAt(0)
   }
}
  1. Em GameFragment, dentro de onCreateView(), depois de inicializar o viewModel, anexe um observador a eventGameFinish. Use o método observe(). Na função lambda, chame o método gameFinished().
// Observer for the Game finished event
viewModel.eventGameFinish.observe(this, Observer<Boolean> { hasFinished ->
   if (hasFinished) gameFinished()
})
  1. Execute o app, jogue e passe por todas as palavras. O app navega automaticamente para a tela de pontuação, em vez de ficar no fragmento do jogo até que você toque em Encerrar jogo.

    Depois que a lista de palavras estiver vazia, eventGameFinish será definido, o método observador associado no fragmento do jogo será chamado, e o app vai navegar até o fragmento da tela.
  2. O código adicionado introduziu um problema de ciclo de vida. Para entender o problema, na classe GameFragment, use um comentário para excluir o código de navegação no método gameFinished(). Não se esqueça de manter a mensagem Toast no método.
private fun gameFinished() {
       Toast.makeText(activity, "Game has just finished", Toast.LENGTH_SHORT).show()
//        val action = GameFragmentDirections.actionGameToScore()
//        action.score = viewModel.score.value?:0
//        NavHostFragment.findNavController(this).navigate(action)
   }
  1. Execute o app, jogue e passe por todas as palavras. Uma mensagem de aviso "O jogo acabou de terminar" aparece brevemente na parte de baixo da tela do jogo, que é o comportamento esperado.

Agora, gire o dispositivo ou emulador. O aviso aparece de novo. Gire o dispositivo mais algumas vezes. É provável que o aviso apareça todas as vezes. Isso é um bug, porque o toast só deve aparecer uma vez, quando o jogo termina. O toast não deve aparecer toda vez que o fragmento for recriado. Você vai resolver esse problema na próxima tarefa.

Etapa 2: redefinir o evento de término do jogo

Normalmente, o LiveData envia atualizações aos observadores apenas quando os dados mudam. Uma exceção desse comportamento é que os observadores também recebem atualizações quando passam de um estado inativo para um ativo.

É por isso que o toast de jogo concluído é acionado repetidamente no app. Quando o fragmento do jogo é recriado após uma rotação de tela, ele passa de um estado inativo para um estado ativo. O observador no fragmento é reconectado ao ViewModel atual e recebe os dados atuais. O método gameFinished() é acionado novamente, e o toast é exibido.

Nesta tarefa, você vai corrigir esse problema e mostrar o toast apenas uma vez, redefinindo a flag eventGameFinish no GameViewModel.

  1. Em GameViewModel, adicione um método onGameFinishComplete() para redefinir o evento de término do jogo, _eventGameFinish.
/** Method for the game completed event **/

fun onGameFinishComplete() {
   _eventGameFinish.value = false
}
  1. Em GameFragment, ao final de gameFinished(), chame onGameFinishComplete() no objeto viewModel. Por enquanto, deixe o código de navegação em gameFinished() comentado.
private fun gameFinished() {
   ...
   viewModel.onGameFinishComplete()
}
  1. Execute o app e jogue. Leia todas as palavras e mude a orientação da tela do dispositivo. O toast é mostrado apenas uma vez.
  2. Em GameFragment, dentro do método gameFinished(), remova o comentário do código de navegação.

    Para remover o comentário no Android Studio, selecione as linhas comentadas e pressione Control+/ (Command+/ em um Mac).
private fun gameFinished() {
   Toast.makeText(activity, "Game has just finished", Toast.LENGTH_SHORT).show()
   val action = GameFragmentDirections.actionGameToScore()
   action.score = viewModel.score.value?:0
   findNavController(this).navigate(action)
   viewModel.onGameFinishComplete()
}

Se solicitado pelo Android Studio, importe androidx.navigation.fragment.NavHostFragment.findNavController.

  1. Execute o app e jogue. Verifique se o app navega automaticamente para a tela de pontuação final depois que você passa por todas as palavras.

Muito bem! Seu app usa LiveData para acionar um evento de jogo concluído e comunicar do GameViewModel ao fragmento do jogo que a lista de palavras está vazia. Em seguida, o fragmento do jogo navega até o fragmento de pontuação.

Nesta tarefa, você vai mudar a pontuação para um objeto LiveData no ScoreViewModel e anexar um observador a ele. Essa tarefa é semelhante ao que você fez ao adicionar LiveData ao GameViewModel.

Você faz essas mudanças em ScoreViewModel para garantir que todos os dados no app usem LiveData.

  1. Em ScoreViewModel, mude o tipo da variável score para MutableLiveData. Renomeie por convenção para _score e adicione uma propriedade de apoio.
private val _score = MutableLiveData<Int>()
val score: LiveData<Int>
   get() = _score
  1. Em ScoreViewModel, dentro do bloco init, inicialize _score. Você pode remover ou deixar o registro no bloco init como quiser.
init {
   _score.value = finalScore
}
  1. No ScoreFragment, dentro de onCreateView(), depois de inicializar o viewModel, anexe um observador ao objeto LiveData de pontuação. Na expressão lambda, defina o valor da pontuação na visualização de texto da pontuação. Remova o código que atribui diretamente a visualização de texto com o valor da pontuação do ViewModel.

Código para adicionar:

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

Código a ser removido:

binding.scoreText.text = viewModel.score.toString()

Quando solicitado pelo Android Studio, importe androidx.lifecycle.Observer.

  1. Execute o app e jogue uma partida. O app vai funcionar como antes, mas agora ele usa LiveData e um observador para atualizar a pontuação.

Nesta tarefa, você vai adicionar um botão Jogar de novo à tela de pontuação e implementar o listener de clique dele usando um evento LiveData. O botão aciona um evento para navegar da tela de pontuação para a tela do jogo.

O código inicial do app inclui o botão Jogar de novo, mas ele está oculto.

  1. Em res/layout/score_fragment.xml, para o botão play_again_button, mude o valor do atributo visibility para visible.
<Button
   android:id="@+id/play_again_button"
...
   android:visibility="visible"
 />
  1. Em ScoreViewModel, adicione um objeto LiveData para armazenar um Boolean chamado _eventPlayAgain. Esse objeto é usado para salvar o evento LiveData e navegar da tela de pontuação para a tela do jogo.
private val _eventPlayAgain = MutableLiveData<Boolean>()
val eventPlayAgain: LiveData<Boolean>
   get() = _eventPlayAgain
  1. Em ScoreViewModel, defina métodos para definir e redefinir o evento, _eventPlayAgain.
fun onPlayAgain() {
   _eventPlayAgain.value = true
}
fun onPlayAgainComplete() {
   _eventPlayAgain.value = false
}
  1. Em ScoreFragment, adicione um observador para eventPlayAgain. Coloque o código no fim de onCreateView(), antes da instrução return. Dentro da expressão lambda, volte para a tela do jogo e redefina eventPlayAgain.
// Navigates back to game when button is pressed
viewModel.eventPlayAgain.observe(this, Observer { playAgain ->
   if (playAgain) {
      findNavController().navigate(ScoreFragmentDirections.actionRestart())
       viewModel.onPlayAgainComplete()
   }
})

Importe androidx.navigation.fragment.findNavController quando solicitado pelo Android Studio.

  1. Em ScoreFragment, dentro de onCreateView(), adicione um listener de clique ao botão PlayAgain e chame viewModel.onPlayAgain().
binding.playAgainButton.setOnClickListener {  viewModel.onPlayAgain()  }
  1. Execute o app e jogue uma partida. Quando o jogo termina, a tela de pontuação mostra a pontuação final e o botão Jogar de novo. Toque no botão PlayAgain. O app vai navegar até a tela do jogo para que você possa jogar de novo.

Bom trabalho! Você mudou a arquitetura do app para usar objetos LiveData no ViewModel e anexou observadores aos objetos LiveData. O LiveData notifica objetos observadores quando o valor mantido pelo LiveData muda.

Projeto do Android Studio: GuessTheWord (link em inglês)

LiveData

  • O LiveData é uma classe armazenadora de dados observáveis compatível com o ciclo de vida, um dos Componentes da arquitetura do Android.
  • Você pode usar LiveData para permitir que a interface seja atualizada automaticamente quando os dados forem atualizados.
  • O LiveData é observável, o que significa que um observador, como uma atividade ou um fragmento, pode ser notificado quando os dados contidos no objeto LiveData mudam.
  • O LiveData armazena dados. Ele é um wrapper que pode ser usado com qualquer tipo de dado.
  • O LiveData é compatível com o ciclo de vida, o que significa que ele só atualiza os observadores que estão em um estado ativo do ciclo de vida, como STARTED ou RESUMED.

Para adicionar o LiveData

  • Mude o tipo das variáveis de dados em ViewModel para LiveData ou MutableLiveData.

MutableLiveData é um objeto LiveData cujo valor pode ser mudado. MutableLiveData é uma classe genérica, então é necessário especificar o tipo de dados que ela contém.

  • Para mudar o valor dos dados mantidos pelo LiveData, use o método setValue() na variável LiveData.

Para encapsular LiveData

  • O LiveData dentro do ViewModel precisa ser editável. Fora do ViewModel, o LiveData precisa estar legível. Isso pode ser implementado usando uma propriedade de apoio do Kotlin.
  • Uma propriedade de apoio do Kotlin permite que você retorne algo de um getter diferente do objeto exato.
  • Para encapsular o LiveData, use private MutableLiveData dentro do ViewModel e retorne uma propriedade de suporte LiveData fora do ViewModel.

LiveData observável

  • LiveData segue um padrão de observador. O "observável" é o objeto LiveData, e os observadores são os métodos nos controladores de UI, como fragmentos. Sempre que os dados envolvidos em LiveData mudam, os métodos de observador nos controladores de UI são notificados.
  • Para tornar o LiveData observável, anexe um objeto observador à referência LiveData nos observadores (como atividades e fragmentos) usando o método observe().
  • Esse padrão de observador LiveData pode ser usado para se comunicar do ViewModel com os controladores da interface.

Curso da Udacity:

Documentação do desenvolvedor Android:

Outro:

Esta seção lista as possíveis atividades de dever de casa para os alunos que estão fazendo este codelab como parte de um curso ministrado por um professor. Cabe ao professor fazer o seguinte:

  • Atribuir o dever de casa, se necessário.
  • Informar aos alunos como enviar deveres de casa.
  • Atribuir nota aos deveres de casa.

Os professores podem usar essas sugestões o quanto quiserem, podendo passar os exercícios que acharem mais apropriados como dever de casa.

Se você estiver seguindo este codelab por conta própria, sinta-se à vontade para usar esses deveres de casa para testar seu conhecimento.

Responda estas perguntas

Pergunta 1

Como encapsular o LiveData armazenado em um ViewModel para que objetos externos possam ler dados sem atualizá-los?

  • Dentro do objeto ViewModel, mude o tipo de dados para private LiveData. Use uma propriedade de backup para expor dados somente leitura do tipo MutableLiveData.
  • Dentro do objeto ViewModel, mude o tipo de dados para private MutableLiveData. Use uma propriedade de backup para expor dados somente leitura do tipo LiveData.
  • Dentro do controlador de interface, mude o tipo de dados para private MutableLiveData. Use uma propriedade de backup para expor dados somente leitura do tipo LiveData.
  • Dentro do objeto ViewModel, mude o tipo de dados para LiveData. Use uma propriedade de backup para expor dados somente leitura do tipo LiveData.

Pergunta 2

O LiveData vai atualizar um controlador de UI (por exemplo, um fragmento) se esse controlador estiver em qual dos seguintes estados?

  • Retomado
  • Em segundo plano
  • Pausado
  • Interrompida

Pergunta 3

No padrão do observador LiveData, qual é o item observável (o que é observado)?

  • O método do observador
  • Os dados em um objeto LiveData
  • O controlador de IU
  • O objeto ViewModel

Comece a próxima lição: 5.3: vinculação de dados com ViewModel e LiveData

Para acessar links de outros codelabs neste curso, consulte a página inicial dos codelabs de conceitos básicos do Kotlin para Android.