107
Dagger 2 Injeção de Dependência no Android

Dagger 2: DI eficiente em Android - TDC 2015

Embed Size (px)

Citation preview

Page 1: Dagger 2: DI eficiente em Android - TDC 2015

Dagger 2Injeção de Dependência no Android

Page 2: Dagger 2: DI eficiente em Android - TDC 2015

rafaeltoledo.net

@_rafaeltoledo

Desenv. Android @ Concrete Solutions

Page 3: Dagger 2: DI eficiente em Android - TDC 2015

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

Page 4: Dagger 2: DI eficiente em Android - TDC 2015

“Injeção de Dependência (ou Dependency Injection, em inglês) é um padrão de desenvolvimento de programas de

computadores utilizado quando é necessário manter baixo o nível de acoplamento entre

diferentes módulos de um sistema. (...)”

Page 5: Dagger 2: DI eficiente em Android - TDC 2015

“Nesta solução as dependências entre os módulos não são definidas

programaticamente, mas sim pela configuração de uma infraestrutura de

software (container) que é responsável por "injetar" em cada componente suas

dependências declaradas. A Injeção de dependência se relaciona com o padrão Inversão de controle mas não pode ser

considerada um sinônimo deste.”

Wikipedia, 2015

Page 6: Dagger 2: DI eficiente em Android - TDC 2015

?????????

Page 7: Dagger 2: DI eficiente em Android - TDC 2015

Diz respeito a separação de onde os objetos são criados e onde são utilizados

Page 8: Dagger 2: DI eficiente em Android - TDC 2015

Em vez de criar, você pede

Page 9: Dagger 2: DI eficiente em Android - TDC 2015

class UserController {

void doLogic() {

try {

User user = RetrofitApi.getInstance().getUser(1);

new UserDaoImpl().save(user);

Logger.getForClass(UserController.class).log("Success");

} catch (IOException e) {

Logger.getForClass(UserController.class).logException(e);

}

}

}

Page 10: Dagger 2: DI eficiente em Android - TDC 2015

class UserController {

UserDaoImpl dao;

Logger logger;

UserApi api;

void doLogic() {

try {

api = RetrofitApi.getInstance();

User user = api.getUser(1);

dao = new UserDaoImpl();

dao.save(user);

logger = Logger.getForClass(UserController.class);

logger.log("Success");

} catch (IOException e) {

logger = Logger.getForClass(UserController.class);

logger.logException(e);

}

}

}

Page 11: Dagger 2: DI eficiente em Android - TDC 2015

class UserController {

UserDao dao; // Interface!

Logger logger;

Api api;

void doLogic() {

try {

if (api == null) api = RetrofitApi.getInstance();

User user = api.getUser(1);

if (dao == null) dao = new UserDaoImpl();

dao.save(user);

if (logger == null) logger = Logger.getForClass(UserController.class);

logger.log("Success");

} catch (IOException e) {

if (logger == null) logger = Logger.getForClass(UserController.class);

logger.logException(e);

}

}

}

Page 12: Dagger 2: DI eficiente em Android - TDC 2015

class UserController {

UserDao dao = new UserDaoImpl();

Logger logger = Logger.getForClass(UserController.class);

Api api = RetrofitApi.getInstance();

void doLogic() {

try {

User user = api.getUser(1);

dao.save(user);

logger.log("Success");

} catch (IOException e) {

logger.logException(e);

}

}

}

Page 13: Dagger 2: DI eficiente em Android - TDC 2015

class UserController {

UserDao dao;

Logger logger;

Api api;

public UserController() {

dao = new UserDaoImpl();

api = RetrofitApi.getInstance();

logger = Logger.getForClass(UserController.class);

}

void doLogic() {

try {

User user = api.getUser(1);

dao.save(user);

logger.log("Success");

} catch (IOException e) { logger.logException(e); }

}

}

Page 14: Dagger 2: DI eficiente em Android - TDC 2015

class UserController {

UserDao dao;

Logger logger;

Api api;

public UserController() {

dao = new UserDaoImpl();

api = RetrofitApi.getInstance();

logger = Logger.getForClass(UserController.class);

}

void doLogic() {

try {

User user = api.getUser(1);

dao.save(user);

logger.log("Success");

} catch (IOException e) { logger.logException(e); }

}

}

Page 15: Dagger 2: DI eficiente em Android - TDC 2015

class UserController {

UserDao dao;

Logger logger;

Api api;

public UserController() {

dao = new UserDaoImpl();

api = RetrofitApi.getInstance();

logger = Logger.getForClass(UserController.class);

}

void doLogic() {

try {

User user = api.getUser(1);

dao.save(user);

logger.log("Success");

} catch (IOException e) { logger.logException(e); }

}

}

Page 16: Dagger 2: DI eficiente em Android - TDC 2015

class UserController {

UserDao dao;

Logger logger;

Api api;

public UserController() {

dao = new UserDaoImpl();

api = RetrofitApi.getInstance();

logger = Logger.getForClass(UserController.class);

}

void doLogic() {

try {

User user = api.getUser(1);

dao.save(user);

logger.log("Success");

} catch (IOException e) { logger.logException(e); }

}

}

Page 17: Dagger 2: DI eficiente em Android - TDC 2015

UserDao

UserController

Page 18: Dagger 2: DI eficiente em Android - TDC 2015

UserDao

UserController

SessionManager

Page 19: Dagger 2: DI eficiente em Android - TDC 2015

UserDao

UserController

SessionManagerSignInController

Page 20: Dagger 2: DI eficiente em Android - TDC 2015

UserDao

UserController

SessionManagerSignInController

CookieJob

JobManager

JobController

PermissionChecker

ReminderJob

RoleController

CandyShopper

FruitJuicerJob

UnknownController

Page 21: Dagger 2: DI eficiente em Android - TDC 2015

UserDao

UserController

SessionManagerSignInController

CookieJob

JobManager

JobController

PermissionChecker

ReminderJob

RoleController

CandyShopper

FruitJuicerJob

UnknownController

EM TODO LUGAR!

Page 22: Dagger 2: DI eficiente em Android - TDC 2015

class UserDaoImpl implements UserDao {

public UserDaoImpl() {

//...

}

}

Page 23: Dagger 2: DI eficiente em Android - TDC 2015

class UserDaoImpl implements UserDao {

public UserDaoImpl(Context context) {

//...

}

}

Page 24: Dagger 2: DI eficiente em Android - TDC 2015
Page 25: Dagger 2: DI eficiente em Android - TDC 2015

Alteração em todas as classes!

Page 26: Dagger 2: DI eficiente em Android - TDC 2015

Alteração em todas as classes!

Muito retrabalho!

Page 27: Dagger 2: DI eficiente em Android - TDC 2015

Alteração em todas as classes!

Muito retrabalho!

Page 28: Dagger 2: DI eficiente em Android - TDC 2015

Alteração em todas as classes!

Muito retrabalho!

Page 29: Dagger 2: DI eficiente em Android - TDC 2015

class UserController {

UserDao dao;

Logger logger;

Api api;

public UserController() {

dao = new UserDaoImpl();

api = RetrofitApi.getInstance();

logger = Logger.getForClass(UserController.class);

}

void doLogic() {

try {

User user = api.getUser(1);

dao.save(user);

logger.log("Success");

} catch (IOException e) { logger.logException(e); }

}

}

Page 30: Dagger 2: DI eficiente em Android - TDC 2015

class UserController {

UserDao dao;

Logger logger;

Api api;

public UserController() {

dao = new UserDaoImpl();

api = RetrofitApi.getInstance();

logger = Logger.getForClass(UserController.class);

}

void doLogic() {

try {

User user = api.getUser(1);

dao.save(user);

logger.log("Success");

} catch (IOException e) { logger.logException(e); }

}

}

Page 31: Dagger 2: DI eficiente em Android - TDC 2015

class UserController {

UserDao dao;

Logger logger;

Api api;

public UserController(UserDao dao, Api api, Logger logger) {

this.dao = dao;

this.api = api;

this.logger = logger;

}

void doLogic() {

try {

User user = api.getUser(1);

dao.save(user);

logger.log("Success");

} catch (IOException e) { logger.logException(e); }

}

}

Page 32: Dagger 2: DI eficiente em Android - TDC 2015

DI: Separação do uso e criação de objetos

Page 33: Dagger 2: DI eficiente em Android - TDC 2015

DI: Separação do uso e criação de objetos

não há a necessidade de bibliotecasou frameworks!

Page 34: Dagger 2: DI eficiente em Android - TDC 2015

Desvantagem: muito boilerplate

Page 35: Dagger 2: DI eficiente em Android - TDC 2015

Spring, Guice, Dagger 1 & cia

#oldbutgold

Page 36: Dagger 2: DI eficiente em Android - TDC 2015

Spring, Guice, Dagger 1 & cia

#oldbutnot

Page 37: Dagger 2: DI eficiente em Android - TDC 2015

Dagger 2

Page 38: Dagger 2: DI eficiente em Android - TDC 2015

Dagger 2?

Page 39: Dagger 2: DI eficiente em Android - TDC 2015

Dagger 2

● Fork do Dagger, da Square, feito pela Google

● Elimina todo o uso de reflections

● Construída sobre as anotações javax.inject da especificação JSR-330

Page 40: Dagger 2: DI eficiente em Android - TDC 2015

Dagger 2

● Validação de todo o grafo de dependências em tempo de compilação

● Menos flexível, se comparado ao Dagger 1 - ex.: não possui module overriding

● Proguard configuration-free

Page 41: Dagger 2: DI eficiente em Android - TDC 2015

Dagger 2

● API enxuta!

● Código gerado é debugger-friendly

● Muito performático

● google.github.io/dagger

Page 42: Dagger 2: DI eficiente em Android - TDC 2015

public @interface Component {

Class<?>[] modules() default {};

Class<?>[] dependencies() default {};

}

public @interface Subcomponent {

Class<?>[] includes() default {};

}

public @interface Module {

Class<?>[] includes() default {};

}

public @interface Provides {

}

public @interface MapKey {

boolean unwrapValue() default true;

}

public interface Lazy<T> {

T get();

}

Page 43: Dagger 2: DI eficiente em Android - TDC 2015

// JSR-330

public @interface Inject {

}

public @interface Scope {

}

public @interface Qualifier {

}

Page 44: Dagger 2: DI eficiente em Android - TDC 2015

Como integro no meu projeto?

Page 45: Dagger 2: DI eficiente em Android - TDC 2015

// build.gradle

buildscript {

repositories {

jcenter()

}

dependencies {

classpath 'com.android.tools.build:gradle:1.2.3'

}

}

allprojects {

repositories {

jcenter()

}

}

Page 46: Dagger 2: DI eficiente em Android - TDC 2015

// build.gradle

buildscript {

repositories {

jcenter()

}

dependencies {

classpath 'com.android.tools.build:gradle:1.2.3'

}

}

allprojects {

repositories {

jcenter()

}

}

Page 47: Dagger 2: DI eficiente em Android - TDC 2015

// build.gradle

buildscript {

repositories {

jcenter()

}

dependencies {

classpath 'com.android.tools.build:gradle:1.2.3'

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

}

}

allprojects {

repositories {

jcenter()

}

}

Page 48: Dagger 2: DI eficiente em Android - TDC 2015

// build.gradle

buildscript {

repositories {

jcenter()

}

dependencies {

classpath 'com.android.tools.build:gradle:1.2.3'

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

}

}

allprojects {

repositories {

jcenter()

}

}

Page 49: Dagger 2: DI eficiente em Android - TDC 2015

apply plugin: 'com.android.application'

android {

compileSdkVersion 22

buildToolsVersion '22.0.1'

defaultConfig {

applicationId 'net.rafaeltoledo.tdc2015'

minSdkVersion 15

targetSdkVersion 22

versionCode 1

versionName '1.0'

}

}

dependencies {

compile 'com.android.support:appcompat-v7:22.2.1'

}

Page 50: Dagger 2: DI eficiente em Android - TDC 2015

apply plugin: 'com.android.application'

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

android {

compileSdkVersion 22

buildToolsVersion '22.0.1'

defaultConfig {

applicationId 'net.rafaeltoledo.tdc2015'

minSdkVersion 15

targetSdkVersion 22

versionCode 1

versionName '1.0'

}

}

dependencies {

compile 'com.android.support:appcompat-v7:22.2.1'

compile 'com.google.dagger:dagger:2.0.1'

apt 'com.google.dagger:dagger-compiler:2.0.1'

provided 'org.glassfish:javax.annotation:10.0-b28'

}

Page 51: Dagger 2: DI eficiente em Android - TDC 2015

apply plugin: 'com.android.application'

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

android {

compileSdkVersion 22

buildToolsVersion '22.0.1'

defaultConfig {

applicationId 'net.rafaeltoledo.tdc2015'

minSdkVersion 15

targetSdkVersion 22

versionCode 1

versionName '1.0'

}

}

dependencies {

compile 'com.android.support:appcompat-v7:22.2.1'

compile 'com.google.dagger:dagger:2.0.1'

apt 'com.google.dagger:dagger-compiler:2.0.1'

provided 'org.glassfish:javax.annotation:10.0-b28' // JSR-330

}

Page 52: Dagger 2: DI eficiente em Android - TDC 2015

E pronto!

Page 53: Dagger 2: DI eficiente em Android - TDC 2015

Vamos começar?

Page 54: Dagger 2: DI eficiente em Android - TDC 2015

@Inject

@Component @Module

@Provides

Dagger 2

Page 55: Dagger 2: DI eficiente em Android - TDC 2015

@Inject

● Parte da JSR-330

● Marca quais dependências devem ser fornecidas pelo Dagger

● Pode aparecer de 3 formas no código

Page 56: Dagger 2: DI eficiente em Android - TDC 2015

public class TdcActivityPresenter {

private TdcActivity activity;

private TdcDataStore dataStore;

@Inject

public TdcActivityPresenter(TdcActivity activity,

TdcDataStore dataStore) {

this.activity = activity;

this.dataStore = dataStore;

}

}

1. No Construtor

Page 57: Dagger 2: DI eficiente em Android - TDC 2015

1. No Construtor

● Todas as dependências vem do grafo de dependências do Dagger

● Anotar uma classe dessa forma faz com que ela também faça parte do grafo de dependências (podendo ser injetada em outras classes)

Page 58: Dagger 2: DI eficiente em Android - TDC 2015

1. No Construtor

● Limitação: não podemos anotar mais que um construtor com a anotação @Inject

Page 59: Dagger 2: DI eficiente em Android - TDC 2015

public class TdcActivity extends AppCompatActivity {

@Inject TdcActivityPresenter presenter;

@Inject SharedPreferences preferences;

@Override

protected void onCreate(Bundle bundle) {

super.onCreate(bundle);

getComponent().inject(this);

}

}

2. Nos Atributos da Classe

Page 60: Dagger 2: DI eficiente em Android - TDC 2015

2. Nos Atributos da Classe

● A injeção nesse caso deve ser manual, caso contrários os atributos serão todos nulos

@Override

protected void onCreate(Bundle bundle) {

super.onCreate(bundle);

getComponent().inject(this);

}

● Limitação: os atributos não podem ser privados!

Page 61: Dagger 2: DI eficiente em Android - TDC 2015

public class TdcActivityPresenter {

private TdcActivity activity;

@Inject

public TdcActivityPresenter(TdcActivity activity) {

this.activity = activity;

}

@Inject

public void enableAnalytics(AnalyticsManager analytics) {

analytics.track(this);

}

}

3. Em métodos públicos

Page 62: Dagger 2: DI eficiente em Android - TDC 2015

3. Em métodos públicos

● Utilizado em conjunto com a anotação no construtor da classe

● Para casos onde o objeto injetado necessitamos da instância da própria classe na dependência fornecida

@Inject

public void enableAnalytics(AnalyticsManager analytics) {

analytics.track(this);

}

Page 63: Dagger 2: DI eficiente em Android - TDC 2015

3. Em métodos públicos

● O método anotado é chamado automaticamente logo após o construtor

Page 64: Dagger 2: DI eficiente em Android - TDC 2015

@Module

● Parte da API do Dagger

● Utilizada para identificar classes que fornecem dependências

Page 65: Dagger 2: DI eficiente em Android - TDC 2015

@Module

public class DataModule {

@Provides @Singleton

public OkHttpClient provideOkHttpClient() {

OkHttpClient okHttpClient = new OkHttpClient();

okHttpClient.setConnectionTimeout(10, TimeUnit.SECONDS);

okHttpClient.setReadTimeout(10, TimeUnit.SECONDS);

okHttpClient.setWriteTimeout(10, TimeUnit.SECONDS);

return okHttpClient;

}

@Provides @Singleton

public RestAdapter provideRestAdapter(OkHttpClient client) {

return new RestAdapter.Builder()

.setClient(new OkClient(okHttpClient))

.setEndpoint("https://api.github.com")

.build();

}

}

Page 66: Dagger 2: DI eficiente em Android - TDC 2015

@Module

public class DataModule {

@Provides @Singleton

public OkHttpClient provideOkHttpClient() {

OkHttpClient okHttpClient = new OkHttpClient();

okHttpClient.setConnectionTimeout(10, TimeUnit.SECONDS);

okHttpClient.setReadTimeout(10, TimeUnit.SECONDS);

okHttpClient.setWriteTimeout(10, TimeUnit.SECONDS);

return okHttpClient;

}

@Provides @Singleton

public RestAdapter provideRestAdapter(OkHttpClient client) {

return new RestAdapter.Builder()

.setClient(new OkClient(okHttpClient))

.setEndpoint("https://api.github.com")

.build();

}

}

Page 67: Dagger 2: DI eficiente em Android - TDC 2015

@Provide

● Utilizada nas classes anotadas como @Module para identificar quais métodos retornam dependências

Page 68: Dagger 2: DI eficiente em Android - TDC 2015

@Module

public class DataModule {

@Provides @Singleton

public OkHttpClient provideOkHttpClient() {

OkHttpClient okHttpClient = new OkHttpClient();

okHttpClient.setConnectionTimeout(10, TimeUnit.SECONDS);

okHttpClient.setReadTimeout(10, TimeUnit.SECONDS);

okHttpClient.setWriteTimeout(10, TimeUnit.SECONDS);

return okHttpClient;

}

@Provides @Singleton

public RestAdapter provideRestAdapter(OkHttpClient client) {

return new RestAdapter.Builder()

.setClient(new OkClient(okHttpClient))

.setEndpoint("https://api.github.com")

.build();

}

}

Page 69: Dagger 2: DI eficiente em Android - TDC 2015

@Module

public class DataModule {

@Provides @Singleton

public OkHttpClient provideOkHttpClient() {

OkHttpClient okHttpClient = new OkHttpClient();

okHttpClient.setConnectionTimeout(10, TimeUnit.SECONDS);

okHttpClient.setReadTimeout(10, TimeUnit.SECONDS);

okHttpClient.setWriteTimeout(10, TimeUnit.SECONDS);

return okHttpClient;

}

@Provides @Singleton

public RestAdapter provideRestAdapter(OkHttpClient client) {

return new RestAdapter.Builder()

.setClient(new OkClient(okHttpClient))

.setEndpoint("https://api.github.com")

.build();

}

}

Page 70: Dagger 2: DI eficiente em Android - TDC 2015

@Component

● É a anotação que liga os @Modules aos @Injects

● É colocada em uma interface

● Define quais módulos possui, quem será injetado

Page 71: Dagger 2: DI eficiente em Android - TDC 2015

@Component

● Precisa especificar obrigatoriamente seu escopo (ciclo de vida de suas dependências)

● Pode publicar dependências

● Pode possuir outros componentes

Page 72: Dagger 2: DI eficiente em Android - TDC 2015

@Singleton

@Component(

modules = {

DataModule.class,

UiModule.class

}

)

public interface TdcAppComponent {

void inject(TdcApplication app);

MainActivity inject(MainActivity activity);

Application getApplication();

AnalyticsManager getAnalyticsManager();

}

Page 73: Dagger 2: DI eficiente em Android - TDC 2015

@Singleton // Escopo

@Component(

modules = {

DataModule.class,

UiModule.class

}

)

public interface TdcAppComponent {

void inject(TdcApplication app);

MainActivity inject(MainActivity activity);

Application getApplication();

AnalyticsManager getAnalyticsManager();

}

Page 74: Dagger 2: DI eficiente em Android - TDC 2015

@Singleton

@Component(

modules = {

DataModule.class,

UiModule.class

}

)

public interface TdcAppComponent {

void inject(TdcApplication app);

MainActivity inject(MainActivity activity);

Application getApplication();

AnalyticsManager getAnalyticsManager();

}

Page 75: Dagger 2: DI eficiente em Android - TDC 2015

@Singleton

@Component(

modules = {

DataModule.class,

UiModule.class

}

)

public interface TdcAppComponent {

void inject(TdcApplication app);

MainActivity inject(MainActivity activity); // Caso queira encadear

Application getApplication();

AnalyticsManager getAnalyticsManager();

}

Page 76: Dagger 2: DI eficiente em Android - TDC 2015

@Singleton

@Component(

modules = {

DataModule.class,

UiModule.class

}

)

public interface TdcAppComponent {

void inject(TdcApplication app);

MainActivity inject(MainActivity activity);

Application getApplication();

AnalyticsManager getAnalyticsManager(); // Dependências visíveis

} // para outros componentes*

Page 77: Dagger 2: DI eficiente em Android - TDC 2015

@Singleton

@Component(

modules = {

DataModule.class,

UiModule.class

}

)

public interface TdcAppComponent {

void inject(TdcApplication app);

MainActivity inject(MainActivity activity);

Application getApplication();

AnalyticsManager getAnalyticsManager();

}

Page 78: Dagger 2: DI eficiente em Android - TDC 2015

@ActivityScope // Escopo personalizado

@Component(

modules = TdcActivityModule.class,

dependencies = TdcComponent.class

)

public interface TdcActivityComponent {

TdcActivity inject(TdcActivity activity);

TdcActivityPresenter presenter();

}

Page 79: Dagger 2: DI eficiente em Android - TDC 2015

@Generated("dagger.internal.codegen.ComponentProcessor")

public final class DaggerMainComponent implements MainComponent {

private Provider<ApiService> provideApiServiceProvider;

private MembersInjector<MainActivity> mainActivityMembersInjector;

private DaggerMainComponent(Builder builder) {

assert builder != null;

initialize(builder);

}

public static Builder builder() {

return new Builder();

}

public static MainComponent create() {

return builder().build();

}

private void initialize(final Builder builder) {

this.provideApiServiceProvider =

ScopedProvider.create(MainModule_ProvideApiServiceFactory.create(builder.mainModule));

this.mainActivityMembersInjector = MainActivity_MembersInjector.create(

(MembersInjector) MembersInjectors.noOp(), provideApiServiceProvider);

}

@Override

public void inject(MainActivity activity) {

mainActivityMembersInjector.injectMembers(activity);

}

}

Page 80: Dagger 2: DI eficiente em Android - TDC 2015

class UserController {

UserDao dao;

Logger logger;

Api api;

public UserController() {

dao = new UserDaoImpl();

api = RetrofitApi.getInstance();

logger = Logger.getForClass(UserController.class);

}

void doLogic() {

try {

User user = api.getUser(1);

dao.save(user);

logger.log("Success");

} catch (IOException e) { logger.logException(e); }

}

}

Page 81: Dagger 2: DI eficiente em Android - TDC 2015

public class TdcApp extends Application {

TdcAppComponent component;

@Override

public void onCreate() {

component = DaggerTdcAppComponent.create();

component = DaggerTdcAppComponent.builder()

.dataModule(new DataModule(this)) // Módulo com construtor

.build(); // parametrizado

}

}

Instanciando um Componente

Page 82: Dagger 2: DI eficiente em Android - TDC 2015

Dagger 2Escopos dinâmicos

Page 83: Dagger 2: DI eficiente em Android - TDC 2015

Escopo = ciclo de vida do grafo de dependências (componente)

Page 84: Dagger 2: DI eficiente em Android - TDC 2015

@Singleton

@Component(

modules = {

DataModule.class,

UiModule.class

}

)

public interface TdcAppComponent {

void inject(TdcApplication app);

MainActivity inject(MainActivity activity);

Application getApplication();

AnalyticsManager getAnalyticsManager();

}

Page 85: Dagger 2: DI eficiente em Android - TDC 2015

@ActivityScope // Escopo personalizado

@Component(

modules = TdcActivityModule.class,

dependencies = TdcComponent.class

)

public interface TdcActivityComponent {

TdcActivity inject(TdcActivity activity);

TdcActivityPresenter presenter();

}

Page 86: Dagger 2: DI eficiente em Android - TDC 2015

@Scope

@Retention(RetentionPolicy.RUNTIME)

public @interface UserScope {

}

Definição de um escopo

Page 87: Dagger 2: DI eficiente em Android - TDC 2015

Exemplo de uso

Miroslaw Stanek frogermcs.github.io

Page 88: Dagger 2: DI eficiente em Android - TDC 2015

@Singleton

@Component(modules = DataModule.class)

public interface TdcAppComponent {

UserComponent plus(UserModule module);

// não é necessário expor as dependências

}

Implementação

Page 89: Dagger 2: DI eficiente em Android - TDC 2015

@UserScope

@Subcomponent(modules = UserModule.class)

public interface UserComponent {

UserActivityComponent plus(UserActivityModule module);

}

Implementação

Page 90: Dagger 2: DI eficiente em Android - TDC 2015

public class TdcApp extends Application {

TdcAppComponent component;

UserComponent userComponent;

public UserComponent createUserComponent(User user) {

userComponent = component.plus(new UserModule(user));

return userComponent;

}

public void releaseUserComponent() {

userComponent = null;

}

...

}

Implementação

Page 91: Dagger 2: DI eficiente em Android - TDC 2015

Dagger 2Outras coisas legais!

Page 92: Dagger 2: DI eficiente em Android - TDC 2015

@Inject

Lazy<SharedPreferences> prefs;

void salvar() {

prefs.get().edit().putString("status", "ok!").apply();

}

Dependências “Preguiçosas”

Page 93: Dagger 2: DI eficiente em Android - TDC 2015

// No módulo

@Provides @Singleton

@ApiUrl String provideApiUrl(Context context) {

return context.getString(R.string.api_url);

}

@Provides @Singleton

@AccessToken String provideRestAdapter(SharedPreferences prefs) {

return prefs.getString("token", null);

}

// Na classe a ser injetada

@Inject @AccessToken

String accessToken;

Qualificadores

Page 94: Dagger 2: DI eficiente em Android - TDC 2015

// Declarando sua anotação

@MapKey(unwrapValue = true)

@interface GroupKey {

String value();

}

@MapKey

Page 95: Dagger 2: DI eficiente em Android - TDC 2015

// Fornecendo dependências no módulo

@Provides(type = Type.MAP)

@GroupKey("um")

String provideFirstValue() {

return "primeiro valor";

}

@Provides(type = Type.MAP)

@GroupKey("dois")

String provideSecondValue() {

return "segundo valor";

}

@MapKey

Page 96: Dagger 2: DI eficiente em Android - TDC 2015

// Uso

@Inject

Map<String, String> map; // {um=primeiro valor, dois=segundo valor}

● Por enquanto, só aceita Map e Set, e valores do tipo String e Enumeradores

@MapKey

Page 97: Dagger 2: DI eficiente em Android - TDC 2015

Ok! Tudo muito bonito mas...

Page 98: Dagger 2: DI eficiente em Android - TDC 2015

O que eu ganho de fato com tudo isso?

Page 99: Dagger 2: DI eficiente em Android - TDC 2015

Grandes benefícios

● Código mais limpo e organizado

● Melhorias no gerenciamento de objetos (melhor controle de singletons)

● Código mais fácil de TESTAR

Page 100: Dagger 2: DI eficiente em Android - TDC 2015

Dagger 2 e Testes

● Programar orientado a interfaces - mocks

● Sobrescrita de Componentes e Módulos

Page 101: Dagger 2: DI eficiente em Android - TDC 2015

Dagger 2 e Testes

@Module

public class TestMainModule {

@Provides // Poderíamos fazer com o Retrofit Mock!

public ApiService provideApiService() {

return new ApiService() {

@Override

public List<Repo> listRepos() {

return Arrays.asList(

new Repo("my-test-repo"),

new Repo("another-test-repo")

);

}

};

}

}

Page 102: Dagger 2: DI eficiente em Android - TDC 2015

Dagger 2 e Testes

@Component(modules = DebugMainModule.class)

public interface TestMainComponent extends MainComponent {

}

Page 103: Dagger 2: DI eficiente em Android - TDC 2015

Dagger 2 e Espresso 2

@RunWith(AndroidJUnit4.class)

public class MainActivityTest {

// ...

@Before

public void setUp() {

Instrumentation instrumentation =

InstrumentationRegistry.getInstrumentation();

MainApplication app = (MainApplication)

instrumentation.getTargetContext().getApplicationContext();

app.setComponent(DaggerDebugMainComponent.create());

rule.launchActivity(new Intent());

}

}

Page 104: Dagger 2: DI eficiente em Android - TDC 2015

Dagger 2 e Robolectric 3

@RunWith(RobolectricGradleTestRunner.class)

@Config(sdk = 21, constants = BuildConfig.class)

public class MainActivityTest {

// ...

@Before

public void setUp() {

MainComponent component = DaggerDebugMainComponent.create();

MainApplication app =

((MainApplication) RuntimeEnvironment.application)

.setComponent(component);

}

}

Page 105: Dagger 2: DI eficiente em Android - TDC 2015

Dagger 2github.com/rafaeltoledo/dagger2-tdc2015

Page 106: Dagger 2: DI eficiente em Android - TDC 2015

Para saber mais

● Site oficial - google.github.io/dagger

● Dagger 2 - A New Type of Dependency Injection (Gregory Kick) - vai.la/fdwt

● The Future of Dependency Injection with Dagger 2 (Jake Wharton) - vai.la/fdwy

● froger_mcs Dev Blog - frogermcs.github.io

Page 107: Dagger 2: DI eficiente em Android - TDC 2015

OBRIGADO!

rafaeltoledo.net

@_rafaeltoledo

Desenv. Android @ Concrete Solutionsestamos contratando!

concretesolutions.com.br/carreira