Este codelab faz parte do curso Conceitos básicos do Kotlin para Android. Você aproveitará mais o curso se fizer os codelabs em sequência. Todos os codelabs do curso estão listados na página de destino dos codelabs do curso Conceitos básicos do Kotlin para Android.
Introdução
No codelab anterior, você atualizou o app TrackMySleepQuality para exibir dados sobre a qualidade do sono em uma RecyclerView
. As técnicas que você aprendeu quando criou sua primeira RecyclerView
são suficientes para a maioria das RecyclerViews
que exibem listas simples que não são muito grandes. No entanto, existem várias técnicas que tornam o RecyclerView
mais eficiente para listas grandes e facilitam a manutenção e a extensão do seu código para listas e grades complexas.
Neste codelab, você usará o app monitor de sono do codelab anterior. Você aprenderá uma maneira mais eficaz de atualizar a lista de dados de sono e aprenderá a usar a vinculação de dados com o RecyclerView
. Se você não tiver o app do codelab anterior, faça o download do código inicial para este codelab.
O que você já precisa saber
- Criação de uma interface do usuário básica usando uma atividade, fragmentos e visualizações.
- Navegar entre fragmentos usando
safeArgs
para transmitir dados entre eles. - Veja modelos, visualizações de fábricas, transformações e
LiveData
e os respectivos observadores. - Como criar um banco de dados
Room
, um DAO e definir entidades. - Como usar corrotinas para banco de dados e outras tarefas de longa duração.
- Como implementar um
RecyclerView
básico com umAdapter
,ViewHolder
e o layout do item.
O que você vai aprender
- Como usar
DiffUtil
para atualizar de forma eficiente uma lista exibida porRecyclerView
. - Como usar a vinculação de dados com
RecyclerView
. - Como usar adaptadores de vinculação para transformar dados.
Atividades do laboratório
- Crie no app TrackMySleepQuality do codelab anterior desta série.
- Atualize o
SleepNightAdapter
para atualizar a lista de maneira eficiente usandoDiffUtil
. - Implemente a vinculação de dados para a
RecyclerView
usando adaptadores de vinculação para transformar os dados.
O app monitor de sono tem duas telas, representadas por fragmentos, como mostrado na figura abaixo.
A primeira tela, mostrada à esquerda, tem botões para iniciar e interromper o rastreamento. A tela mostra alguns dados de sono do usuário. O botão Limpar exclui permanentemente todos os dados que o app coletou para o usuário. A segunda tela, mostrada à direita, serve para selecionar uma classificação de qualidade do sono.
Este app foi arquitetado para usar um controlador de IU, ViewModel
e LiveData
, e um banco de dados Room
para manter dados de sono.
Os dados de sono são exibidos em um RecyclerView
. Neste codelab, você criará a DiffUtil
e a parte de vinculação de dados para a RecyclerView
. Após este codelab, seu app será exatamente igual, mas será mais eficiente e fácil de escalonar e manter.
Você pode continuar usando o app SleepTracker do codelab anterior ou pode fazer o download do app DiffDiffUtilDataBinding-Starter no GitHub.
- Se necessário, faça o download do app DiffDiffUtilDataBinding-Starter no GitHub e abra o projeto no Android Studio.
- Execute o app.
- Abra o arquivo
SleepNightAdapter.kt
. - Inspecione o código para se familiarizar com a estrutura do app. Consulte o diagrama abaixo para recapitular o uso de
RecyclerView
com o padrão do adaptador para exibir dados de sono ao usuário.
- Na entrada do usuário, o app cria uma lista de objetos
SleepNight
. Cada objetoSleepNight
representa uma única noite de sono, a duração e a qualidade dele. - O
SleepNightAdapter
adapta a lista de objetosSleepNight
em algo queRecyclerView
pode usar e exibir. - O adaptador
SleepNightAdapter
produzViewHolders
que contém as visualizações, dados e informações meta para que a visualização de reciclagem exiba os dados. - A
RecyclerView
usa aSleepNightAdapter
para determinar quantos itens há para exibir (getItemCount()
). ARecyclerView
usa aonCreateViewHolder()
e aonBindViewHolder()
para vincular os armazenadores de visualização aos dados a serem exibidos.
O método notifyDataSetChanged() é ineficiente.
Para informar ao RecyclerView
que um item da lista foi alterado e precisa ser atualizado, o código atual chama notifyDataSetChanged()
no SleepNightAdapter
, conforme mostrado abaixo.
var data = listOf<SleepNight>()
set(value) {
field = value
notifyDataSetChanged()
}
No entanto, o notifyDataSetChanged()
informa ao RecyclerView
que a lista inteira é possivelmente inválida. Como resultado, a RecyclerView
vincula e desenha novamente todos os itens da lista, incluindo os que não estão visíveis na tela. Esse é um trabalho desnecessário. Para listas grandes ou complexas, esse processo pode levar tempo o suficiente, de forma que a tela oscila ou oscila à medida que o usuário rola a lista.
Para corrigir esse problema, informe RecyclerView
exatamente o que mudou. RecyclerView
pode atualizar apenas as visualizações que foram alteradas na tela.
RecyclerView
tem uma API avançada para atualizar um único elemento. Você pode usar notifyItemChanged()
para informar a RecyclerView
que um item foi alterado e usar funções semelhantes para itens adicionados, removidos ou movidos. Você poderia fazer tudo manualmente, mas essa tarefa seria complexa e poderia envolver bastante código.
Felizmente, existe um jeito melhor.
O DiffUtil é eficiente e faz o trabalho pesado para você.
RecyclerView
tem uma classe chamada DiffUtil
, que serve para calcular as diferenças entre duas listas. O DiffUtil
usa uma lista antiga e uma nova e descobre o que é diferente. Ela localiza os itens adicionados, removidos ou alterados. Em seguida, ele usa um algoritmo chamado Eugene W. o algoritmo de diferença de Myers para descobrir o número mínimo de alterações a serem feitas na lista antiga para produzir a nova.
Depois que o DiffUtil
descobre o que foi alterado, o RecyclerView
pode usar essa informação para atualizar somente os itens que foram alterados, adicionados, removidos ou movidos. Isso é muito mais eficiente do que refazer a lista inteira.
Nesta tarefa, você fará upgrade do SleepNightAdapter
para usar DiffUtil
e otimizar o RecyclerView
para mudanças nos dados.
Etapa 1: implementar SleepNightDiffCallback
Para usar a funcionalidade da classe DiffUtil
, estenda DiffUtil.ItemCallback
.
- Abra o
SleepNightAdapter.kt
- Abaixo da definição de classe completa para
SleepNightAdapter
, crie uma nova classe de nível superior chamadaSleepNightDiffCallback
, que estendaDiffUtil.ItemCallback
. TransmitaSleepNight
como um parâmetro genérico.
class SleepNightDiffCallback : DiffUtil.ItemCallback<SleepNight>() {
}
- Coloque o cursor no nome da classe
SleepNightDiffCallback
. - Pressione
Alt+Enter
(Option+Enter
no Mac) e selecione Implementar membros. - Na caixa de diálogo exibida, clique com o botão esquerdo do mouse para selecionar os métodos
areItemsTheSame()
eareContentsTheSame()
, depois clique em OK.
Isso gera stubs dentro deSleepNightDiffCallback
para os dois métodos, conforme mostrado abaixo. ODiffUtil
usa esses dois métodos para descobrir como a lista e os itens foram alterados.
override fun areItemsTheSame(oldItem: SleepNight, newItem: SleepNight): Boolean {
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
}
override fun areContentsTheSame(oldItem: SleepNight, newItem: SleepNight): Boolean {
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
}
- Dentro de
areItemsTheSame()
, substitua aTODO
pelo código que testa se os dois itensSleepNight
transmitidos,oldItem
enewItem
, são iguais. Se os itens tiverem o mesmonightId
, serão o mesmo item, então retornetrue
. Caso contrário, retornefalse
. ODiffUtil
usa esse teste para ajudar a descobrir se um item foi adicionado, removido ou movido.
override fun areItemsTheSame(oldItem: SleepNight, newItem: SleepNight): Boolean {
return oldItem.nightId == newItem.nightId
}
- No
areContentsTheSame()
, verifique seoldItem
enewItem
contêm os mesmos dados, ou seja, se eles são iguais. Essa verificação de igualdade verificará todos os campos porqueSleepNight
é uma classe de dados. As classesData
definem automaticamente oequals
e alguns outros métodos para você. Se houver diferenças entreoldItem
enewItem
, esse código informará aoDiffUtil
que o item foi atualizado.
override fun areContentsTheSame(oldItem: SleepNight, newItem: SleepNight): Boolean {
return oldItem == newItem
}
É um padrão comum usar um RecyclerView
para exibir uma lista que muda. RecyclerView
fornece uma classe de adaptador, ListAdapter
, que ajuda a criar um adaptador RecyclerView
que tem o suporte de uma lista.
O ListAdapter
monitora a lista para você e notifica o adaptador quando a lista é atualizada.
Etapa 1: mudar o adaptador para estender o ListAdapter
- No arquivo
SleepNightAdapter.kt
, mude a assinatura da classe deSleepNightAdapter
para estenderListAdapter
. - Se solicitado, importe
androidx.recyclerview.widget.ListAdapter
. - Adicione
SleepNight
como o primeiro argumento aoListAdapter
antes deSleepNightAdapter.ViewHolder
. - Adicione
SleepNightDiffCallback()
como um parâmetro ao construtor. OListAdapter
usará isso para descobrir o que mudou na lista. A assinatura da classeSleepNightAdapter
final precisa ficar assim:
class SleepNightAdapter : ListAdapter<SleepNight, SleepNightAdapter.ViewHolder>(SleepNightDiffCallback()) {
- Na classe
SleepNightAdapter
, exclua o campodata
, incluindo o setter. Você não precisa mais desta lista, porqueListAdapter
monitora a lista para você. - Exclua a substituição de
getItemCount()
, porque aListAdapter
implementa esse método para você. - Para eliminar o erro em
onBindViewHolder()
, mude a variávelitem
. Em vez de usardata
para conseguir umitem
, chame o métodogetItem(position)
que oListAdapter
fornece.
val item = getItem(position)
Etapa 2: use sendList() para manter a lista atualizada
Seu código precisa informar a ListAdapter
quando uma lista alterada estiver disponível. ListAdapter
fornece um método com o nome submitList()
para informar ao ListAdapter
que uma nova versão da lista está disponível. Quando esse método é chamado, o ListAdapter
diferencia a nova lista da antiga e detecta itens que foram adicionados, removidos, movidos ou alterados. Em seguida, o ListAdapter
atualizará os itens mostrados por RecyclerView
.
- Abra o
SleepTrackerFragment.kt
- Em
onCreateView()
, no observador desleepTrackerViewModel
, localize o erro em que a variáveldata
que você excluiu é referenciada. - Substitua
adapter.data = it
por uma chamada paraadapter.submitList(it)
. O código atualizado é mostrado abaixo.
sleepTrackerViewModel.nights.observe(viewLifecycleOwner, Observer {
it?.let {
adapter.submitList(it)
}
})
- Execute o app. Ele será executado mais rápido, talvez não perceptível se sua lista for pequena.
Nesta tarefa, você usa a mesma técnica dos codelabs anteriores para configurar a vinculação de dados e eliminar as chamadas para findViewById()
.
Etapa 1: adicionar a vinculação de dados ao arquivo de layout
- Abra o arquivo de layout
list_item_sleep_night.xml
na guia Text. - Coloque o cursor na tag
ConstraintLayout
e pressioneAlt+Enter
(Option+Enter
em um Mac). O menu de intenção (o menu "correção rápida") é aberto. - Selecione Converter para layout de vinculação de dados. Isso envolve o layout em
<layout>
e adiciona uma tag<data>
. - Se necessário, role para a parte superior e, dentro da tag
<data>
, declare uma variável chamadasleep
. - Defina o
type
como o nome totalmente qualificado deSleepNight
,com.example.android.trackmysleepquality.database.SleepNight
. A tag<data>
final ficará como o exemplo abaixo.
<data>
<variable
name="sleep"
type="com.example.android.trackmysleepquality.database.SleepNight"/>
</data>
- Para forçar a criação do objeto
Binding
, selecione Build > Clean Project e Build > Rebuild Project. Se você ainda tiver problemas, selecione File > Invalidate Caches / Restart. O objeto de vinculaçãoListItemSleepNightBinding
, com o código relacionado, é adicionado aos arquivos gerados pelo projeto.
Etapa 2: inflar o layout do item usando a vinculação de dados
- Abra o
SleepNightAdapter.kt
- Na classe
ViewHolder
, encontre o métodofrom()
. - Exclua a declaração da variável
view
.
Código para excluir:
val view = layoutInflater
.inflate(R.layout.list_item_sleep_night, parent, false)
- Onde a variável
view
estava, defina uma nova variável chamadabinding
que infla o objeto de vinculaçãoListItemSleepNightBinding
, como mostrado abaixo. Faça a importação necessária do objeto de vinculação.
val binding =
ListItemSleepNightBinding.inflate(layoutInflater, parent, false)
- No final da função, em vez de retornar o
view
, retornebinding
.
return ViewHolder(binding)
- Para eliminar o erro, coloque o cursor sobre a palavra
binding
. PressioneAlt+Enter
(Option+Enter
em um Mac) para abrir o menu de intents.
- Selecione Alterar parâmetro 'itemView' tipo de construtor principal da classe 'ViewHolder' para 'ListItemSleepNightBinding'. Isso atualiza o tipo de parâmetro da classe
ViewHolder
.
- Role para cima até a definição de classe do
ViewHolder
para ver a mudança na assinatura. Você verá um erro paraitemView
, porque alterouitemView
parabinding
no métodofrom()
.
Na definição da classeViewHolder
, clique com o botão direito do mouse em uma das ocorrências deitemView
e selecione Refactor > Rename. Mude o nome parabinding
. - Adicione o prefixo
binding
ao parâmetroval
do construtor para torná-lo uma propriedade. - Na chamada para a classe pai,
RecyclerView.ViewHolder
, mude o parâmetro debinding
parabinding.root
. É necessário transmitir umView
, ebinding.root
é aConstraintLayout
raiz no layout do item. - A declaração de classe finalizada ficará como o código abaixo.
class ViewHolder private constructor(val binding: ListItemSleepNightBinding) : RecyclerView.ViewHolder(binding.root){
Você também verá um erro nas chamadas para findViewById()
e o corrigirá em seguida.
Etapa 3: substituir findViewById()
Agora você pode atualizar as propriedades sleepLength
, quality
e qualityImage
para usar o objeto binding
em vez de findViewById()
.
- Mude as inicializações de
sleepLength
,qualityString
equalityImage
para usar as visualizações do objetobinding
, como mostrado abaixo. Depois disso, o código não mostrará mais erros.
val sleepLength: TextView = binding.sleepLength
val quality: TextView = binding.qualityString
val qualityImage: ImageView = binding.qualityImage
Com o objeto de vinculação em vigor, não é mais necessário definir as propriedades sleepLength
, quality
e qualityImage
. O DataBinding
armazenará as pesquisas em cache. Portanto, não é necessário declarar essas propriedades.
- Clique com o botão direito do mouse nos nomes das propriedades
sleepLength
,quality
equalityImage
. Selecione Refatorar > Inline ou pressioneControl+Command+N
(Option+Command+N
no Mac). - Execute o app. Em caso de erros, talvez seja necessário limpar e recriar o projeto.
Nesta tarefa, você fará upgrade do seu app para usar a vinculação de dados com adaptadores de vinculação e definir os dados nas suas visualizações.
Em um codelab anterior, você usou a classe Transformations
para usar LiveData
e gerar strings formatadas para exibição em visualizações de texto. No entanto, se você precisar vincular tipos diferentes ou complexos, poderá fornecer adaptadores de vinculação para ajudar na vinculação de dados. Adaptadores de vinculação são adaptadores que adaptam seus dados para algo que pode ser usado para vincular uma visualização, como um texto ou uma imagem.
Você implementará três adaptadores de vinculação, um para a imagem de qualidade e outro para cada campo de texto. Em resumo, para declarar um adaptador de vinculação, você define um método que usa um item e uma visualização e insere a anotação @BindingAdapter
. No corpo do método, você implementa a transformação. No Kotlin, você pode criar um adaptador de vinculação como uma função de extensão na classe de visualização que recebe os dados.
Etapa 1: criar adaptadores de vinculação
Você precisará importar várias classes na etapa, e ela não será chamada individualmente.
- Abra o
SleepNightAdapater.kt
- Na classe
ViewHolder
, encontre o métodobind()
e lembre-se do que esse método faz. Você usará o código que calcula os valores debinding.sleepLength
,binding.quality
ebinding.qualityImage
e o usará dentro do adaptador. Por enquanto, deixe o código como está. Você o moverá em uma etapa posterior. - No pacote
sleeptracker
, crie e abra um arquivo chamadoBindingUtils.kt
. - Declare uma função de extensão em
TextView
, chamadasetSleepDurationFormatted
, e transmita umaSleepNight
. Essa função será seu adaptador para calcular e formatar a duração do sono.
fun TextView.setSleepDurationFormatted(item: SleepNight) {}
- No corpo de
setSleepDurationFormatted
, vincule os dados à visualização, como você fez emViewHolder.bind()
. ChameconvertDurationToFormatted()
e definatext
daTextView
como o texto formatado. Como essa é uma função de extensão noTextView
, você pode acessar a propriedadetext
diretamente.
text = convertDurationToFormatted(item.startTimeMilli, item.endTimeMilli, context.resources)
- Para informar a vinculação de dados sobre esse adaptador de vinculação, anote a função com
@BindingAdapter
. - Essa função é o adaptador do atributo
sleepDurationFormatted
. Portanto, transmitasleepDurationFormatted
como um argumento para@BindingAdapter
.
@BindingAdapter("sleepDurationFormatted")
- O segundo adaptador define a qualidade do sono com base no valor em um objeto
SleepNight
. Crie uma função de extensão chamadasetSleepQualityString()
emTextView
e transmita umaSleepNight
. - No corpo, vincule os dados à visualização, como você fez na
ViewHolder.bind()
. ChameconvertNumericQualityToString
e definatext
. - Anote a função com
@BindingAdapter("sleepQualityString")
.
@BindingAdapter("sleepQualityString")
fun TextView.setSleepQualityString(item: SleepNight) {
text = convertNumericQualityToString(item.sleepQuality, context.resources)
}
- O terceiro adaptador de vinculação define a imagem em uma visualização. Crie a função de extensão em
ImageView
, chamesetSleepImage
e use o código deViewHolder.bind()
, conforme mostrado abaixo.
@BindingAdapter("sleepImage")
fun ImageView.setSleepImage(item: SleepNight) {
setImageResource(when (item.sleepQuality) {
0 -> R.drawable.ic_sleep_0
1 -> R.drawable.ic_sleep_1
2 -> R.drawable.ic_sleep_2
3 -> R.drawable.ic_sleep_3
4 -> R.drawable.ic_sleep_4
5 -> R.drawable.ic_sleep_5
else -> R.drawable.ic_sleep_active
})
}
Etapa 2: atualizar o SleepNightAdapter
- Abra o
SleepNightAdapter.kt
- Exclua tudo no método
bind()
, porque agora você pode usar a vinculação de dados e os novos adaptadores para fazer esse trabalho para você.
fun bind(item: SleepNight) {
}
- Dentro de
bind()
, atribua a suspensão aitem
, porque você precisa informar o objeto de vinculação sobre o novoSleepNight
.
binding.sleep = item
- Abaixo dessa linha, adicione
binding.executePendingBindings()
. Essa chamada é uma otimização que pede que a vinculação de dados execute imediatamente as vinculações pendentes. É sempre bom chamarexecutePendingBindings()
ao usar adaptadores de vinculação em umaRecyclerView
, já que isso pode acelerar um pouco o dimensionamento das visualizações.
binding.executePendingBindings()
Etapa 3: adicionar vinculações ao layout XML
- Abra o
list_item_sleep_night.xml
- No
ImageView
, adicione uma propriedadeapp
com o mesmo nome do adaptador de vinculação que define a imagem. Transmita a variávelsleep
, conforme mostrado abaixo.
Essa propriedade cria a conexão entre a visualização e o objeto de vinculação pelo adaptador. Sempre que osleepImage
é referenciado, o adaptador adapta os dados daSleepNight
.
app:sleepImage="@{sleep}"
- Faça o mesmo para as visualizações de texto
sleep_length
equality_string
. Sempre que os métodossleepDurationFormatted
ousleepQualityString
são referenciados, os adaptadores adaptam os dados doSleepNight
.
app:sleepDurationFormatted="@{sleep}"
app:sleepQualityString="@{sleep}"
- Execute o app. Ele funciona exatamente como antes. Os adaptadores de vinculação cuidam de todo o trabalho de formatação e atualização das visualizações à medida que os dados mudam, simplificando o
ViewHolder
e fornecendo o código muito mais estruturado do que antes.
Você exibiu a mesma lista para os últimos exercícios. Por padrão, isso mostra que a interface Adapter
permite arquitetar o código de várias maneiras diferentes. Quanto mais complexo for o código, mais importante será arquitetá-lo bem. Em apps de produção, esses padrões e outros são usados com RecyclerView
. Os padrões funcionam e cada um tem seus benefícios. A opção escolhida depende do que você está criando.
Parabéns! Você já está no caminho certo para dominar RecyclerView
no Android.
Projeto do Android Studio: RecyclerViewDiffUtilDataBinding.
DiffUtil
:
RecyclerView
tem uma classe chamadaDiffUtil
, que serve para calcular as diferenças entre duas listas.- A
DiffUtil
tem uma classe chamadaItemCallBack
que será estendida para descobrir a diferença entre duas listas. - Na classe
ItemCallback
, é necessário modificar os métodosareItemsTheSame()
eareContentsTheSame()
.
ListAdapter
:
- Para ter um gerenciamento de listas sem custo financeiro, você pode usar a classe
ListAdapter
em vez deRecyclerView.Adapter
. No entanto, se você usar aListAdapter
, precisará criar seu próprio adaptador para outros layouts. É por isso que este codelab mostra como fazer isso. - Para abrir o menu de intents no Android Studio, posicione o cursor sobre qualquer item do código e pressione
Alt+Enter
(Option+Enter
no Mac). Esse menu é particularmente útil para refatorar código e criar stubs para implementar métodos. O menu é sensível ao contexto. Portanto, é necessário posicionar o cursor exatamente para chegar ao menu correto.
Vinculação de dados:
- Use a vinculação de dados no layout do item para vincular dados às visualizações.
Como vincular adaptadores:
- Você já usou
Transformations
para criar strings de dados. Se você precisar vincular dados de tipos diferentes ou complexos, forneça adaptadores de vinculação para ajudar na vinculação. - Para declarar um adaptador de vinculação, defina um método que use um item e uma visualização e inclua a anotação
@BindingAdapter
no método. No Kotlin, você pode programar o adaptador de vinculação como uma função de extensão noView
. Transmita o nome da propriedade que o adaptador adapta. Exemplo:
@BindingAdapter("sleepDurationFormatted")
- No layout XML, defina uma propriedade
app
com o mesmo nome do adaptador de vinculação. Transmita uma variável com os dados. Exemplo:
.app:sleepDurationFormatted="@{sleep}"
Cursos da Udacity:
Documentação do desenvolvedor Android:
- Criar uma lista com o RecyclerView
RecyclerView
DiffUtil
- Biblioteca Data Binding
- Como vincular adaptadores
notifyDataSetChanged()
Transformations
Outros recursos:
Esta seção lista as possíveis atividades para os alunos que estão trabalhando neste codelab como parte de um curso ministrado por um instrutor. Cabe ao instrutor fazer o seguinte:
- Se necessário, atribua o dever de casa.
- Informe aos alunos como enviar o dever de casa.
- Atribua nota aos trabalhos de casa.
Os professores podem usar essas sugestões o quanto quiserem, e eles devem se sentir à vontade para passar o dever de casa como achar adequado.
Se você estiver fazendo este codelab por conta própria, use essas atividades para testar seu conhecimento.
Responda a estas perguntas
Pergunta 1
Quais das opções a seguir são necessárias para usar DiffUtil
? Selecione todas as opções aplicáveis.
▢ Ampliar a classe ItemCallBack
.
▢ Modificar areItemsTheSame()
.
▢ Modificar areContentsTheSame()
.
▢ Use vinculação de dados para rastrear as diferenças entre os itens.
Pergunta 2
Quais das alternativas a seguir são verdadeiras sobre os adaptadores de vinculação?
▢ Um adaptador de vinculação é uma função com uma anotação @BindingAdapter
.
▢ Usar um adaptador de vinculação permite separar a formatação dos dados do armazenador de visualização.
▢ É necessário usar um RecyclerViewAdapter
se você quiser usar adaptadores de vinculação.
▢ Os adaptadores de vinculação são uma boa solução quando é preciso transformar dados complexos.
Pergunta 3
Quando usar Transformations
em vez de um adaptador de vinculação? Selecione todas as opções aplicáveis.
▢ Seus dados são simples.
▢ Você está formatando uma string.
▢ Sua lista é muito longa.
▢ Seu ViewHolder
contém apenas uma visualização.
Inicie a próxima lição: