DEV Community

Cover image for Conhecendo o Koin Annotations
Pedro Francisco de Sousa Neto
Pedro Francisco de Sousa Neto

Posted on

6 1

Conhecendo o Koin Annotations

Declarando dependências com Koin

Através deste artigo você irá aprender todas as formas de como realizar as declarações de dependências utilizando o Koin - Koin DSL, Constructor DSL e finalmente o poderosíssimo Koin Annotations.

Koin DSL

Desta forma declaramos o módulo Koin e inicializamos os construtores de maneira explícita, invocando o famoso get() do Koin.

Exemplo:



class ClassA()
class ClassB(val a: ClassA)

val myModule = module {
    single { ClassA() }
    single { ClassB(a = get()) }
}


Enter fullscreen mode Exit fullscreen mode

Constructor DSL

Desta maneira o trabalho fica bem mais simples, pois não precisamos declarar de maneira explícita os parâmetros dos construtores.

Exemplo:



class ClassA()
class ClassB(val a: ClassA)

val myModule = module {
    singleOf(::ClassA)
    singleOf(::ClassB)
}


Enter fullscreen mode Exit fullscreen mode

Anotações

E por fim, chegamos onde a mágica realmente acontece, pois podemos deixar de usar (ou não) a declaração de dependências num módulo Koin. Apenas utilizando as anotações nas classes das nossas dependências.

Exemplo:



@Single
class ClassA()

@Factory
class ClassB(val a: ClassA)

@KoinViewModel
class MyViewModel(b: ClassB): ViewModel()

@KoinWorker
class UploadFiles: WorkManager()


Enter fullscreen mode Exit fullscreen mode

Também é possível utilizar escopos e propriedades nas suas anotações, para mais detalhes consulte o guia do Koin Annotations aqui.

Koin Annotations

Até aqui acredito que já tenham percebido o quão poderoso é o Koin Annotations, e também o quão é parecido com outros players do mercado, como o Dagger e o Hilt, certo?

O Koin Annotations funciona de maneira adicional aos projetos Kotlin que fazem o uso do Koin. Sendo integrável a projetos já existentes e também há novos projetos.

Com a adoção do Koin Annotations além de deixarmos o código escrito de uma maneira mais simples por anotações, ainda podemos fazer o uso de um recurso que costuma ser o motivo de muitas queixas contrárias ao uso do Koin, que é a verificação das dependências em tempo de compilação!

brain explosion meme animated gif

Compile Safety

Com este recurso é possível validar todas as dependências em tempo de compilação tal qual o Hilt ou o Dagger faz. Apenas adicionando uma linha de código ksp { arg("KOIN_CONFIG_CHECK", "true") }.

Segundo a Kotzilla, empresa responsável por manter e distribuir o Koin, o tempo de compilação do Koin Annotations é 75% mais rápido que o Dagger.

O compile safety é um recurso ainda experimental. Mas tenho aplicado-o num projeto de Server-Driven UI, no core do SDK_ a ser utilizado pelo client-side android. Em mais de 1 mês de uso não tive problemas.

É válido lembrar que o compile safety é configurável então pode ser habilitado ou desabilitado a qualquer momento via arquivo gradle - o padrão é false/desabilitado.

Um ponto negativo, na minha opinião, é que o compile safety não consegue enxergar as dependências declaradas em Koin DSL ou Constructor DSL.

Abaixo temos um exemplo de erro ao tentar compilar um projeto contendo o recurso habilitado e uma dependência não mapeada anotada.

ksp-classb-missing-classa

Troubleshooting: O Koin não conseguiu satisfazer a dependência de ClassA que era esperada no construtor de ClassB.

Mas e os meus módulos?

Por baixo do capô, o Koin Annotations gerará um módulo que contém todas as dependências mapeadas. E para usar este módulo no seu tradicional startKoin é muito simples, exemplo:



// Usar o módulo default gerado pelo Koin Annotations
import org.koin.ksp.generated.*

fun main() {
    startKoin { defaultModule() }
}

// Cenário com N módulos
fun main() {
    startKoin { modules(defaultModule, moduleA, moduleB, existingModule) }
}


Enter fullscreen mode Exit fullscreen mode

Mas e a organização?

Se você pensar num projeto muito grande, com várias dependências, o módulo default pode não soar como algo muito organizado.
Para evitar que o Koin Annotations gere este módulo basta desativar esta configuração padrão com ksp { arg("KOIN_DEFAULT_MODULE", "false") }.

E neste caso, deveremos passar a declarar o uso dos módulos gerados pelas anotações. Veja os exemplos abaixo.

Módulo Koin com Koin Annotations:



@Module
class MyGiantModule


Enter fullscreen mode Exit fullscreen mode

Utilizando o módulo gerado:



import org.koin.ksp.generated.*

fun main() {
    startKoin { modules(MyGiantModule().module) }
}


Enter fullscreen mode Exit fullscreen mode

Como declarar as dependências de cada @Module?

Agora vejamos mais uma anotação para o seu módulo, a @ComponentScan. Ela fará com que todas as dependências declaradas no mesmo package e subpackages sejam mapeadas para o seu @Module. Veja o exemplo a seguir:



@Module
class MyModule


Enter fullscreen mode Exit fullscreen mode

Você também pode especificar o package que deverá ser observado para mapear as dependências. Da seguinte maneira:



@Module
@ComponentScan("com.my.app")
class MyModule


Enter fullscreen mode Exit fullscreen mode

Ainda é possível declarar dependências diretas no seu módulo anotado utilizando funções do Kotlin.



@Module
@ComponentScan("com.my.app")
class MyModule {

    @Factory
    fun service(retrofit: Retrofit): ServiceAPI {
        return retrofit.create(ServiceAPI::class.java)
    }

}


Enter fullscreen mode Exit fullscreen mode

Mas e se eu precisar de mais um @Module?

A inclusão de módulos funciona com as anotações, da seguinte forma:



@Module
class ModuleA

@Module(includes = [ModuleA::class])
class ModuleB


Enter fullscreen mode Exit fullscreen mode

E neste caso poderíamos utilizar da seguinte forma:



import org.koin.ksp.generated.*

fun main() {
startKoin {
modules(
// Irá carregar o ModuleB e o ModuleA
ModuleB().module
)
}
}

Enter fullscreen mode Exit fullscreen mode




Conclusão

O Koin Annotations pode ser utilizados em novos projetos e em projetos já existentes. Além disto ele traz uma maneira bastante idiomática para se trabalhar com injeção de dependência em Kotlin.

Acredito que este era o último passo que faltava para o Koin fazer brilhar os olhos de qualquer desenvolvedor Kotlin!
E só mais uma coisa, o Koin Annotations não é específico da plataforma Android, ele também funciona em projetos multiplataformas.

Próximos Passos

Ainda há mais temas para serem cobertos em relação ao Koin Annotations, por exemplo: especificar o binding de uma dependência, injetar um parâmetro, injetar uma dependência lazy, obter uma lista de dependências de um mesmo tipo, etc.
Para estes e outros temas consulte a documentação oficial do Koin Annotations.

Em breve farei um novo artigo demostrando como adicionar o Koin Annotations em apenas um módulo de um projeto. Desta maneira, demonstrando a flexibilidade que temos para poder evoluir um projeto que já utilize o Koin.

Créditos da imagem da capa

Foto de Pawel Czerwinski na Unsplash

Heroku

This site is built on Heroku

Join the ranks of developers at Salesforce, Airbase, DEV, and more who deploy their mission critical applications on Heroku. Sign up today and launch your first app!

Get Started

Top comments (1)

Collapse
 
jhonatangeison profile image
Jhonatan Geison

Parabens , pub excelente.

Sentry mobile image

Improving mobile performance, from slow screens to app start time

Based on our experience working with thousands of mobile developer teams, we developed a mobile monitoring maturity curve.

Read more