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.
@Module, classe que irá prover as dependências
@Provides, para os métodos provedores da classe de módulos
@Inject, para requisitar um dependência (use no construtor, atributos públicos ou métodos set)
@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:
Identificar os quais objetos dependerão de quais outros objetos
Criar uma classe módulo ( com a anotação @Module ) e criar métodos provedores (com a anotação @Provides)
Nas classes dependentes, requisitar a injeção de dependências com a anotação @Inject
Criar interfaces ( ou classes abstratas) com a anotação @Component e adicionar as classes módulos a ela
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
Passo2: 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
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.
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.
Comentários