
Quando o desenvolvedor não é cuidadoso o suficiente, as coisas podem correr muito mal. Por exemplo, as omissões clássicas do desenvolvedor são o uso de uma nova versão da API que não é compatível com o código antigo, a execução de ações que requerem permissões especiais de usuário e lacunas na localização do aplicativo. E estes são apenas alguns deles.
Além disso, Java e Kotlin, como qualquer outra linguagem de programação, têm suas próprias construções que podem levar a um desempenho ruim.
Hello fiapo
Usamos uma ferramenta chamada Lint (ou Linter) para evitar esses problemas. O Lint é uma ferramenta de análise de código estática que ajuda os desenvolvedores a detectar possíveis problemas antes da compilação do código. O Lint executa várias verificações do código-fonte, que podem detectar problemas como variáveis não utilizadas ou argumentos de função, simplificação de condições, escopo incorreto, variáveis ou funções indefinidas, código mal otimizado etc. Quando falamos sobre o desenvolvimento do Android, existem centenas de verificações do Lint prontas para uso.
Mas, às vezes, precisamos encontrar problemas específicos em nosso código que não sejam cobertos por essas verificações existentes.
Olá cheques personalizados Lint
Antes de começarmos a codificar, vamos definir nosso objetivo e ver como implementá-lo passo a passo usando a API Lint. O objetivo é criar uma verificação para detectar uma chamada de método incorreta para um objeto. A idéia desse teste é determinar se o método de instalação do ouvinte no componente View é tal que interrompe vários cliques consecutivos no componente, para que possamos evitar a abertura da mesma atividade ou o acesso à rede várias vezes.
As verificações de usuário do Lint são gravadas como parte do módulo Java (ou Kotlin) padrão. A maneira mais fácil de começar é criar um projeto simples baseado em Gradle (não precisa ser um projeto Android).
Em seguida, adicione as dependências do Lint. No arquivo build.gradle
do seu módulo, adicione:
compileOnly "com.android.tools.lint:lint-api:$lintVersion" compileOnly "com.android.tools.lint:lint-checks:$lintVersion"
Agora, há um truque que aprendi ao pesquisar esse tópico. lintVersion
deve ser gradlePluginVersion + 23.0.0
. gradlePluginVersion
é uma variável definida no arquivo build.gradle
no nível do projeto. E, no momento, a versão estável mais recente é a 3.3.0. Isso significa que lintVersion
deve ser 26.3.0.
Cada verificação de cotão consiste em 4 partes:
- O problema é o problema em nosso código que estamos tentando evitar. Quando a verificação do cotão falha, isso é relatado ao desenvolvedor.
- O Detector é uma ferramenta de localização de problemas que fornece a API do Lint.
- Uma implementação é uma área em que um problema pode surgir (arquivo de origem, arquivo XML, código compilado etc.).
- Um registro é um registro de verificação personalizado do Lint que será usado com um registro existente contendo verificações predefinidas.
Implementação
Vamos começar criando uma implementação para nossa validação personalizada. Cada implementação consiste em uma classe que implementa um detector e um escopo.
val correctClickListenerImplementation = Implementation(CorrectClickListenerDetector::class.java, Scope.JAVA_FILE_SCOPE)
Lembre-se de que Scope.JAVA_FILE_SCOPE
também funcionará para as classes Kotlin.
O problema
O próximo passo é usar esta implementação para determinar o problema. Cada problema consiste em várias partes:
- ID é um identificador exclusivo.
- Descrição - uma declaração curta (5-6 palavras) do problema.
- Explicação Uma explicação completa de um problema com uma sugestão sobre como corrigir isso.
- Categoria - a categoria do problema (desempenho, tradução, segurança etc.).
- Prioridade - A importância do problema, no intervalo de 1 a 10, onde 10 é o mais alto. Isso será usado para classificar problemas no relatório criado quando o Lint foi lançado.
- Gravidade - a gravidade do problema (fatal, erro, aviso, informação ou ignorar).
- Uma implementação é uma implementação que será usada para detectar esse problema.
val ISSUE_CLICK_LISTENER = Issue.create( id = "UnsafeClickListener", briefDescription = "Unsafe click listener", explanation = """" This check ensures you call click listener that is throttled instead of a normal one which does not prevent double clicks. """.trimIndent(), category = Category.CORRECTNESS, priority = 6, severity = Severity.WARNING, implementation = correctClickListenerImplementation )
Detector
A API Lint oferece interfaces para cada área que você pode definir em uma implementação. Cada uma dessas interfaces fornece métodos que você pode substituir e acessar partes do código que lhe interessam.
- UastScanner - arquivos Java ou Kotlin (UAST - Árvore de sintaxe abstrata unificada (árvore de sintaxe abstrata unificada russa)).
- ClassScanner - arquivos compilados (bytecode).
- BinaryResourceScanner - recursos binários como bitmaps ou arquivos
res/raw
. - ResourceFolderScanner - pastas de recursos (arquivos não específicos nelas).
- XmlScanner - arquivos XML.
- GradleScanner - arquivos Gradle.
- OtherFileScanner - tudo o resto.
Além disso, a classe Detector
é uma classe base que possui implementações vazias de todos os métodos fornecidos por cada uma das interfaces acima; portanto, você não precisa implementar a interface completa caso precise de apenas um método.
Agora estamos prontos para implementar um detector que verificará a chamada de método correta para o objeto.
private const val REPORT_MESSAGE = "Use setThrottlingClickListener" class CorrectClickListenerDetector : Detector(), Detector.UastScanner { override fun getApplicableUastTypes(): List<Class<out UElement>>? { return listOf<Class<out UElement>>(UCallExpression::class.java) } /** * UAST, , * UAST . UElementHandler, * , , * , , , , .. * , * . — , * , , . */ override fun createUastHandler(context: JavaContext): UElementHandler? { return object: UElementHandler() { override fun visitCallExpression(node: UCallExpression) { if (node.methodName != null && node.methodName?.equals("setOnClickListener", ignoreCase = true) == true) { context.report(ISSUE_CLICK_LISTENER, node, context.getLocation(node), REPORT_MESSAGE, createFix()) } } } } private fun createFix(): LintFix { return fix().replace().text("setOnClickListener").with("setThrottlingClickListener").build() } }
O registro
A última coisa que precisamos fazer é adicionar problemas ao nosso registro e informar ao Lint que existe um registro de problemas especial que ele deve usar junto com o padrão.
class MyIssueRegistry : IssueRegistry() { override val issues: List<Issue> = listOf(ISSUE_CLICK_LISTENER) }
No nível do módulo build.gradle
:
jar { manifest { attributes("Lint-Registry-v2": "co.infinum.lint.MyIssueRegistry") } }
onde co.infinum.lint
é um pacote da classe MyIssueRegistry
. Agora você pode executar a tarefa jar
usando o script gradlew
, e a biblioteca deve aparecer no diretório build/libs
.
Aqui está outro exemplo de verificação de usuário do Lint, onde você pode ver como processar arquivos XML.
Use
Sua nova verificação de cotão está pronta para uso no projeto. Se essa verificação puder ser aplicada a todos os projetos, você poderá colocá-la na pasta ~/.android/lint
(você pode criá-la se ela ainda não existir).
Além disso, você pode colocar seu cheque em um módulo separado em seu projeto e habilitá-lo como qualquer outra dependência usando o método lintChecks
.
Vale a pena?
O Lint é uma ferramenta realmente boa que todo desenvolvedor deve usar. Ser capaz de detectar problemas potenciais com seu código antecipadamente é muito útil. Embora as verificações personalizadas não sejam fáceis de escrever, principalmente devido à complexidade da API, elas definitivamente valem a pena e podem economizar muito tempo e esforço no futuro.