• Home

    Escolha seu Plano

    Carreiras Alura

    Evolua com profundidade técnica, direção clara e aplicação prática.

    Jornadas guiadas do básico ao avançado com checkpoints práticos, desenhadas para quem busca profundidade e protagonismo técnico.

    Iniciante

    Comece do zero com uma trilha clara e progressiva.

    Fundamentos práticos para dar os primeiros passos com segurança e construir uma base sólida.

    Intermediário

    Continue sua evolução com cursos que conectam fundamentos, ferramentas e prática profissional. Ganhe autonomia, e avance para projetos mais completos.

    Avançado

    Aprofunde temas técnicos e estratégicos para enfrentar desafios mais complexos. Explore boas práticas, arquitetura, performance com visão profissional.

    Cursos

    Ver mais cursos de Back-end
    • Pensamento computacional: fundamentos da computação e lógica de programação
    • Lógica de programação: mergulhe em programação com JavaScript
    • DDD: fundamentos do design orientado a domínio
    • ASP.NET: autenticação e autorização em APIs e aplicações web
    • Microsserviços: migração de monólitos e modularização

    Cursos

    Ver mais cursos de Dados
    • Python para Dados: primeiros passos
    • Excel: domine o editor de planilhas
    • Engenharia de Dados: Orquestração de Pipelines com Apache Airflow
    • Power BI Desktop: construindo meu primeiro dashboard
    • Governança e Arquitetura de Dados

    Cursos

    Ver mais cursos de Inteligência Artificial
    • IA: Explorando o Potencial da Inteligência Artificial Generativa
    • Engenharia de Prompt: Criando Prompts Eficazes para IA Generativa
    • Claude para Análise de Dados: prompts, integrações e automações
    • Agno: criando agentes e sistemas multiagente
    • Engenharia de software na era da IA: segurança de aplicações com agentes, MCPs e código gerado por IA

    Cursos

    Ver mais cursos de Front-end
    • HTML e CSS: ambiente, estrutura e estilo
    • React: realizando testes avançados com Jest e Testing Library
    • React: integrando TypeScript em projetos
    • JavaScript: aprendendo a programar
    • React: aplicando arquiteturas de Micro frontends

    Cursos

    Ver mais cursos de DevOps
    • Sistema Operacional Linux: fundamentos e administração prática
    • Containers e Docker: empacotamento, isolamento e gestão
    • Redes: dos conceitos iniciais à criação de uma intranet
    • Linux: gerenciando diretórios, arquivos, permissões e processos
    • Cibersegurança: Fundamentos e práticas integradas

    Cursos

    Ver mais cursos de UX & Design
    • UX Research: mapeando a experiência da pessoa usuária
    • UX/UI Design: Entregando produtos digitais com IA
    • UI Design: Prototipação e animações interativas
    • Figma: Conhecendo o programa
    • Product Design: métricas e ciclo de vida do produto

    Cursos

    Ver mais cursos de Gestão & Negócios
    • Canva: Criação de landing pages e e-mail marketing
    • Agilidade: como ela pode ajudar a criar um time de alta performance
    • Google Analytics 4: Extrair insights e configurar eventos
    • Management 3.0: gerencie o ambiente, não as pessoas
    • Automação de processos com n8n: Inteligência de dados para Marketing

    Cursos

    Ver mais cursos de Mobile
    • React Native: Estilização e Layouts com Flexbox e StyleSheet
    • Flutter: Graphql e suporte offline
    • Android com Gemini: Trabalhando com textos e imagens na IA
    • Dart: trabalhando com orientação a objetos
    • React Native: Dominando Listas com FlatList e ScrollView

    Carreiras

    Ver mais carreiras
    • Especialista em IA
    • Engenharia de IA
    • Ai native software engineering
    • Arquitetura de Soluções com IA
    • AI Product Design
    • Engenharia de Machine Learning
    • Desenvolvimento Front-End React
    • Engenharia de Dados
    • Cloud Security
    • Social Media Marketing
    • Engenharia de Agentes de IA

    Cursos

    • Engenharia de Prompt: Prompts Eficazes para IA Generativa
    • Claude Code: Criando sua Primeira Aplicação
    • Python: Crie sua Primeira Aplicação
    • Git e GitHub: Compartilhando e Colaborando
    • N8N: Fluxos de Trabalho Avançados

    Cursos

    • Copilot Studio: Solução Multiagentes
    • Padrões de API HTTP e Modelagem de APIs
    • Python para Análise de Dados com SQL
    • Docker: Criando e Gerenciando Containers
    • Design com IA: Otimizando o Processo Criativo

    Cursos

    • Model Context Protocol (MCP)
    • Spec-Driven Development: Dev Assistido por Agentes
    • Arquitetura de Sistemas Distribuídos com Java
    • Governança de Modelos e Reprodutibilidade
    • Pentest: Vulnerabilidades em Aplicações Web

    Escolha seu Plano

    Skills & Go

    O Skills & Go é para Tech Leads, Product Managers, estrategistas e early adopters que transformam ideias em soluções de alto impacto. Em cursos ao vivo e 100% online, você domina a nova era da IA em tempo real.

    Aulas ao vivo

    Saiba mais
    • Agentic Engineering: orquestre múltiplos agentes com confiabilidade
    • Building AI Products: transforme ideias em produtos reais com IA
    • AI Data Strategy: transforme dados em decisões estratégicas com IA

    Escolha seu Plano

    Eventos Alura

    Nossos eventos são pensados para quem quer estar à frente das mudanças em tecnologia, IA e inovação. Em experiências presenciais, você acompanha tendências e se conecta com especialistas que estão moldando o futuro.

    Próximos eventos

    • Imersão Engenharia de Software: Dev na Era da IA
    • IA Conference
    • Alura Signals
  • Talent Lab
  • IA

    Escolha seu Plano

    Conteúdos gratuitos

    Explore conteúdos gratuitos para aprender tecnologia no seu ritmo. Encontre artigos com conteúdos técnicos para aprender na prática, notícias para acompanhar as principais tendências do mercado e o Alura Labs, com análises e reflexões de especialistas sobre tecnologia, IA e carreira.

    Conteúdos gratuitos

    • Artigos
    • Notícias
    • Alura Labs
  • Para Empresas
Ver planos
Links principais
  • Planos e Promoções
  • Links complementares do menu mobile
  • Talent lab
  • Inteligência Artificial
  • Pós Graduações
  • Para Empresas
  • Sobre a Alura
  • Grupo Alun
  • Entrar
    • Home
    • Carreiras
    • Skills & Go
    • Talent Lab
    • Inteligência Artificial
    • Pós Graduações
    • Artigos
    • Sobre a Alura
    • Grupo Alun
    LoginContato
    • LinkedIn
    • Instagram
    • YouTube
    1. Página inicial
    2. Mobile
    3. Injeção de dependência no Android com o Hilt

    Injeção de dependência no Android com o Hilt

    14 min14 minutos de leitura

    14 min14 minutos de leitura

    Publicado: 26/05/2021

    1. Projeto de exemplo
    2. Preparando o ambiente
    3. Configurando a Application
    4. Injetando o ViewModel
    5. Módulos do Hilt
    6. Provendo instâncias no módulo
    7. Otimizando as dependências
    8. Conclusão

    Recentemente, em 18 de maio de 2021, foi anunciada a versão release do Hilt, uma biblioteca para injeção de dependência no Android. A partir dela, evitamos boilerplates, trechos de código que se repetem ao longo do projeto, para configurar e implementar uma solução de injeção de dependência no nosso código, o que não era uma realidade com o Dagger.

    Caso você não sabia o conceito de injeção de dependência e seus benefícios, dê uma olhada neste tópico do artigo de injeção de dependência no Android com o Koin. Você também pode conferir um resumo da documentação do Android que aborda o assunto.

    Dentro dessa proposta, o Hilt é uma biblioteca bastante atrativa recomendada pela equipe de desenvolvedores do Andoid.

    Neste artigo eu vou demonstrar como é possível fazer a configuração do Hilt em um projeto Android com Navigation, ViewModel, Repository, Room e Retrofit! Quer saber como fica essa configuração? Então, bora começar!

    Projeto de exemplo

    Para este artigo, vou considerar o uso do Ceep, um app que simula o Google Keep para cadastrar notas. Se quiser acompanhar os exemplos do artigo, você pode acessar o código-fonte ou baixar o projeto em seu estado inicial (sem a integração com o Hilt).

    Funcionalidades do projeto

    Este tópico é focado em explicar mais sobre o projeto. Então, caso você não tenha interesse, vá para o próximo tópico, "Preparando o ambiente".

    O app lista notas com imagem, título e descrição, sejam armazenadas internamente ou recebidas via web API.

    As técnicas e tecnologias utilizadas neste projeto são:

    • Navigation: configuração da navegação das telas
    • RecyclerView: listagem das notas
    • ConstraintLayout: ViewGroup para implementar o layout das notas
    • Coil: carregar imagens via requisição HTTP
    • Retrofit: requisição HTTP para buscar novas notas
    • Room: Armazenamento interno das notas
    • ViewModel: modelo para manter regra de negócio das Activities/Fragments
    • Coroutines: processamento assíncrono
    • View Binding: busca de views do layout de forma segura

    Amostra animada do app em que as partes vão surgindo até completar a tela: primeiro, aparece o cabeçalho do app onde se lê “Ceep”, em seguida aparecem duas notas na tela (my first title/my first description e my second title/my second description) e, por fim, surgem as imagens meramente ilustrativas de cada nota #inset

    Observações da web API

    As notas apresentadas na amostra são carregadas por meio de uma web API mockada, ou seja, para que você consiga fazer a mesma simulação, você precisa utilizar um endereço de uma API em funcionamento.

    Caso você implemente a sua própria ou utilize uma mockada, é necessário configurar um end-point GET para /notes. Como corpo da resposta, você deve devolver uma lista de notas:

    [
        {
            "id" : 1,
            "title": "my first title",
            "description": "my first description"
        },
        {
            "id" : 2,
            "title": "my second title",
            "description": "my second description"
        }
    ]
    

    O app também funciona sem essa integração com uma web API. O grande detalhe é que ele vai mostrar no logcat que não conseguiu fazer uma comunicação:

    br.com.alura.ceep E/NoteRepository: findAll: failure to fetch new notes from API
    

    Para adicionar notas sem a conexão com a web API, você pode acessar a CeepApp e descomentar o código do onCreate(). Na amostra de código é apresentado um exemplo de como salvar notas:

    class CeepApp : Application() {
        override fun onCreate() {
            super.onCreate()
            saveNotes(
                listOf(
                    Note(
                        title = "first title",
                        description = "first description"
                    ),
                    Note(
                        title = "second title",
                        description = "second description"
                    )
                )
            )
        }
        private fun saveNotes(notes: List<Note>) {
            CoroutineScope(IO).launch {
                AppDatabase.getInstance(this@CeepApp)
                    .getNoteDao().save(notes)
            }
        }
    }
    

    Neste exemplo, foram salvas 2 notas, e você pode modificar a quantidade conforme a sua preferência. A única orientação é que, depois de executar o app uma vez, comente ou apague essa amostra de código para que você consiga testar as mudanças e não apareçam várias notas!

    Agora que passei todas as informações do projeto, vamos começar com a configuração do Hilt!

    Banner do Guia Tático Alura sobre carreira em tecnologia, destacando o mapa da carreira tech. A imagem convida a explorar diferentes caminhos profissionais, comparar possibilidades e encontrar a próxima fase da carreira na área de tecnologia, com chamada “Explore o mapa”.

    Preparando o ambiente

    Para adicionar o Hilt, adicionamos os seguintes scripts:

    • build.gradle do projeto:
    buildscript {
        ...
        ext.hilt_version = '2.35'
        dependencies {
            ...
            classpath "com.google.dagger:hilt-android-gradle-plugin:$hilt_version"
        }
    }
    
    • app/build.gradle do módulo:
    ...
    apply plugin: 'kotlin-kapt'
    apply plugin: 'dagger.hilt.android.plugin'
    android {
        ...
    }
    dependencies {
        implementation "com.google.dagger:hilt-android:$hilt_version"
        kapt "com.google.dagger:hilt-compiler:$hilt_version"
    }
    

    Feitas as modificações, sincronize o projeto com o Gradle.

    Configurando a Application

    Como primeiro passo, precisamos anotar a Application com a @HiltAndroidApp para que o Hilt gere o código a nível de aplicação que vai fornecer as dependências para todas as entidades, desde as classes do Android framework, como também as suas classes do projeto:

    import android.app.Application
    import dagger.hilt.android.HiltAndroidApp
    @HiltAndroidApp
    class CeepApp: Application() {
    
    // rest of the code
    
    
    

    }

    Apenas com essa anotação fizemos a configuração mínima para configurar o Hilt.

    Configurando classes para injetar dependências

    Após configurar o Hilt, podemos anotar as classes que o Hilt pode injetar dependências a partir da @AndroidEntryPoint. Como por exemplo, podemos fazer a nossa primeira configuração na MainActivity:

    @AndroidEntryPoint
    class MainActivity : AppCompatActivity() {
        // rest of the code
    }
    

    A partir de agora, a nossa Activity pode receber dependências a partir do Hilt! Para um primeiro teste, podemos criar a classe TestMyFirstDI com as seguintes informações:

    package br.com.alura.ceep.ui.activity
    // other imports
    import dagger.hilt.android.AndroidEntryPoint
    import javax.inject.Inject
    @AndroidEntryPoint
    class MainActivity : AppCompatActivity() {
        @Inject
        private lateinit var instance: TestMyFirstDI
        override fun onCreate(savedInstanceState: Bundle?) {
            super.onCreate(savedInstanceState)
            Log.i("MainActivity", "onCreate: $instance")
            // rest of the code
    		}
    }
    class TestMyFirstDI @Inject constructor()
    

    Note que precisamos indicar qual construtor da classe deve ser injetado pelo Hilt com a anotação @Inject e, então, criamos uma property lateinit do tipo TestMyFirstDI e anotamos com a @Inject também, pois é dessa forma indicamos para o Hilt qual construtor ele vai utilizar para criar a instância!

    Inclusive, a partir dessa configuração, é indicado à esquerda da property que o mapeamento com o Hilt foi feito:

    Animação que exibe os ícones indicando o mapeamento da dependência `lateinit var instance: TextMyFirstDI` com a classe `TestMyFirstDI` configurada para injeção de dependência na MainActivity #inset

    Dependências na Activity não podem ser privadas! Caso configure dessa forma, ao gerar o código no processo de build, o Hilt vai indicar que não é possível!

    Então, se executamos o app para conferir o valor da instância, temos o seguinte resultado:

    I/MainActivity: onCreate: br.com.alura.ceep.ui.activity.TestMyFirstDI@c7edb3e
    

    E é dessa forma que fazemos a configuração básica de injeção de dependência com o Hilt!

    Por mais que essa demonstração seja simples, sabemos que ao utilizar ferramentas para injeção de dependência no Android, procuramos configurar classes como: ViewModel, Repositories, DAO, Services etc.

    Sendo assim, vamos começar a configuração de injeção de dependência do ViewModel da tela de lista de notas!

    Injetando o ViewModel

    Da mesma forma que fizemos na Activity, para injetar dependências no Fragment, precisamos utilizar a anotação @AndroidEntryPoint:

    @AndroidEntryPoint
    class NotesListFragment : Fragment() {
        // rest of the code
    }
    

    Então, precisamos modificar o ViewModel que queremos injetar também, a diferença é que para o ViewModel temos uma anotação específica para que seja criado a partir de um factory, a @HiltViewModel. Como primeira amostra, vamos criar um ViewModel de teste:

    @HiltViewModel
    class TestViewModel @Inject constructor() : ViewModel()
    

    A partir desta anotação, as classes anotadas com @AndroidEntryPoint, são capazes de injetar o TestViewModel.

    Diferente de classes comuns, em ViewModels precisamos utilizar um ViewModelProvider ou a delegated property viewModels() para injetar dependências com o Hilt:

    @AndroidEntryPoint
    class NotesListFragment : Fragment() {
        // properties
        private val testViewModel: TestViewModel by viewModels()
        override fun onViewCreated(
            view: View,
            savedInstanceState: Bundle?
        ) {
            super.onViewCreated(view, savedInstanceState)
            Log.i("NotesListFragment", "onViewCreated: $testViewModel")
            configureAdapter()
        }
        // rest of the code
    }
    @HiltViewModel
    class TestViewModel @Inject constructor() : ViewModel()
    

    Ao testar o código, o Hilt apresenta a instância pra gente:

    I/NotesListFragment: onViewCreated: br.com.alura.ceep.ui.fragment.TestViewModel@efd0d57
    

    O grande detalhe é que essa delegated property também funciona sem o Hilt! Ou seja, não temos tanto benefício com ViewModels sem dependências! Porém, ao configurar o NoteViewModel:

    @HiltViewModel
    class NoteViewModel @Inject constructor(
        private val repository: NoteRepository
    ) : ViewModel() {
        fun findAll(): Flow<List<Note>> = repository.findAll()
    }
    

    Observe que, dessa vez, o construtor do NoteViewModel tem uma dependência! Ao tentar buildar o projeto, temos a seguinte mensagem de problema:

    [Dagger/MissingBinding] br.com.alura.ceep.repository.NoteRepository cannot be provided without an @Inject constructor or an @Provides-annotated method.
    

    Ela indica que para que seja possível instanciar o NoteViewModel, é necessário indicar também como é possível instanciar o NoteRepository!

    Uma das maneiras de fazer isso é anotando o construtor que desejamos instância do NoteRepository com o @Inject:

    class NoteRepository @Inject constructor(
        private val dao: NoteDao,
        private val service: NoteService
    ) {
        // rest of the code
    }
    

    Ao fazer isso, temos um novo problema ao fazer o build:

    [Dagger/MissingBinding] br.com.alura.ceep.database.dao.NoteDao cannot be provided without an @Provides-annotated method.
    

    Precisamos também indicar ao Hilt como ele cria instâncias do NoteDao e NoteService! O grande detalhe é que são interfaces, ou seja, não temos um construtor para indicar ao Hilt como ele pode criar instâncias de interface.

    Módulos do Hilt

    Nesses casos, utilizamos um recurso conhecido como módulo, que é uma configuração que permite ensinar ao Hilt a criar instâncias de referências que não podem ser criadas a partir de um construtor anotado.

    Para configurar um módulo, precisamos de uma classe para representar o módulo. A representação de um módulo pode ser feita a partir do que ele vai configurar, por exemplo, o NoteDao faz parte da configuração do Room que é realizado à configuração do banco de dados, portanto, podemos nomear como um módulo de banco de dados:

    package br.com.alura.ceep.di.modules;
    class DatabaseModule {
    }
    

    Para iniciar a configuração, precisamos anotar a classe com @Module para indicar ao Hilt que é um módulo e também utilizar a @InstallIn que indica onde o módulo será utilizado/instalado.

    @Module
    @InstallIn
    class DatabaseModule {
    {
    

    Além de anotar, a @InstallIn exige que indiquemos, via argumento, a classe do Android que vamos instalar o módulo. Isso é necessário para determinar em qual entidade do Android a instância será criada e oferecida, bem como o seu ciclo de vida.

    A princípio parece bastante abstrato, mas é mais simples do que parece, pois, basicamente, instalamos módulos em classes como: Application, Activity, Fragment, ViewModel etc.

    Em outras palavras, se você instala o módulo em uma Application, a instância vai ficar disponível para toda aplicação; caso seja para uma Activity, a instância será criada pela Activity e apenas seus membros terão acesso, além disso, será sincronizada com o seu ciclo de vida, ou seja, se a Activity for destruída a instância também será!

    "Então qual o escopo escolhemos?"

    Em casos como o banco de dados, geralmente mantemos a disponibilidade da mesma instância para toda a aplicação. Portanto, podemos instalar o módulo em nível de aplicação. Para isso, utilizamos a referência SingletonComponent:

    @Module
    @InstallIn(SingletonComponent::class)
    class DatabaseModule {
    {
    

    Além da SingletonComponent, o Hilt oferece outras classes para instalar os módulos, você pode conferir aqui as demais possibilidades.

    Provendo instâncias no módulo

    Com o módulo configurado, o nosso próximo passo é configurar como ele vai prover as instâncias que queremos. Por exemplo, se precisamos que ele forneça a instância do NoteDao, criamos um método que retorne esse tipo e o anotamos com @Provides:

    @Module
    @InstallIn
    class DatabaseModule {
        @Provides
        fun provideDao() : NoteDao {
    
    }
    
    
    

    }

    Com o método criado, precisamos instanciar o NoteDao, então, para isso, utilizamos o método getInstance() da classe AppDatabase que cria um NoteDao. O grande detalhe é que esse método precisa de um Context para criar a instância, e não temos acesso no módulo!

    É nesse momento que o Hilt brilha! Pois podemos acessar um Context da aplicação via parâmetro a partir da anotação @ApplicationContext:

    @Module
    @InstallIn(SingletonComponent::class)
    class DatabaseModule {
        @Provides
        fun getNoteDao(@ApplicationContext context: Context) : NoteDao {
            return AppDatabase.getInstance(context).getNoteDao()
        }
    }
    

    Ao fazer o build do projeto, ainda temos o problema com o NoteService, mas já conseguimos ver o mapeamento da NoteDao dentro do NoteRepository:

    Animação mostrando que o cursor clica em um ícone à esquerda da linha 13 (private val dao: NoteDao,) do código que leva para a linha 23 (fun getNoteDao(@ApplicationContext context: Context) : NoteDao{.) #inset

    Com essa configuração, seria o suficiente para testar o app. Porém, observe que temos também o NoteService que podemos configurar de maneira similar ao que fizemos. Então, vamos criar o Módulo para o Retrofit:

    @Module
    @InstallIn(SingletonComponent::class)
    class RetrofitModule {
        @Provides
        fun provideNoteService(): NoteService {
        }
    }
    

    Um padrão comum ao criar provider é utilizar a nomeação provideDependencyName(), ou seja, em vez de getNoteDao(), é mais comum utilizar o provideNoteDao(). Fique à vontade para manter o que preferir, mas, a partir deste ponto, vou utilizar apenas o padrão mais comum.

    O grande detalhe do NoteService é que precisamos de uma instância do Retrofit. Inicialmente, podemos fazer a seguinte implementação para prover o NoteService:

    @Module
    @InstallIn(SingletonComponent::class)
    class RetrofitModule {
        @Provides
        fun provideNoteService(): NoteService {
            val logging = HttpLoggingInterceptor()
            logging.setLevel(HttpLoggingInterceptor.Level.BODY)
            val client: OkHttpClient = OkHttpClient.Builder()
                .addInterceptor(logging)
                .build()
            val retrofit = Retrofit.Builder()
                .baseUrl(BASE_URL)
                .addConverterFactory(MoshiConverterFactory.create())
                .client(client)
                .build()
            return retrofit.create(NoteService::class.java)
        }
    }
    

    Com essa implementação, temos todo o mapeamento necessário e podemos testar o app que ele roda sem problemas.

    Otimizando as dependências

    Por mais que o app funcione, ainda existem alguns detalhes nesta implementação. Por exemplo, para atualizar automaticamente a busca de novos dados com o Room, é necessário que a instância do AppDatabase seja uma instância única em todo app, isto é, um Singleton!

    Da maneira como implementamos, todas as instâncias oferecidas pelo provide são novas instâncias cada vez que uma entidade do Android recebe como injeção, portanto, por padrão, são factories, um padrão que sempre fabrica uma nova instância!

    Para transformar as instâncias como Singleton, utilizamos a anotação @Singleton no provide:

    @Module
    @InstallIn(SingletonComponent::class)
    class DatabaseModule {
        @Singleton
        @Provides
        fun provideNoteDao(@ApplicationContext context: Context) : NoteDao {
        return AppDatabase.getInstance(context).getNoteDao()
        }
    }
    

    O grande detalhe desta configuração é que o NoteDao está sendo o Singleton em vez do AppDatabase, ou seja, somos os responsáveis em oferecer uma instância de AppDatabase como Singleton, como é o caso do método getInstance().

    Para delegar essa responsabilidade para o Hilt, podemos criar um outro provider focado apenas em criar a instância do AppDatabase:

    private const valDATABASE_NAME= "ceep.db"
    @Module
    @InstallIn(SingletonComponent::class)
    class DatabaseModule {
        @Provides
        fun provideNoteDao(db: AppDatabase): NoteDao {
            return db.getNoteDao()
        }
        @Singleton
        @Provides
        fun provideAppDatabase(
            @ApplicationContext context: Context
        ): AppDatabase {
            return Room.databaseBuilder(
                context,
                AppDatabase::class.java,
    						                              DATABASE_NAME
    						                              ).build()
        }
    }
    

    Observe que agora ensinamos o Hilt como ele pode criar um AppDatabase e, a partir dessa configuração, podemos receber instâncias de AppDatabase para configurar dependências! Como o provider do NoteDao precisa de um AppDatabase para ser criado, logo, podemos receber, via parâmetro, a sua dependência (db: AppDatabase).

    Com essa mudança, não temos mais a necessidade de manter a anotação @Singleton para no provide do NoteDao, e a implementação dele fica mais simples!

    Veja também que agora o AppDatabase simplifica bem o seu código dado que não precisa manter mais o getInstance():

    @Database(
        version = 1,
        exportSchema = false,
        entities = [Note::class]
    )
    abstract class AppDatabase : RoomDatabase() {
        abstract fun getNoteDao(): NoteDao
    }
    

    Com essa mudança, pontos de código que usavam a maneira antiga precisam ser ajustados, como é o caso da Application (CeepApp), que tem o código que salva notas diretamente no banco dados, que podemos ajustar para acessar via injeção de dependência:

    @HiltAndroidApp
    class CeepApp : Application() {
        @Inject lateinit var dao: NoteDao
        override fun onCreate() {
            super.onCreate()
    //        saveNotes(
    //            listOf(
    //                Note(
    //                    title = "first title",
    //                    description = "first description"
    //                ),
    //                Note(
    //                    title = "second title",
    //                    description = "second description"
    //                )
    //            )
    //        )
        }
        private fun saveNotes(notes: List<Note>) {
    				CoroutineScope(Dispatchers.IO).launch{
    						dao.save(notes)
    				}
    		}
    }
    

    O NoteViewModelFactory também utiliza uma instância do AppDatabase, porém, não é necessário mantê-lo, dado que o Hilt é o único responsável por criar ViewModels, então, podemos removê-lo do projeto!

    Da mesma maneira que fizemos com o módulo de banco de dados, podemos também fazer com o do Retrofit:

    private const val BASE_URL= "https://your_web_api_address"
    @Module
    @InstallIn(SingletonComponent::class)
    class RetrofitModule {
        @Singleton
        @Provides
        fun provideOkHttpClient(): OkHttpClient {
            val logging = HttpLoggingInterceptor()
            logging.setLevel(HttpLoggingInterceptor.Level.BODY)
            return OkHttpClient.Builder()
                .addInterceptor(logging)
                .build()
        }
        @Singleton
        @Provides
        fun provideRetrofit(client: OkHttpClient): Retrofit {
            return Retrofit.Builder()
                .baseUrl(BASE_URL)
                .addConverterFactory(MoshiConverterFactory.create())
                .client(client)
                .build()
        }
        @Provides
        fun provideNoteService(retrofit: Retrofit): NoteService {
            return retrofit.create(NoteService::class.java)
        }
    }
    

    Com esta implementação, não há mais a necessidade de utilizar o RetrofitInit, portanto, podemos remover do projeto também.

    Conclusão

    Neste artigo, demonstrei a configuração mais simples e comum no Hilt, porém, ainda existem outros detalhes que podem ser úteis no seu projeto Android.

    Caso seja do seu interesse, você pode conferir esta página da documentação para mais detalhes do Hilt.

    E se você gostou deste artigo, a Formação Arquitetura Android é para você!

    Banner do Guia Tático Alura sobre carreira em tecnologia, destacando o mapa da carreira tech. A imagem convida a explorar diferentes caminhos profissionais, comparar possibilidades e encontrar a próxima fase da carreira na área de tecnologia, com chamada “Explore o mapa”.

    Avalie este artigo

    • Foto de Alex Felipe

      Autor(a)

      Alex Felipe

      Alex é instrutor e desenvolvedor e possui experiência em Java, Kotlin, Android. Atualmente cria conteúdo no canal https://www.youtube.com/@AlexFelipeDev.

    Explore por tópico

    • Back-end
    • Dados
    • DevOps
    • Front-end
    • Gestão & Negócios
    • Institucionais
    • Inteligência Artificial
    • Mobile
    • UX & Design

    Leia também

    • 23/02/2022

      Qual a diferença entre Static, Const e Final no Dart

      Ler mais
    • 10/12/2023

      Vale a pena aprender KMP?

      Ler mais
    • 14/08/2016

      Integrando App Android com o Firebase Cloud Messaging

      Ler mais
    Ver mais conteúdos

    Inscreva-se em nossa Newsletter

    Fique por dentro de conteúdos, insights e oportunidades do universo tech. Receba novidades e lançamentos direto no seu e-mail.

    Institucional

    • Sobre nós
    • Trabalhe Conosco
    • Para Empresas
    • Para Escolas
    • Política de Privacidade
    • Compromisso de Integridade
    • Termos de Uso
    • Canal de Ética
    • Código de Ética
    • Fale Conosco
    • Documentos Institucionais
    • Status
    Institucional
    • Sobre nós
    • Trabalhe Conosco
    • Para Empresas
    • Para Escolas
    • Política de Privacidade
    • Compromisso de Integridade
    • Termos de Uso
    • Canal de Ética
    • Código de Ética
    • Fale Conosco
    • Documentos Institucionais
    • Status

    A Alura

    • Como Funciona
    • Inteligência Artificial
    • Plataforma
    • Depoimentos
    • Instrutores(as)
    • Dev em <T>
    • Luri, a Inteligência Artificial da Alura
    • IA Conference
    • Cursos Imersivos
    • Perguntas Frequentes
    A Alura
    • Como Funciona
    • Inteligência Artificial
    • Plataforma
    • Depoimentos
    • Instrutores(as)
    • Dev em <T>
    • Luri, a Inteligência Artificial da Alura
    • IA Conference
    • Cursos Imersivos
    • Perguntas Frequentes

    Conteúdos

    • Alura Cases
    • Imersão Engenharia de Software: Dev na Era da IA
    • Artigos
    • Podcasts
    • Artigos de educação corporativa
    Conteúdos
    • Alura Cases
    • Imersão Engenharia de Software: Dev na Era da IA
    • Artigos
    • Podcasts
    • Artigos de educação corporativa
    Uma Empresa do GrupoLogo Grupo Alun

    Outras empresas do Grupo Alun

    • FIAP
    • STARTSE
    • PM3
    • LUMINA

    Ao submeter seu e-mail, você concorda com a política de privacidade da Alura.

    Redes Sociais & Apps

    instagram
    youtube
    tiktok
    x
    appStore
    googlePlay
    Uma Empresa do GrupoLogo Grupo Alun

    Outras empresas do Grupo Alun

    • FIAP
    • STARTSE
    • PM3
    • LUMINA

    Ao submeter seu e-mail, você concorda com a política de privacidade da Alura.

    Redes Sociais & Apps

    instagram
    youtube
    tiktok
    x
    appStore
    googlePlay
    Alura