1 of 23

Hilt

Um pouco sobre a nova lib de Dependency Injection da Google

  • Isaque Coelho

2 of 23

Sumário

  • Overview injeção de dependências
  • Overview sobre Hilt
  • Exemplos de código (Com teoria antes)
  • Exmplo de implementação em app

3 of 23

O que é Injeção de Dependências?

The basic idea of the Dependency Injection is to have a separate object, an assembler, that populates a field in the lister class with an appropriate implementation for the finder interface” - Martin Fowler

Ponto importantes sobre DI:

  • Facilita construção de unit test
  • Facilita na manutenção do código
  • NO SOLID cumpre com o S(Single Responsibility)
  • NO SOLID cumpre com o D(Dependency Inversion)

4 of 23

Onde o Hilt entra nisso?

O Hilt é uma lib android para facilitar a implementação de DI de forma escalável e com desempenho.

  • Baseado no Dagger
  • Declaração através de Annotations

5 of 23

BORA PRO CODE

Afinal, quem sabe, faz ao vivo (como não sei colei ao lado)

buildscript {

...

dependencies {

...

classpath 'com.google.dagger:hilt-android-gradle-plugin:2.28-alpha'

}

}

...

apply plugin: 'kotlin-kapt'

apply plugin: 'dagger.hilt.android.plugin'

android {

...

}

dependencies {

implementation "com.google.dagger:hilt-android:2.28-alpha"

kapt "com.google.dagger:hilt-android-compiler:2.28-alpha"

}

Project Gradle

App Gradle

6 of 23

Configurando o Hilt

Crie uma classe que herde de Application e aplique a anotação @HiltAndroidApp, dessa forma o HIlt poderá ser gerado e anexado ao ciclo de vida do app.

@HiltAndroidApp

class ExampleApplication : Application() { ... }

Obs: Caso projeto seja modularizado é necessário que a classe acima tenha visibilidade dos outros módulos!

7 of 23

Quais classes Android o Hilt é compatível?

  • Application (ao usar o @HiltAndroidApp)
  • Activity
  • Fragment
  • View
  • Service
  • BroadcastReceiver

Exceto Application que possui sua própria anotação, todas as classes descritas acima possuem suporte a injeção através da anotação @AndroidEntryPoint

8 of 23

Exceções de compatibilidade para classes Android

Existe algumas restrições para a compatibilidade em classes Android, veja:

  • Activity deve estender de ComponentActivity (AppCompatActivity)
  • Fragment deve estender de androidx.Fragment
  • NÃO COMPATÍVEL COM FRAGMENTS RETIDOS

9 of 23

DI em classes Android

@AndroidEntryPoint

class ExampleActivity : AppCompatActivity() {

@Inject lateinit var analytics: AnalyticsAdapter

...

}

Inject de campo

Passe a anotação @Inject ao campo que precisa ser injetado.

Obs: Por restrições do Hilt o campo jamais poderá ser private, caso contrário, será gerado um erro de compilação.

10 of 23

Definir vinculação do Hilt

Em caso de classe que não seja android é possível passar um vínculo entre as dependências dela através de injeção de construtor com a anotação @Inject

class AnalyticsAdapter @Inject constructor(

private val service: AnalyticsService

) { ... }

Nesse exemplo o Hilt precisa saber como fornecer instâncias de AnalyticsService.

11 of 23

Perai, como que funciona memo?

No momento de compilação o Hilt gera os componentes do Dagger, em seguida revisa os códigos cumprindo as seguintes etapas:

  • Cria e valida gráficos de dependências, evitando dependências insatisfeitas ou ciclo de dependências.
  • Gera classes no momento da execução para criar objetos reais e as suas dependências.

12 of 23

Módulos Hilt

Quando não se é possível injetar algo diretamente no construtor, como interfaces ou libs externas, o Módulo Hilt permite fornecer instâncias de determinados tipos.

Um módulo Hilt é uma classe anotada com @Module e com @Installin para informar em qual classe do android cada módulo será usado ou instalado.

13 of 23

Componentes gerados para classes do Android

Para cada classe do Android em que você pode executar a injeção de campo, há um componente Hilt associado que pode ser consultado na anotação @InstallIn. Cada componente é responsável por injetar as próprias vinculações na classe Android correspondente.

SingletonComponent

Application

ActivityRetainedComponent

ViewModel

ActivityComponent

Activity

FragmentComponent

Fragment

ViewComponent

View

ViewWithFragmentComponent

View @WithFragmentBindings

ServiceComponent

Service

14 of 23

Injetar instâncias de interface com @Binds

A anotação @Bind informa ao Hilt, através de uma função abstrata, qual implementação usar quando se precisa de uma instancia de uma interface.

15 of 23

Como ficaria as classes?

O constructor-injected precisa ser fornecido para o Hilt saber como gerar as instancias de AnalyticsServiceImpl

interface AnalyticsService {

fun analyticsMethods()

}

class AnalyticsServiceImpl @Inject constructor(

...

) : AnalyticsService { ... }

Interface

Classe que implementa

@Module

@InstallIn(ActivityComponent::class)

abstract class AnalyticsModule {

@Binds

abstract fun bindAnalyticsService(

analyticsServiceImpl: AnalyticsServiceImpl

): AnalyticsService

}

Módulo de injeção

Como ficaria o injeção?

  • Parametro: Diz que o Hilt precisa fornecer uma implementação de AnalyticsServiceImpl.
  • Retorno: Informa ao Hilt que essa função fornece instancias da interface AnalyticsServie.

16 of 23

A injeção pelo construtor também não é possível se a classe vem de uma biblioteca externa (ex: Retrofit) ou se as instâncias precisam ser criadas com o padrão do builder, para isso existe a @Provides.

Injetar instâncias com @Provides

17 of 23

Na prática

@Module

@InstallIn(ActivityComponent::class)

object AnalyticsModule {

@Provides

fun provideAnalyticsService(

...

): AnalyticsService {

return Retrofit.Builder()

.baseUrl("https://example.com")

.build()

.create(AnalyticsService::class.java)

}

}

Módulo de injeção

No função anotada temos:

  • Os parâmetros informam as dependências do tipo correspondente.
  • O retorno informa de qual tipo essa função fornece instâncias.
  • O corpo informa como fornecer uma instância do tipo correspondente e é executado sempre que precisa fornecer uma instância desse tipo.

18 of 23

Mas e a ViewModel, onde fica?

O Hilt inclui extensões para fornecer classes de outras bibliotecas do Jetpack. Atualmente, o Hilt é compatível com os componentes ViewModel e WorkManager do Jetpack.

19 of 23

Mas antes de codar...

Vamos importar umas libs para poder usar ;)

...

dependencies {

...

implementation 'androidx.hilt:hilt-lifecycle-viewmodel:1.0.0-alpha01'

// When using Kotlin.

kapt 'androidx.hilt:hilt-compiler:1.0.0-alpha01'

// When using Java.

annotationProcessor 'androidx.hilt:hilt-compiler:1.0.0-alpha01'

}

App Gradle

20 of 23

ViewModel

Forneça a anotação @HiltViewModel para a classe e em seu construtor aplique a anotação @Inject

Obs: A documentação oficial apresenta 2 anotações: @ViewModelInject (herdada do dagger) para o construtor e a @Assisted para o parâmetro obrigatório savedStateHandle mas ambas as anotações estão DEPRECIADAS e o parametro não é mais obrigatório

@HiltViewModel

class ExampleViewModel @Inject constructor(

private val repository: ExampleRepository

) : ViewModel() {

...

}

21 of 23

Na Activty/Fragment

@AndroidEntryPoint

class ExampleFragment : Fragment() {

private val viewModel: ExampleViewModel by viewModels()

...

}

Com a activity/fragment anotada com @AndroidEntryPoint receba sua viewModel através da extenção ktx viewModels()

22 of 23

Exemplo prático

Substituído anotações depreciadas

App sobre Rick and Morty

Utilizado JetPack Compose, Navigations, Hilt e GraphQL

23 of 23

The End

Muitíssimo obrigado pela

atenção e...

Guilda paga, partiu Almoço ;)