Compreendendo as tarefas do Gradle
Você raramente pode lidar diretamente com tarefas do Gradle e, na maioria das vezes, novos Tasks são adicionados como parte de um plug-in ou como um trecho de código copiado e colado do guia "Como iniciar" das bibliotecas. Não entender como as Tarefas funcionam, sua estrutura e seu ciclo de vida torna os desenvolvedores mais propensos a evitar a inclusão de alterações nessas tarefas, mesmo que haja espaço para melhorias.
Neste artigo, vamos tentar entender o que são Tarefas Gradle, como são criadas e utilizadas e que formas podem assumir.
Coisas básicas que você deve saber sobre um Task:
- A
Taské um trecho de código executável que contém sequências de ações. - As ações são adicionadas a a por
Taskmeio dos encerramentosdoFirst{}e .doLast{} - Uma lista de tarefas disponíveis pode ser acessada executando
./gradlew tasks.
Mais adiante no artigo, se você estiver testando o código em um projeto Android ou qualquer outro projeto com wrapper Gradle, executar a tarefa X significa executar ./gradlew Xno Mac ou gradlew.bat Xno Windows.
Como são as tarefas?
Como você já deve saber, no Gradle, as coisas vêm em muitas formas diferentes, e as Tarefas não são exceção. A definição da tarefa pode ser feita de várias maneiras diferentes, mais comumente em uma como esta:
Ao executar o taskName1acima, a saída não é tão óbvia:
> Configure project :app
Why is this printed first?
> Task :app:taskName
First?
Last?
O código acima é mais descritivo e fala por si. Como você pode ver, estamos chamando o objeto TaskContainercreate() do projeto , após o qual configuramos uma propriedade de grupo do recém-criado e adicionamos ações à lista.tasksTask
Vamos executar nosso taskName1novamente e ver a saída:
> Configure project :app
Why is this printed first?
Why is this printed first?
> Task :app:taskName
First?
Last?
Construir ciclo de vida e fases
Ao contrário das tarefas declaradas acima, a maioria das tarefas depende umas das outras. Para executar uma tarefa, o Gradle precisa entender as tarefas disponíveis no projeto e quais dependências a tarefa possui. Para isso, Gradle cria um grafo de dependência acíclica direcionado e executa tarefas de acordo com ele.
Não fique chocado com o termo gráfico de dependência acíclica direcionada. Tudo o que significa é que:
- As tarefas e suas dependências são compostas em uma estrutura de gráfico onde os nós representam as tarefas e os vértices/linhas representam as dependências.
- As direções dos vértices representam como uma tarefa depende de outras tarefas.
- Acíclico significa que não existem tais tarefas A e B onde ambas são dependentes uma da outra direta ou transitivamente.
- Inicialização — começa com a criação de um
Settingsobjeto de acordo com osettings.gradlearquivo e cria uma hierarquia de subprojetos (no Android Studio chamados de módulos) incluídos no projeto Gradle. - Configuração — configura cada projeto descoberto na fase de inicialização, depois vai para os respectivos
build.gradlearquivos e configuraProjectinstâncias e constrói um gráfico de tarefas das quais a tarefa alvo depende direta ou transitivamente. - Execução — executa uma tarefa e todas as tarefas dependem da tarefa executada, que é conhecida desde a fase de configuração.
Isso pode ser evitado?
Sim, para isso, o Gradle possui API de prevenção de configuração . É um método recomendado para criar tarefas que ajudam a reduzir o tempo de configuração, evitando trabalhar com Taskinstâncias diretamente e, em vez disso, fazê-lo usando TaskProvidere criando uma referência a um arquivo Task.
O uso TaskContainer.register()impedirá que uma tarefa seja incluída na fase de configuração, a menos que a tarefa cadastrada seja executada diretamente ou seja incluída no gráfico de dependência da tarefa que está sendo executada.
Tente executar taskName1mais uma vez e veja se a saída é a mesma de antes de adicionar o arquivo taskName3. Ao mesmo tempo, a execução do taskName3adiciona mais uma linha à parte de configuração dos logs porque agora está incluída na fase de configuração junto com taskName2etaskName1
> Configure project :app
Why is this printed first?
Why is this printed first?
Why is this printed first?
> Task :app:taskName
First?
Last?
Por que simplesmente colocar Actions em uma sequência correta de execução não é suficiente e por que precisamos de doFirst{}e doLast{}?
Por um momento, trate esses fechamentos como algo a ser executado antes e depois de X. O que é X, então?
Para responder a isso, vamos definir uma classe de tarefa simples e executar uma tarefa da classe de tarefa recém-criada, demonstrando mais uma maneira de definir uma tarefa.
Deixando de lado a parte relacionada à configuração dos logs, a saída para ambas as tarefas do novo tipo definido será:
> Task :app:taskName5
First?
Before and after actions annotated with @TaskAction
Last?
Como você pode ver no trecho de código nº 4, a classe CustomTaskTypeextends DefaultTask, uma classe básica que você pode estender para implementar uma classe de tarefa personalizada. O Gradle tem vários tipos de tarefas úteis e prontos para uso que você pode encontrar no Github do Gradle .
O que mais você deve saber sobre as Tarefas do Gradle?
Tasks têm resultados que indicam o que aconteceu com as tarefas durante o processo de construção. Intuitivamente, você pode imaginar que uma tarefa pode ter três resultados — não executada, executada usando resultados armazenados em cache e apenas executada.
No Gradle, existem cinco resultados de tarefas:
NO-SOURCE— uma tarefa não foi executada porque os dados de entrada necessários para sua execução não foram encontrados. Um exemplo de uma entrada pode ser um arquivo anotado com@InputFiles@SkipWhenEmptye@Incrementalque não foi produzido por uma tarefa anterior.SKIPPED- ignorado por algum motivo. Tal motivo pode ser — uma tarefa marcada comoenabled = falseno corpo da tarefa ou excluída do processo de execução via argumento de linha de comando-xe alguns outros.UP-TO-DATE— o resultado de uma tarefa não foi alterado desde a última compilação e pode ser reutilizado. Isso acontece como parte do recurso de compilação incremental .FROM-CACHE— a tarefa pode ser retirada das compilações anteriores. Ele usa um recurso chamado cache de saída de tarefa . É um avanço da compilação incremental usadaUP-TO-DATE, pois pode reutilizar caches remotos obtendo-os do CI. A menos que você tenha ou use sinalizadororg.gralde.caching=trueao executar uma tarefa, isso não é aplicado às suas compilações. Para que uma tarefa seja detectável, ela deve ser anotada como .gradle.properties--build-cache@CacheableTaskEXECUTED— a tarefa é executada com sucesso. Este rótulo não é exibido nos logs.
./gradlew assembleDebug --console=plain
Ordenação de tarefas e dependências
Foi mencionado que a Taskpode depender de outras tarefas, mas como ele se parece no código? Esses indicadores abaixo denotam que as tarefas são dependentes umas das outras:
Defina explicitamente as relações entre duas tarefas:
dependsOn—task X { dependsOn Y }, a tarefa X requer a tarefa Y para sua execução, e se a execução de Y falhar, a execução de X não acontecerá.finalizedBy—task X { finalizedBy Y }a tarefa Y será executada após a tarefa X, mesmo que a X tenha falhado na execução ou tenha sido ignorada.
@OutputFilee@InputFile— é uma maneira implícita de criar uma dependência anotando as entradas e saídas das tarefas. Essa abordagem requer a configuração de tarefas que tenham entradas e saídas correspondentes.
As tarefas podem ser definidas de várias maneiras, mas nem todas são igualmente boas. Para o tempo de configuração, utilize a API de prevenção de configuração e registre tarefas usando TaskContainer.register().
É bom entender os Taskresultados para identificar os pontos fracos da compilação e tentar armazenar em cache os resultados da execução da tarefa sempre que possível, estruturando adequadamente as dependências entre as tarefas e colocando os mecanismos de cache de compilação incremental e de saída da tarefa para funcionar.
Want to Connect?
Connect with me on Twitter and LinkedIn.




































![O que é uma lista vinculada, afinal? [Parte 1]](https://post.nghiatu.com/assets/images/m/max/724/1*Xokk6XOjWyIGCBujkJsCzQ.jpeg)