O documento explica três tipos de métodos binding adapter no Android: 1) busca automática por métodos setters, 2) definição explícita de métodos usando @BindingMethods, 3) definição de lógica com @BindingAdapter. Anotações @Binding permitem customizar métodos setters. @BindingMethods direciona métodos para atributos específicos. @BindingAdapter define lógica para escolher métodos.
2. Métodos binding adapter, funcionamento
Primeiro é importante saber que todas as anotações de prefixo @Binding são
anotações "binding adapter" e não somente a anotação @BindingAdapter em
específico.
Há três tipos de funcionamento com métodos binding adapter sendo utilizados, são
eles:
• Busca automática por um método setter, método que aceita como argumento o
o tipo de dado informado no atributo alvo;
• Definição explicita do método que será utilizado - @BindingMethods;
• Definição de lógica sobre qual método será utilizado - @BindingAdapter.
O framework de classes de visualização do Android faz internamente uso de
anotações @Binding, segundo a documentação. Sendo assim o comportamento
padrão é a "busca automática por métodos setters”.
Definições customizadas de métodos binding adapter (o que estudaremos neste
conjunto de slides) sobrescrevem as definições padrões no framework de classes
Android.
3. Busca automática por um método setter
Na busca automática, caso um atributo, oficial Android ou não, seja utilizado, um
método set com o parâmetro correto é buscado. Exemplo:
• Atributo android:text é utilizado tendo como valor @{ car.model };
• A Data Binding API busca por setText( String ), tendo em mente que a
propriedade model é do tipo String;
• Encontrando o método setText( String ), invoca ele para definir o valor em
android:text.
Os passos anteriores para acionamento do correto método setter são os mesmo
até para atributos não oficiais, como, por exemplo, app:textCar. Neste caso a Data
Binding API buscaria por setTextCar(). Se o argumento informado fosse um do tipo
Int, então a API buscaria por um método setTextCar( Int ).
A API tenta realizar a conversão caso necessário, aplicando um cast. O atributo
android:text (que aciona o método setText()) é o mais simples como exemplo de
conversão, pois o tipo aguardado é um CharSequence, porém frequentemente o
tipo fornecido é uma String.
4. Acesso a método específico, @BindingMethods
A anotação @BindingMethods nos permite direcionar o método que será invocado de acordo
com a visualização e o atributo sendo utilizados. Veja o código a seguir:
5. Note que na segunda definição de BindingMethod foi utilizada a superclasse de
TitleTextView, mais precisamente a definição TextView::class. Não há problemas
quanto a isso, pois o que é válido para a superclasse também é válido para as
subclasses.
@BindingMethods aceita quantos BindingMethod forem necessários. Os
argumentos de BindingMethod são, em ordem:
• O tipo da View que terá a alteração do método setter do atributo especificado
- type;
• O atributo que terá um novo método setter vinculado a ele - attribute;
• O rótulo do novo método setter vinculado ao atributo - method.
A documentação oficial informa que a definição de @BindingMethods pode ser
realizada em qualquer classe, incluindo uma classe vazia.
Mas segundo alguns testes realizados a classe tem de ser a classe View que será
utilizada, caso contrário, ao menos para métodos ou atributos novos (não definidos
no framework Android), não haverá vinculo dos métodos binding adapter.
6. Para melhor entendimento, a definição anterior da classe TitleTextView somente
terá efeito se está classe View for utilizada, como a seguir:
Caso contrário, utilizando diretamente o widget TextView, por exemplo, nem
mesmo o método setPaddingLeft() é invocado. O TextView a seguir não aciona
nenhum dos métodos vinculados anteriormente via @BindingMethods:
7. Fique ciente que para métodos binding serem invocados, também é preciso o uso
da sintaxe binding, ou seja, o valor do atributo entre @{}.
Um outro ponto importante: na documentação o namespace é informado como
parte irrelevante, mas quando testando temos que a definição attribute = "text"
não aciona o método setTextTitle() como a definição com o namespace attribute =
“android:text".
Ou seja, sim, para qualquer método binding o namespace do atributo é importante.
Thiengo, quantos conflitos com a documentação oficial em relação a prática. É isso
mesmo?
Sim, provavelmente a documentação oficial não está atualizada de acordo com a
evolução da biblioteca Data Binding.
8. Lógica customizada para acesso a método setter,
@BindingAdapter
Se você estudou o primeiro artigo do Blog sobre Data Binding então já deve conhecer a
anotação @BindingAdapter, que se não utilizada com as devidas precauções pode ser
tão prejudicial quanto os conhecidos "variável global" e "go to".
Diferente de @BindingMethods, métodos @BindingAdapter têm de estar em um
contexto de entidade estática, que no Kotlin é a definição do método dentro de uma
classe object ou companion object e com a anotação @JvmStatic.
O método a seguir é específico para a atualização do padding de topo de uma View
qualquer, e não somente a TitleTextView, que faz uso do atributo android:paddingTop:
9. O namespace do atributo também é importante aqui. Não há necessidade de ser
um atributo já definido no Android, pode ser um qualquer de sua autoria, incluindo o
namespace.
O método setPaddingTop() anterior seria seguramente acionado pela definição a
seguir:
O primeiro argumento de um método @BindingAdapter é a View alvo, os
argumentos posteriores são os valores dos atributos definidos como argumentos
em @BindingAdapter( ... ).
10. Agora uma versão @BindingAdapter com mais de um atributo sendo necessário
(ou não) para acionar um método:
Como requireAll foi definido com o valor false, o uso de qualquer um dos
atributos, android:paddingBottom ou android:paddingRight, acionará o método
setPaddingBottomRight().
Como Int é um "tipo primitivo", o 0 será o valor do parâmetro que não tiver um dado
informado em XML.
Em caso de tipo de dado que não é primitivo, coloque a definição de aceitação de
null na declaração do parâmetro (exemplo: Tipo?) quando o requireAll for false,
caso contrário uma exceção poderá ser gerada.
11. Acessando o antigo e o novo valor em uma mesma definição
de método setter
Caso seja necessário acessar também o valor antigo definido no atributo, a sintaxe
para atendimento a essa necessidade é como a seguir:
12. O método setMarginLeft() será acionado quando houver, por exemplo, definições
em layout como abaixo:
Caso mais de um atributo seja definido, então os primeiros parâmetros depois do
parâmetro da visualização alvo é que serão os valores antigos, veja o exemplo:
13. Conversão de valor via @BindingConversion
Em alguns casos a conversão automática da API Data Binding não funciona, isso, pois a
simples sintaxe de cast geraria uma exceção.
Nessas situações nós podemos utilizar a anotação @BindingConversion em um método de
contexto estático, como quando utilizando a anotação @BindingAdapter.
O método conversion definido pode ter qualquer rótulo, mas para ele ser invocado é necessário:
• o tipo de parâmetro correto;
• e também o tipo de retorno correto.
No exemplo a seguir o atributo android:background está recebendo como valor um tipo Int,
pois @color/nome_cor retorna o ID identificador da cor em arquivo XML de cores, porém o tipo
de valor aguardado em android:background é um Drawable:
14. No código dinâmico podemos ter a seguinte configuração de método de conversão:
Como informado anteriormente, o vinculo entre método setter e atributo ocorre pelo
uso da anotação @BindingConversion em um método de contexto estático e com
os corretos tipos de parâmetro e retorno de função.
Note que de todas as anotações @Binding discutidas neste conjunto de slides,
somente a @BindingConversion trabalha com métodos que têm valor de retorno,
as outras anotações não utilizam valor de retorno.
15. Pontos negativos
• A uso de anotação para método de conversão, @BindingConversion,
deveria aceitar como argumento o atributo vinculado ao novo método de
conversão, algo similar ao que é necessário quando utilizando
@BindingAdapter. A falta desse vinculo explicito pode confundir alguns
desenvolvedores que estão iniciando na biblioteca Data Binding;
• A teoria na documentação é bem inconsistente quando comparada à prática
da API Data Binding, muitas coisas informadas na documentação divergem
da prática, ou seja, provavelmente a documentação, ao menos para a API
utilizada no contexto Kotlin, está depreciada;
• Todos os métodos binding adapters customizados podem oferecer problemas
de leitura de código, como acontece com o uso de "variáveis globais" e de
sintaxes "go to", caso não muito bem documentados.
16. Ponto positivo
• Métodos @BindingMethods podem melhorar a arquitetura do projeto, leitura
de código, para novas visualizações que tendem a utilizar os mesmos
atributos de widgets nativos Android, porém com um processamento
diferente, como fizemos com o TitleTextView.
17. Conclusão
Apesar dos inúmeros problemas entre teoria na documentação e a prática da
parte de métodos binding da API Data Binding, o conhecimento de uso de
@BindingMethods, @BindingAdapter e @BindingConversion pode lhe ajudar
em algumas situações específicas, como foi o caso da visualização personalizada
TitleTextView.
Mas confesso que não vejo o uso dessas anotações sendo algo comum, diferente
do restante dos recursos da biblioteca Data Binding.
De qualquer forma, conhecer por completo a Data Binding API é sim importante,
primeiro porque o mercado de desenvolvedor Android exigi isso, segundo porque
são os problemas específicos de domínio que vão dizer se você está ou não
preparado para utilizar os recursos menos convencionais de qualquer API.
18. Fontes
Conteúdo completo, em texto e em vídeo, no link a seguir:
• Como Utilizar Métodos Binding Adapter no Android.
Fontes:
• Binding adapters;
• Data bindings with custom listeners on custom view - Resposta de subhash.
19. Para estudo
• Treinamento oficial:
• Prototipagem Profissional de Aplicativos Android.
• Meus livros:
• Desenvolvedor Kotlin Android - Bibliotecas para o dia a dia;
• Receitas Para Desenvolvedores Android;
• Refatorando Para Programas Limpos.
• Redes:
• Udemy;
• YouTube;
• Facebook;
• LinkedIn;
• GitHub;
• Twitter;
• Google Plus.
• Blog App.
20. Como Utilizar Métodos Binding
Adapter no Android
thiengo.com.br
Vinícius Thiengo
thiengocalopsita@gmail.com