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
Em codelabs anteriores deste curso, você usou a função findViewById()
para receber referências a visualizações. Quando o app tem hierarquias de visualização complexas, o findViewById()
é caro e deixa o app mais lento, porque o Android percorre a hierarquia de visualização, começando pela raiz, até encontrar a visualização desejada. Felizmente, existe uma maneira melhor.
Para definir dados em visualizações, você usou recursos de string e definiu os dados da atividade. Seria mais eficiente se a visualização soubesse sobre os dados. Felizmente, isso é possível.
Neste codelab, você vai aprender a usar a vinculação de dados para eliminar a necessidade de findViewById()
. Você também vai aprender a usar a vinculação de dados para acessar dados diretamente de uma visualização.
O que você já precisa saber
Você precisa:
- O que é uma atividade e como configurar uma atividade com um layout em
onCreate()
. - Criar uma visualização de texto e definir o texto que ela vai mostrar.
- Usar
findViewById()
para receber uma referência a uma visualização. - Como criar e editar um layout XML básico para uma visualização.
O que você vai aprender
- Como usar a biblioteca Data Binding para eliminar chamadas ineficientes para
findViewById()
. - Como acessar dados de apps diretamente do XML.
Atividades deste laboratório
- Modifique um app para usar a vinculação de dados em vez de
findViewById()
e acesse os dados diretamente dos arquivos XML de layout.
Neste codelab, você vai começar com o app AboutMe e mudar o app para usar a vinculação de dados. O app vai ficar exatamente igual quando você terminar.
Confira o que o app AboutMe faz:
- Quando o usuário abre o app, ele mostra um nome, um campo para inserir um apelido, um botão Concluído, uma imagem de estrela e um texto rolável.
- O usuário pode inserir um apelido e tocar no botão Concluído. O campo editável e o botão são substituídos por uma visualização de texto que mostra o apelido inserido.
Você pode usar o código criado no codelab anterior ou fazer o download do código AboutMeDataBinding-Starter no GitHub.
O código que você escreveu em codelabs anteriores usa a função findViewById()
para receber referências a visualizações.
Sempre que você usa findViewById()
para pesquisar uma visualização depois que ela é criada ou recriada, o sistema Android percorre a hierarquia de visualizações no momento da execução para encontrá-la. Quando o app tem apenas algumas visualizações, isso não é um problema. No entanto, os apps de produção podem ter dezenas de visualizações em um layout, e mesmo com o melhor design, haverá visualizações aninhadas.
Imagine um layout linear que contém uma visualização de rolagem que contém uma visualização de texto. Em uma hierarquia de visualizações grande ou profunda, encontrar uma visualização pode levar tempo suficiente para diminuir a velocidade do app para o usuário. O armazenamento em cache de visualizações em variáveis pode ajudar, mas ainda é necessário inicializar uma variável para cada visualização, em cada namespace. Com muitas visualizações e várias atividades, isso também aumenta.
Uma solução é criar um objeto que contenha uma referência a cada visualização. Esse objeto, chamado de objeto Binding
, pode ser usado por todo o app. Essa técnica é chamada de vinculação de dados. Depois que um objeto de vinculação é criado para seu app, é possível acessar as visualizações e outros dados por ele, sem precisar percorrer a hierarquia de visualização ou pesquisar os dados.
A vinculação de dados tem os seguintes benefícios:
- O código é mais curto, fácil de ler e de manter do que o que usa
findByView()
. - Os dados e as visualizações estão claramente separados. Esse benefício da vinculação de dados se torna cada vez mais importante mais adiante neste curso.
- O sistema Android percorre a hierarquia de visualização apenas uma vez para receber cada visualização, e isso acontece durante a inicialização do app, não em tempo de execução quando o usuário está interagindo com ele.
- Você recebe segurança de tipos para acessar visualizações. Segurança de tipo significa que o compilador valida tipos durante a compilação e gera um erro se você tentar atribuir o tipo errado a uma variável.
Nesta tarefa, você vai configurar a vinculação de dados e usá-la para substituir chamadas de findViewById()
por chamadas ao objeto de vinculação.
Etapa 1: ativar a vinculação de dados
Para usar a vinculação de dados, é necessário ativá-la no arquivo Gradle, já que ela não é ativada por padrão. Isso acontece porque a vinculação de dados aumenta o tempo de compilação e pode afetar o tempo de inicialização do app.
- Se você não tiver o app AboutMe de um codelab anterior, acesse o código AboutMeDataBinding-Starter no GitHub. Abra no Android Studio.
- Abra o arquivo
build.gradle (Module: app)
. - Na seção
android
, antes da chave de fechamento, adicione uma seçãodataBinding
e definaenabled
comotrue
.
dataBinding {
enabled = true
}
- Quando solicitado, sincronize o projeto. Se não aparecer uma solicitação, selecione File > Sync Project with Gradle Files.
- Você pode executar o app, mas não vai notar nenhuma mudança.
Etapa 2: mudar o arquivo de layout para que ele possa ser usado com a vinculação de dados
Para trabalhar com vinculação de dados, você precisa incluir o layout XML em uma tag <layout>
. Assim, a classe raiz não é mais um grupo de visualizações, mas sim um layout que contém grupos de visualizações e visualizações. O objeto de vinculação pode então conhecer o layout e as visualizações nele.
- Abra o arquivo
activity_main.xml
. - Mude para a guia Texto.
- Adicione
<layout></layout>
como a tag mais externa ao redor de<LinearLayout>
.
<layout>
<LinearLayout ... >
...
</LinearLayout>
</layout>
- Escolha Code > Reformat code para corrigir o recuo do código.
As declarações de namespace de um layout precisam estar na tag mais externa.
- Corte as declarações de namespace do
<LinearLayout>
e cole-as na tag<layout>
. Sua tag de abertura<layout>
deve ter a aparência mostrada abaixo, e a tag<LinearLayout>
só pode conter propriedades de visualização.
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
- Crie e execute o app para verificar se você fez isso corretamente.
Etapa 3: criar um objeto de vinculação na atividade principal
Adicione uma referência ao objeto de vinculação à atividade principal para poder usá-lo no acesso às visualizações:
- Abra o arquivo
MainActivity.kt
. - Antes de
onCreate()
, no nível superior, crie uma variável para o objeto de vinculação. Essa variável é chamada debinding
.
O tipo debinding
, a classeActivityMainBinding
, é criado pelo compilador especificamente para essa atividade principal. O nome é derivado do nome do arquivo de layout, ou seja,activity_main + Binding
.
private lateinit var binding: ActivityMainBinding
- Se solicitado pelo Android Studio, importe
ActivityMainBinding
. Se não aparecer uma solicitação, clique emActivityMainBinding
e pressioneAlt+Enter
(Option+Enter
em um Mac) para importar essa classe ausente. Para mais atalhos de teclado, consulte Atalhos de teclado.
A instruçãoimport
deve ser semelhante à mostrada abaixo.
import com.example.android.aboutme.databinding.ActivityMainBinding
Em seguida, substitua a função setContentView()
atual por uma instrução que faça o seguinte:
- Cria o objeto de vinculação.
- Usa a função
setContentView()
da classeDataBindingUtil
para associar o layoutactivity_main
aoMainActivity
. Essa funçãosetContentView()
também cuida de algumas configurações de vinculação de dados para as visualizações.
- Em
onCreate()
, substitua a chamadasetContentView()
pela seguinte linha de código.
binding = DataBindingUtil.setContentView(this, R.layout.activity_main)
- Importe
DataBindingUtil
.
import androidx.databinding.DataBindingUtil
Etapa 4: usar o objeto de vinculação para substituir todas as chamadas para findViewById()
Agora você pode substituir todas as chamadas para findViewById()
por referências às visualizações que estão no objeto de vinculação. Quando o objeto de vinculação é criado, o compilador gera os nomes das visualizações no objeto de vinculação com base nos IDs das visualizações no layout, convertendo-os para camel case. Por exemplo, done_button
é doneButton
no objeto de vinculação, nickname_edit
se torna nicknameEdit
e nickname_text
se torna nicknameText
.
- Em
onCreate()
, substitua o código que usafindViewById()
para encontrar odone_button
por um código que faz referência ao botão no objeto de vinculação.
Substitua este código:findViewById<Button>(R.id.
done_button
)
por:binding.doneButton
O código finalizado para definir o listener de clique emonCreate()
vai ficar assim.
binding.doneButton.setOnClickListener {
addNickname(it)
}
- Faça o mesmo para todas as chamadas de
findViewById()
na funçãoaddNickname()
.
Substitua todas as ocorrências defindViewById<
View
>(R.id.
id_view
)
porbinding.
idView
. Faça isso da seguinte maneira:
- Exclua as definições das variáveis
editText
enicknameTextView
com as chamadas parafindViewById()
. Isso vai gerar erros. - Para corrigir os erros, extraia as visualizações
nicknameText
,nicknameEdit
edoneButton
do objetobinding
em vez das variáveis (excluídas). - Substitua
view.visibility
porbinding.doneButton.visibility
. Usarbinding.doneButton
em vez deview
transmitido torna o código mais consistente.
O resultado é o seguinte código:
binding.nicknameText.text = binding.nicknameEdit.text
binding.nicknameEdit.visibility = View.GONE
binding.doneButton.visibility = View.GONE
binding.nicknameText.visibility = View.VISIBLE
- Não há mudanças na funcionalidade. Opcionalmente, é possível eliminar o parâmetro
view
e atualizar todos os usos deview
para usarbinding.doneButton
dentro dessa função.
- O
nicknameText
exige umString
, enicknameEdit.text
é umEditable
. Ao usar a vinculação de dados, é necessário converter explicitamente oEditable
em umString
.
binding.nicknameText.text = binding.nicknameEdit.text.toString()
- Você pode excluir as importações esmaecidas.
- Kotlinize a função usando
apply{}
.
binding.apply {
nicknameText.text = nicknameEdit.text.toString()
nicknameEdit.visibility = View.GONE
doneButton.visibility = View.GONE
nicknameText.visibility = View.VISIBLE
}
- Crie e execute o app. Ele vai parecer e funcionar exatamente como antes.
Você pode aproveitar a vinculação de dados para disponibilizar uma classe de dados diretamente a uma visualização. Essa técnica simplifica o código e é extremamente valiosa para lidar com casos mais complexos.
Neste exemplo, em vez de definir o nome e o apelido usando recursos de string, você cria uma classe de dados para o nome e o apelido. Você disponibiliza a classe de dados para a visualização usando a vinculação de dados.
Etapa 1: criar a classe de dados MyName
- No Android Studio, no diretório
java
, abra o arquivoMyName.kt
. Se você não tiver esse arquivo, crie um novo arquivo Kotlin e chame-o deMyName.kt
. - Defina uma classe de dados para o nome e o apelido. Use strings vazias como valores padrão.
data class MyName(var name: String = "", var nickname: String = "")
Etapa 2: adicionar dados ao layout
No arquivo activity_main.xml
, o nome está definido em um TextView
de um recurso de string. É necessário substituir a referência ao nome por uma referência aos dados na classe de dados.
- Abra
activity_main.xml
na guia Texto. - Na parte de cima do layout, entre as tags
<layout>
e<LinearLayout>
, insira uma tag<data></data>
. É aqui que você vai conectar a visualização aos dados.
<data>
</data>
Dentro das tags de dados, você pode declarar variáveis nomeadas que contêm uma referência a uma classe.
- Na tag
<data>
, adicione uma tag<variable>
. - Adicione um parâmetro
name
para dar à variável o nome"myName"
. Adicione um parâmetrotype
e defina o tipo como um nome totalmente qualificado da classe de dadosMyName
(nome do pacote + nome da variável).
<variable
name="myName"
type="com.example.android.aboutme.MyName" />
Agora, em vez de usar o recurso de string para o nome, você pode fazer referência à variável myName
.
- Substitua
android:text="@string/name"
pelo código abaixo.
@={}
é uma diretiva para receber os dados referenciados dentro das chaves.
myName
faz referência à variável myName
que você definiu anteriormente, que aponta para a classe de dados myName
e busca a propriedade name
da classe.
android:text="@={myName.name}"
Etapa 3: criar os dados
Agora você tem uma referência aos dados no arquivo de layout. Em seguida, crie os dados reais.
- Abra o arquivo
MainActivity.kt
. - Acima de
onCreate()
, crie uma variável particular, também chamadamyName
por convenção. Atribua à variável uma instância da classe de dadosMyName
, transmitindo o nome.
private val myName: MyName = MyName("Aleks Haecky")
- Em
onCreate()
, defina o valor da variávelmyName
no arquivo de layout como o valor da variávelmyName
que você acabou de declarar. Não é possível acessar a variável diretamente no XML. Você precisa acessá-lo pelo objeto de vinculação.
binding.myName = myName
- Isso pode mostrar um erro, porque é necessário atualizar o objeto de vinculação depois de fazer alterações. Crie o app, e o erro vai desaparecer.
Etapa 4: usar a classe de dados para o apelido na TextView
A última etapa é usar a classe de dados para o apelido no TextView
.
- Abra
activity_main.xml
. - Na visualização de texto
nickname_text
, adicione uma propriedadetext
. Faça referência aonickname
na classe de dados, conforme mostrado abaixo.
android:text="@={myName.nickname}"
- Em
ActivityMain
, substituanicknameText.text = nicknameEdit.text.toString()
por um código para definir o apelido na variávelmyName
.
myName?.nickname = nicknameEdit.text.toString()
Depois que o apelido for definido, você vai querer que seu código atualize a interface com os novos dados. Para isso, invalide todas as expressões de vinculação para que sejam recriadas com os dados corretos.
- Adicione
invalidateAll()
depois de definir o apelido para que a interface seja atualizada com o valor no objeto de vinculação atualizado.
binding.apply {
myName?.nickname = nicknameEdit.text.toString()
invalidateAll()
...
}
- Crie e execute o app. Ele vai funcionar exatamente da mesma forma que antes.
Projeto do Android Studio: AboutMeDataBinding
Etapas para usar a vinculação de dados e substituir chamadas para findViewById()
:
- Ative a vinculação de dados na seção android do arquivo
build.gradle
:dataBinding { enabled = true }
- Use
<layout>
como a visualização raiz no layout XML. - Defina uma variável de vinculação:
private lateinit var binding: ActivityMainBinding
- Crie um objeto de vinculação em
MainActivity
, substituindosetContentView
:binding = DataBindingUtil.setContentView(this, R.layout.activity_main)
- Substitua as chamadas para
findViewById()
por referências à visualização no objeto de vinculação. Por exemplo:findViewById<Button>(R.id.done_button) ⇒ binding.doneBu
tton
. No exemplo, o nome da visualização é gerado em camelCase doid
da visualização no XML.
Etapas para vincular visualizações a dados:
- Crie uma classe de dados para seus dados.
- Adicione um bloco
<data>
dentro da tag<layout>
. - Defina um
<variable>
com um nome e um tipo que seja a classe de dados.
<data>
<variable
name="myName"
type="com.example.android.aboutme.MyName" />
</data>
- Em
MainActivity
, crie uma variável com uma instância da classe de dados. Por exemplo:private val myName: MyName = MyName("Aleks Haecky")
- No objeto de vinculação, defina a variável como a que você acabou de criar:
binding.myName = myName
- No XML, defina o conteúdo da visualização para a variável definida no bloco
<data>
. Use a notação de ponto para acessar os dados na classe de dados.android:text="@={myName.name}"
Curso da Udacity:
Documentação do desenvolvedor Android:
- Biblioteca Data Binding
- Classes de vinculação geradas
- Comece a usar a vinculação de dados
- Layouts e expressões de vinculação
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
Por que você quer minimizar as chamadas explícitas e implícitas para findViewById()
?
- Toda vez que o
findViewById()
é chamado, ele passa pela hierarquia de visualização. - O
findViewById()
é executado na linha de execução principal ou de interface. - Essas chamadas podem deixar a interface do usuário mais lenta.
- Seu app tem menos probabilidade de falhar.
Pergunta 2
Como você descreveria a vinculação de dados?
Por exemplo, confira algumas coisas que você pode dizer sobre a vinculação de dados:
- A grande ideia sobre vinculação de dados é criar um objeto que conecta/mapeia/vincula duas informações distantes no momento da compilação, para que você não precise procurar os dados no tempo de execução.
- O objeto que mostra essas vinculações para você é chamado de objeto de vinculação.
- O objeto de vinculação é criado pelo compilador.
Pergunta 3
Qual das opções a seguir NÃO é um benefício da vinculação de dados?
- O código é mais curto e a manutenção e leitura dele são mais fáceis.
- Os dados e as visualizações estão claramente separados.
- O sistema Android percorre a hierarquia de visualizações apenas uma vez para receber cada visualização.
- Chamar
findViewById()
gera um erro de compilador. - Segurança de tipo para acessar visualizações.
Pergunta 4
Qual é a função da tag <layout>
?
- Você o envolve na visualização raiz no layout.
- As vinculações são criadas para todas as visualizações em um layout.
- Ele designa a visualização de nível superior em um layout XML que usa vinculação de dados.
- Você pode usar a tag
<data>
dentro de um<layout>
para vincular uma variável a uma classe de dados.
Pergunta 5
Qual é a maneira correta de referenciar os dados vinculados no layout XML?
android:text="@={myDataClass.property}"
android:text="@={myDataClass}"
android:text="@={myDataClass.property.toString()}"
android:text="@={myDataClass.bound_data.property}"
Comece a próxima lição:
Para acessar links de outros codelabs neste curso, consulte a página inicial dos codelabs de conceitos básicos do Kotlin para Android.