• Ramon Ferreira Silva

Como Fazer Injeção de dependências no Android com Dagger

Atualizado: 27 de Ago de 2019

Injeção de Dependencias

Introdução


Continuando o assunto do meu outro post, onde foi apresentado o Dagger, biblioteca de injeção de dependências  no Android, agora vamos ver como implementar o Dagger em um projeto android para fazer injeção de dependências.

Este tutorial irá usar a versão mais recente do Dagger 2, que você pode conferir no GitHub do projeto.


Dagger 2 Api

A versão 2 do Dagger expõe algumas anotações especiais, a maioria nós já vimos no post anterior, mas temos uma nova anotação chamada @Component.

  1. @Module, classe que irá prover as dependências

  2. @Provides, para os métodos provedores da classe de módulos

  3. @Inject, para requisitar um dependência (use no construtor, atributos públicos ou métodos set)

  4. @Component, funciona como um ponte entre os módulos(@Module) e a injeção (@Inject).

Injeção de dependências no Android passo a passo

Para implementar o Dagger corretamente, precisamos executar 5 passos:

  1. Identificar os quais objetos dependerão de quais outros objetos

  2. Criar uma classe módulo ( com a anotação @Module ) e criar métodos provedores (com a anotação @Provides)

  3. Nas classes dependentes, requisitar a injeção de dependências com a anotação @Inject

  4. Criar interfaces ( ou classes abstratas) com a anotação @Component e adicionar as classes módulos a ela

  5. Instanciar o componente para que ele construa os objetos que iremos usar na aplicação

A analise de dependências do Dagger é feita em tempo de compilação, com isso não há grandes penalidades de desempenho na aplicação e erros de na injeção de dependências podem ser vistos já na compilação.


Preparando o Ambiente


Passo 1: Crie um novo projeto Android

Criando um novo projeto android

Passo2: Configure o SDK mínimo do projeto para API level 10


Configure o SDK mínimo do projeto para API level 10

Passo 3 : Escolha a Activity em branco


para este tutoria não precisaremos criar nenhum layout

Escolha uma Activity em Branco

Configurando O Gradle


Agora precisamos configurar as dependências do Projeto, e para isso iremos modificar os nossos arquivos gradle.


Primeiro alteramos o nosso Gradle do Projeto, ele deve ficar assim


// Top-level build file where you can add configuration options common to all sub-projects/modules.

buildscript {
    repositories {
        jcenter()
    }
    dependencies {
        classpath 'com.android.tools.build:gradle:1.5.0'
        classpath 'com.neenbedankt.gradle.plugins:android-apt:1.4'
        // NOTE: Do not place your application dependencies here; they belong
        // in the individual module build.gradle files
    }
}

allprojects {
    repositories {
        //jcenter()
        mavenCentral()
        maven{
            url 'https://oss.sonatype.org/content/repositories/snapshots/'
        }
    }
}

task clean(type: Delete) {
    delete rootProject.buildDir
}

Primeiro adicionamos a dependência

classpath 'com.neenbedankt.gradle.plugins:android-apt:1.4'

depois trocamos o canal de software jCentral por MavenCentral

repositories {
        //jcenter()
        mavenCentral()
        maven{
            url 'https://oss.sonatype.org/content/repositories/snapshots/'
        }

Agora iremos alterar o build.gradle do nosso módulo app.

Adicione

apply plugin:'com.neenbedankt.android-apt'

logo abaixa da primeira linha do arquivo

apply plugin: 'com.android.application'

E adicione nas dependencias do modulo app

compile 'com.google.dagger:dagger:2.0.2'
apt 'com.google.dagger:dagger-compiler:2.0.2'
provided 'org.glassfish:javax.annotation:10.0+'

Com isso já podemos compilar o nosso projeto com todas as suas dependências.


Implementando o Dagger


Passo 1: Identificar objetos e suas dependências


Para este tutorial teremos duas classes, Usuário que represente um usuário do nosso aplicativo e Perfil, que representa o seu perfil de usuário.


Diagrama de Classes

A nossa classe de usuário será a seguinte

class Usuario {
		
	public Perfil perfil;	

	public Usuario(Perfil perfil){
	     this.perfil = perfil;
	}

}

E nossa classe perfil

class Perfil{
  String nome;

  public String getNome(){
       return this.nome;
  }
}

class UsuarioFree extends Perfil{
     public UsuarioFree(){
         this.nome ="Usuário Free";
     }
}

class UsuarioPremium extends Perfil{
     public UsuarioFree(){
         this.nome ="Usuário Premium";
     }
}

Essas classes são simples e não contem nenhuma lógica de negócio, mas servirão para ilustrar nosso exemplo.


Passo 2 : Criar nossa classe de Módulo


Classes anotadas com @Module, devem conter métodos anotados com @Provides, esses métodos é que serão chamados na hora que as dependências forem injetadas.


import javax.inject.Singleton;
 
import dagger.Module;
import dagger.Provides;
 
/**
 * Created by kerry on 14/02/15.
 */
 
@Module
public class UsuarioModule {
 
    @Provides @Singleton
    Perfil providePerfil(){
        return new PerfilPremium();
    }
 
    @Provides @Singleton
    Usuario provideUsuario(){
        return new Usuario(new PerfilPremium());
    }
}

Aqui criamos dois métodos, o primeiro provê um Objeto Perfil, que é independente, e o outro provê um objeto Usuário que possui como dependência um Perfil.

A anotação @Singleton indica que em toda aplicação existirá apenas um instância do objeto. Isto é sempre que precisarmos de um objeto usuário, será retorna a mesma instância.


Passo 3 : Requisitando a injeção de dependências dentro do Objeto Dependente


Agora nossa classe módulo possui métodos provedores para as nossas diferentes classes. Nossa classe usuário necessita de um Perfil, então precisamos indicar isso usando a anotação @Inject no nosso construtor (poderíamos criar um método setPerfil, ou deixar o atributo perfil como público e anotá-lo).


@Inject
public Usuario(Perfil perfil){
    this.perfil = perfil;
}


Passo 4: Conecctar os Módulos com os Injetores


A conexão entre os Módulos (@Module) provedores e as classes que estão requisitando objetos (@Inject) se dá através dos componentes (@Component), que deve ser uma interface ou classe abstrata.

import javax.inject.Singleton;
 
import dagger.Component;
 
@Singleton
@Component(modules = {UsuarioModule.class})
public interface UsuarioComponent {
 
    Usuario provideUsuario();
 
}


Ao fazer a anotação @Component, você deve especificar quais módulos estarão disponíveis naquele componente(Separar módulos com ‘,’).


Com esta interface, o Dagger irá implementar os métodos abstratos e adicionar alguns métodos mais, que serão úteis ao nosso desenvolvimento.


Passo 5: Utilizar a interface anotada com @Component para obter os objetos


Agora que está tudo configurado e conectado podemos obter uma instancia dessa interface e invocar seus métodos para obter nossos objetos, através dos provedores.

Para isso irei implementar as chamadas no método OnCreate da nossa MainActivity.


package net.ramonsilva.tutorial.dagger;
 
import android.support.v7.app.ActionBarActivity;
import android.os.Bundle;
import android.widget.Toast;
 
import net.ramonsilva.tutorial.component.DaggerUsuarioComponent;
import net.ramonsilva.tutorial.component.UsuarioComponent;
import net.ramonsilva.tutorial.model.Usuario;
import net.ramonsilva.tutorial.module.UsuarioModule;
 
public class MainActivity extends ActionBarActivity {
 
    Usuario usuario;
 
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
 
        UsuarioComponent component = DaggerUsuarioComponent.builder().usuarioModule(new UsuarioModule()).build();
 
        usuario = component.provideUsuario();
 
        Toast.makeText(this, String.valueOf(usuario.getNome()), Toast.LENGTH_SHORT).show();
    }
}

Quando queremo criar uma instancia da interface anotada com @Component, você deve chamar o método build do classe Gerada pelo Dagger, essa classe terá o nome Dagger<Nome_do_Component>.


A partir desta instancia podemos chamar os métodos provedores de objetos, e receberemos nossas instancias de objetos já com todas as dependências injetadas.


usuario = component.provideUsuario();

Conclusão


A injeção de dependências é um padrão que deve-se usar desde de cedo no seu projeto, porém se for necessário aplicá-lo mais tarde no projeto, será necessário algumas refatorações, porém todo esse trabalho será recompensado com um código mais limpo e fácil de manter e testar.


Usando a biblioteca Dagger, o seu trabalho se tornará muito mais fácil.

#Framework #dagger #programação #CódigoLimpo #patterns #Refatoração #BoasPráticas #Android

3 visualizações