SlideShare uma empresa Scribd logo
Better Faster
Stronger Dagger
Rafael Toledo
@_rafaeltoledo
Android Developer @ Concrete Solutions
www.rafaeltoledo.net
O que é Injeção de
Dependência?
@_rafaeltoledo
“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. (...)”
@_rafaeltoledo
“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
@_rafaeltoledo
?????????
@_rafaeltoledo
Diz respeito a separação de onde os
objetos são criados e onde são utilizados
@_rafaeltoledo
Em vez de criar, você pede
@_rafaeltoledo
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);
}
}
}
@_rafaeltoledo
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);
}
}
} @_rafaeltoledo
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);
}
}
} @_rafaeltoledo
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);
}
}
}
@_rafaeltoledo
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); }
}
} @_rafaeltoledo
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); }
}
} @_rafaeltoledo
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); }
}
} @_rafaeltoledo
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); }
}
} @_rafaeltoledo
UserDao
UserController
@_rafaeltoledo
UserDao
UserController
SessionManager
@_rafaeltoledo
UserDao
UserController
SessionManager
SignInController
@_rafaeltoledo
UserDao
UserController
SessionManager
SignInController
CookieJob
JobManager
JobController
PermissionChecker
ReminderJob
RoleController
CandyShopper
FruitJuicerJob
UnknownController
@_rafaeltoledo
UserDao
UserController
SessionManager
SignInController
CookieJob
JobManager
JobController
PermissionChecker
ReminderJob
RoleController
CandyShopper
FruitJuicerJob
UnknownController
EM
TODO
LUGAR!
@_rafaeltoledo
class UserDaoImpl implements UserDao {
public UserDaoImpl() {
//...
}
}
@_rafaeltoledo
class UserDaoImpl implements UserDao {
public UserDaoImpl(Context context) {
//...
}
}
@_rafaeltoledo
@_rafaeltoledo
Alteração em todas as classes!
@_rafaeltoledo
Alteração em todas as classes!
Muito retrabalho!
@_rafaeltoledo
Alteração em todas as classes!
Muito retrabalho!
@_rafaeltoledo
Alteração em todas as classes!
Muito retrabalho!
@_rafaeltoledo
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); }
}
} @_rafaeltoledo
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); }
}
} @_rafaeltoledo
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); }
}
} @_rafaeltoledo
DI: Separação do uso e criação de objetos
@_rafaeltoledo
DI: Separação do uso e criação de objetos
não há a necessidade de bibliotecas
ou frameworks!
@_rafaeltoledo
Desvantagem: muito boilerplate
@_rafaeltoledo
Spring, Guice, Dagger 1 & cia
#oldbutgold
@_rafaeltoledo
Spring, Guice, Dagger 1 & cia
#oldbutnot
@_rafaeltoledo
Dagger 2
@_rafaeltoledo
Dagger 2?
@_rafaeltoledo
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
@_rafaeltoledo
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
@_rafaeltoledo
Dagger 2
● API enxuta!
● Código gerado é debugger-friendly
● Muito performático
● google.github.io/dagger
@_rafaeltoledo
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();
}
@_rafaeltoledo
// JSR-330
public @interface Inject {
}
public @interface Scope {
}
public @interface Qualifier {
}
@_rafaeltoledo
Como integro no meu projeto?
@_rafaeltoledo
// build.gradle
buildscript {
repositories {
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:1.3.1'
}
}
allprojects {
repositories {
jcenter()
}
}
@_rafaeltoledo
// build.gradle
buildscript {
repositories {
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:1.3.1'
}
}
allprojects {
repositories {
jcenter()
}
}
@_rafaeltoledo
// build.gradle
buildscript {
repositories {
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:1.3.1'
classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8'
}
}
allprojects {
repositories {
jcenter()
}
}
@_rafaeltoledo
apply plugin: 'com.android.application'
android {
compileSdkVersion 23
buildToolsVersion '23.0.1'
defaultConfig {
applicationId 'net.rafaeltoledo.tdc2015'
minSdkVersion 15
targetSdkVersion 23
versionCode 1
versionName '1.0'
}
}
dependencies {
compile 'com.android.support:appcompat-v7:23.0.1'
}
@_rafaeltoledo
apply plugin: 'com.android.application'
apply plugin: 'com.neenbedankt.android-apt'
android {
compileSdkVersion 23
buildToolsVersion '23.0.1'
defaultConfig {
applicationId 'net.rafaeltoledo.tdc2015'
minSdkVersion 15
targetSdkVersion 23
versionCode 1
versionName '1.0'
}
}
dependencies {
compile 'com.android.support:appcompat-v7:23.0.1'
compile 'com.google.dagger:dagger:2.0.1'
apt 'com.google.dagger:dagger-compiler:2.0.1'
provided 'javax.annotation:javax.annotation-api:1.2'
}
@_rafaeltoledo
apply plugin: 'com.android.application'
apply plugin: 'com.neenbedankt.android-apt'
android {
compileSdkVersion 23
buildToolsVersion '23.0.1'
defaultConfig {
applicationId 'net.rafaeltoledo.tdc2015'
minSdkVersion 15
targetSdkVersion 23
versionCode 1
versionName '1.0'
}
}
dependencies {
compile 'com.android.support:appcompat-v7:23.0.1'
compile 'com.google.dagger:dagger:2.0.1'
apt 'com.google.dagger:dagger-compiler:2.0.1'
provided 'javax.annotation:javax.annotation-api:1.2' // JSR-330
}
@_rafaeltoledo
E pronto!
@_rafaeltoledo
Vamos começar?
@_rafaeltoledo
@Inject
@Component @Module
@Provides
Dagger 2
@_rafaeltoledo
@Inject
● Parte da JSR-330
● Marca quais dependências devem ser
fornecidas pelo Dagger
● Pode aparecer de 3 formas no código
@_rafaeltoledo
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
@_rafaeltoledo
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)
@_rafaeltoledo
1. No Construtor
● Limitação: não podemos anotar mais que
um construtor com a anotação @Inject
@_rafaeltoledo
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
@_rafaeltoledo
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!
@_rafaeltoledo
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
@_rafaeltoledo
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);
}
@_rafaeltoledo
3. Em métodos públicos
● O método anotado é chamado
automaticamente logo após o construtor
@_rafaeltoledo
@Module
● Parte da API do Dagger
● Utilizada para identificar classes que
fornecem dependências
@_rafaeltoledo
@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();
}
} @_rafaeltoledo
@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();
}
} @_rafaeltoledo
@Provides
● Utilizada nas classes anotadas como
@Module para identificar quais métodos
retornam dependências
@_rafaeltoledo
@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();
}
} @_rafaeltoledo
@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();
}
} @_rafaeltoledo
@Component
● É a anotação que liga os @Modules aos
@Injects
● É colocada em uma interface
● Define quais módulos possui, quem será
injetado
@_rafaeltoledo
@Component
● Precisa especificar obrigatoriamente seu
escopo (ciclo de vida de suas dependências)
● Pode publicar dependências
● Pode possuir outros componentes
@_rafaeltoledo
@Singleton
@Component(
modules = {
DataModule.class,
UiModule.class
}
)
public interface TdcAppComponent {
void inject(TdcApplication app);
MainActivity inject(MainActivity activity);
Application getApplication();
AnalyticsManager getAnalyticsManager();
}
@_rafaeltoledo
@Singleton // Escopo
@Component(
modules = {
DataModule.class,
UiModule.class
}
)
public interface TdcAppComponent {
void inject(TdcApplication app);
MainActivity inject(MainActivity activity);
Application getApplication();
AnalyticsManager getAnalyticsManager();
}
@_rafaeltoledo
@Singleton
@Component(
modules = {
DataModule.class,
UiModule.class
}
)
public interface TdcAppComponent {
void inject(TdcApplication app);
MainActivity inject(MainActivity activity);
Application getApplication();
AnalyticsManager getAnalyticsManager();
}
@_rafaeltoledo
@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();
}
@_rafaeltoledo
@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*
@_rafaeltoledo
@Singleton
@Component(
modules = {
DataModule.class,
UiModule.class
}
)
public interface TdcAppComponent {
void inject(TdcApplication app);
MainActivity inject(MainActivity activity);
Application getApplication();
AnalyticsManager getAnalyticsManager();
}
@_rafaeltoledo
@ActivityScope // Escopo personalizado
@Component(
modules = TdcActivityModule.class,
dependencies = TdcComponent.class
)
public interface TdcActivityComponent {
TdcActivity inject(TdcActivity activity);
TdcActivityPresenter presenter();
}
@_rafaeltoledo
@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);
}
}
@_rafaeltoledo
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
@_rafaeltoledo
Dagger 2
Escopos dinâmicos
@_rafaeltoledo
Escopo = ciclo de vida do grafo de
dependências (componente)
@_rafaeltoledo
@Singleton
@Component(
modules = {
DataModule.class,
UiModule.class
}
)
public interface TdcAppComponent {
void inject(TdcApplication app);
MainActivity inject(MainActivity activity);
Application getApplication();
AnalyticsManager getAnalyticsManager();
}
@_rafaeltoledo
@ActivityScope // Escopo personalizado
@Component(
modules = TdcActivityModule.class,
dependencies = TdcComponent.class
)
public interface TdcActivityComponent {
TdcActivity inject(TdcActivity activity);
TdcActivityPresenter presenter();
}
@_rafaeltoledo
@Scope
@Retention(RetentionPolicy.RUNTIME)
public @interface UserScope {
}
Definição de um escopo
@_rafaeltoledo
Exemplo de uso
Miroslaw Stanek frogermcs.github.io
@_rafaeltoledo
@Singleton
@Component(modules = DataModule.class)
public interface TdcAppComponent {
UserComponent plus(UserModule module);
// não é necessário expor as dependências
}
Implementação
@_rafaeltoledo
@UserScope
@Subcomponent(modules = UserModule.class)
public interface UserComponent {
UserActivityComponent plus(UserActivityModule module);
}
Implementação
@_rafaeltoledo
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
@_rafaeltoledo
Dagger 2
Outras coisas legais!
@_rafaeltoledo
@Inject
Lazy<SharedPreferences> prefs;
void salvar() {
prefs.get().edit().putString("status", "ok!").apply();
}
Dependências “Preguiçosas”
@_rafaeltoledo
// 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
@_rafaeltoledo
// Declarando sua anotação
@MapKey(unwrapValue = true)
@interface GroupKey {
String value();
}
@MapKey
@_rafaeltoledo
// 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
@_rafaeltoledo
// 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
@_rafaeltoledo
Ok! Tudo muito bonito mas...
@_rafaeltoledo
O que eu ganho de fato com tudo isso?
@_rafaeltoledo
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
@_rafaeltoledo
Dagger 2 e Testes
● Programar orientado a interfaces - mocks
● Sobrescrita de Componentes e Módulos
@_rafaeltoledo
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")
);
}
};
}
} @_rafaeltoledo
Dagger 2 e Testes
@Component(modules = DebugMainModule.class)
public interface TestMainComponent extends MainComponent {
}
@_rafaeltoledo
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());
}
}
@_rafaeltoledo
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);
}
}
@_rafaeltoledo
Dagger 2
github.com/rafaeltoledo/dagger2-tdc2015
@_rafaeltoledo
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
OBRIGADO!
rafaeltoledo.net
@_rafaeltoledo
Desenv. Android @ Concrete Solutions
concretesolutions.com.br/carreira

Mais conteúdo relacionado

PDF
Android DevConference - Dagger 2: uso avançado em projetos Android
PDF
Android DevConference - Refactoring for RxJava
PDF
Testes: Por onde Começar?
PDF
Persistência JPA
PDF
Porque você deveria usar CDI nos seus projetos Java! - JavaOne LA 2012 - Sérg...
PDF
Testes de Unidade com Junit
PDF
Reduzindo o boilerplate code com Lombok
ODP
Android DevConference - Elastic Search como ferramenta de busca em aplicações...
Android DevConference - Dagger 2: uso avançado em projetos Android
Android DevConference - Refactoring for RxJava
Testes: Por onde Começar?
Persistência JPA
Porque você deveria usar CDI nos seus projetos Java! - JavaOne LA 2012 - Sérg...
Testes de Unidade com Junit
Reduzindo o boilerplate code com Lombok
Android DevConference - Elastic Search como ferramenta de busca em aplicações...

Mais procurados (19)

PDF
JUnit 5 vs JUnit 4
PDF
TDC2016POA | Trilha Android - Testes no Android
PDF
Liferay e Modularização com Arquitetura OSGi
PDF
Desenvolvimento Dirigido por Testes com Junit
PDF
Seminário sd android_exemplos
PDF
Como construir aplicações gráficas e applets
PPT
Fazendo Injeção de dependência com Unity 1.2
PDF
De a máxima cobertura nos seus testes de API
PPTX
Introdução a testes unitários com jUnit
PDF
Testes de Unidade com JUnit
PPT
Aula JPA
PDF
Vraptor
PDF
Robotium_Sikuli
PDF
Introdução ao JavaFX
PDF
PDF
Conhecendo o Spring
PDF
Palestra Testes Unidade Com JUnit
PDF
JavaEE 7, na era do cloud computing
JUnit 5 vs JUnit 4
TDC2016POA | Trilha Android - Testes no Android
Liferay e Modularização com Arquitetura OSGi
Desenvolvimento Dirigido por Testes com Junit
Seminário sd android_exemplos
Como construir aplicações gráficas e applets
Fazendo Injeção de dependência com Unity 1.2
De a máxima cobertura nos seus testes de API
Introdução a testes unitários com jUnit
Testes de Unidade com JUnit
Aula JPA
Vraptor
Robotium_Sikuli
Introdução ao JavaFX
Conhecendo o Spring
Palestra Testes Unidade Com JUnit
JavaEE 7, na era do cloud computing
Anúncio

Destaque (20)

PDF
Design a arte de materializar as decisoes de negocios
PDF
sap startup focus acelerando startus brasileiras com sap hana
PDF
Por que sua próxima aplicação web deve ser em Clojure?
PPTX
Fundamentos de Akka.net para sistemas concorrentes e distribuidos usando o mo...
PPTX
O que aprendi com minha empresa
PDF
De 0 a10000 usuarios em 3 meses
PPT
o que e ser cio de uma startup?
PDF
como esta a arquitetura do seu app?
PDF
Criando app Android utilizando Kotlin
PDF
Reconstruindo a Torre de Babel com RequireJS
PDF
Repaint/Reflow/Dom/RenderTree - Renderizando uma página web
PDF
Do relogio ao carro
PPTX
introdução a pretotyping fazer a coisa certa mais do que fazer certo a coisa
PDF
Instagram: que tipo de conteúdo o público prefere?
PDF
cakephp 3.0 o bolo ainda serve muita gente
PPTX
Como impulsionar a sua carreira atraves das redes sociais?
PDF
Polo: Desenvolvendo os problemas de inconsistência de dados em projetos Rails
PDF
A experiência da AGCO ao adotar o BDD em seus projetos: uma experiência excit...
PDF
Gere resultados com Facebook Ads
PDF
Gerenciando o ciclo de vida de aplicações com AWS Elastic Beanstalk
Design a arte de materializar as decisoes de negocios
sap startup focus acelerando startus brasileiras com sap hana
Por que sua próxima aplicação web deve ser em Clojure?
Fundamentos de Akka.net para sistemas concorrentes e distribuidos usando o mo...
O que aprendi com minha empresa
De 0 a10000 usuarios em 3 meses
o que e ser cio de uma startup?
como esta a arquitetura do seu app?
Criando app Android utilizando Kotlin
Reconstruindo a Torre de Babel com RequireJS
Repaint/Reflow/Dom/RenderTree - Renderizando uma página web
Do relogio ao carro
introdução a pretotyping fazer a coisa certa mais do que fazer certo a coisa
Instagram: que tipo de conteúdo o público prefere?
cakephp 3.0 o bolo ainda serve muita gente
Como impulsionar a sua carreira atraves das redes sociais?
Polo: Desenvolvendo os problemas de inconsistência de dados em projetos Rails
A experiência da AGCO ao adotar o BDD em seus projetos: uma experiência excit...
Gere resultados com Facebook Ads
Gerenciando o ciclo de vida de aplicações com AWS Elastic Beanstalk
Anúncio

Semelhante a better faster stronger dagger (20)

PDF
(A10) LabMM3 - JavaScript - Subalgoritmos
PDF
Programando para programadores: Desafios na evolução de um Framework
ODP
TDC 2014 SP - E o DeltaSpike ?
PDF
Ecosistema spring a_plataforma_enterprise_jav
PDF
Dependency injection WTF? - PHPSC Conference 2012
PDF
T10_LM3: Subalgoritmos/funções (2013-2014)
PDF
Testando Rails apps com RSpec
PDF
Introdução ao Zend Framework 2
PDF
LabMM3 - Aula teórica 08
PPT
Spring & Struts
ODP
PDF
TDC2016POA | Trilha Android - Testes no Android
PDF
Apostilava Java EE 5 - 2007
PDF
Como escolher o Framework Java para web?
PDF
Paradigmas de Linguagens de Programação - Modularização, componentização e re...
PDF
CDI Extensions e DeltaSpike
PDF
Precisamos falar sobre Gradle
PDF
Spring framework 2.5
(A10) LabMM3 - JavaScript - Subalgoritmos
Programando para programadores: Desafios na evolução de um Framework
TDC 2014 SP - E o DeltaSpike ?
Ecosistema spring a_plataforma_enterprise_jav
Dependency injection WTF? - PHPSC Conference 2012
T10_LM3: Subalgoritmos/funções (2013-2014)
Testando Rails apps com RSpec
Introdução ao Zend Framework 2
LabMM3 - Aula teórica 08
Spring & Struts
TDC2016POA | Trilha Android - Testes no Android
Apostilava Java EE 5 - 2007
Como escolher o Framework Java para web?
Paradigmas de Linguagens de Programação - Modularização, componentização e re...
CDI Extensions e DeltaSpike
Precisamos falar sobre Gradle
Spring framework 2.5

Mais de tdc-globalcode (20)

PDF
TDC2019 Intel Software Day - Visao Computacional e IA a servico da humanidade
PDF
TDC2019 Intel Software Day - Tecnicas de Programacao Paralela em Machine Lear...
PDF
TDC2019 Intel Software Day - ACATE - Cases de Sucesso
PDF
TDC2019 Intel Software Day - Otimizacao grafica com o Intel GPA
PDF
TDC2019 Intel Software Day - Deteccao de objetos em tempo real com OpenVino
PDF
TDC2019 Intel Software Day - OpenCV: Inteligencia artificial e Visao Computac...
PDF
TDC2019 Intel Software Day - Inferencia de IA em edge devices
PDF
Trilha BigData - Banco de Dados Orientado a Grafos na Seguranca Publica
PPT
Trilha .Net - Programacao funcional usando f#
PDF
TDC2018SP | Trilha Go - Case Easylocus
PDF
TDC2018SP | Trilha Modern Web - Para onde caminha a Web?
PDF
TDC2018SP | Trilha Go - Clean architecture em Golang
PDF
TDC2018SP | Trilha Go - "Go" tambem e linguagem de QA
PDF
TDC2018SP | Trilha Mobile - Digital Wallets - Seguranca, inovacao e tendencia
PDF
TDC2018SP | Trilha .Net - Real Time apps com Azure SignalR Service
PDF
TDC2018SP | Trilha .Net - Passado, Presente e Futuro do .NET
PDF
TDC2018SP | Trilha .Net - Novidades do C# 7 e 8
PDF
TDC2018SP | Trilha .Net - Obtendo metricas com TDD utilizando build automatiz...
PDF
TDC2018SP | Trilha .Net - .NET funcional com F#
PDF
TDC2018SP | Trilha .Net - Crie SPAs com Razor e C# usando Blazor em .Net Core
TDC2019 Intel Software Day - Visao Computacional e IA a servico da humanidade
TDC2019 Intel Software Day - Tecnicas de Programacao Paralela em Machine Lear...
TDC2019 Intel Software Day - ACATE - Cases de Sucesso
TDC2019 Intel Software Day - Otimizacao grafica com o Intel GPA
TDC2019 Intel Software Day - Deteccao de objetos em tempo real com OpenVino
TDC2019 Intel Software Day - OpenCV: Inteligencia artificial e Visao Computac...
TDC2019 Intel Software Day - Inferencia de IA em edge devices
Trilha BigData - Banco de Dados Orientado a Grafos na Seguranca Publica
Trilha .Net - Programacao funcional usando f#
TDC2018SP | Trilha Go - Case Easylocus
TDC2018SP | Trilha Modern Web - Para onde caminha a Web?
TDC2018SP | Trilha Go - Clean architecture em Golang
TDC2018SP | Trilha Go - "Go" tambem e linguagem de QA
TDC2018SP | Trilha Mobile - Digital Wallets - Seguranca, inovacao e tendencia
TDC2018SP | Trilha .Net - Real Time apps com Azure SignalR Service
TDC2018SP | Trilha .Net - Passado, Presente e Futuro do .NET
TDC2018SP | Trilha .Net - Novidades do C# 7 e 8
TDC2018SP | Trilha .Net - Obtendo metricas com TDD utilizando build automatiz...
TDC2018SP | Trilha .Net - .NET funcional com F#
TDC2018SP | Trilha .Net - Crie SPAs com Razor e C# usando Blazor em .Net Core

Último (20)

PPTX
ELEMENTOS E FUNÇÕES DE LINGUAGEM (EMOTIVA, REFERENCIAL, CONATIVA, POÉTICA, FÁ...
PDF
Ebook - Matemática_Ensino_Médio_Saeb_V1.pdf
PDF
O retorno a origem (islã Islamismo)
PPTX
Aula 13 - Tópico Frasal - Argumentação.pptx
PPTX
Reino Monera e Protista: representantes e caracteristicas.pptx
PPTX
Pedagogia em Ambientes Não Escolares.pptx
PDF
Metabolismo_energético_3ano_pre_vest_2026.pdf
PPT
História e Evolução dos Computadores domésticos
PPTX
INDÚSTRIA_ Histórico da industrialização.pptx
PPTX
brasilcolnia2-101027184359-phpapp02.pptx
PPTX
O Romantismo e a identidade brasileira..
PPTX
Trabalho Cidades sustentáveis ou Utopia.pptx
PDF
Uma Introdução às Ciências do Alcorão (Islam)
PPTX
Ciências da Natureza e suas áreas de desenvolvimento
PPTX
ACIDOS NUCLEICOS - REPLICAÇÃO DO DNA - E.M.
PDF
Ementa 2 semestre PEI Orientação de estudo
PDF
A relação entre funções executivas e desempenho acadêmico em crianças com Tra...
PPTX
Revolução Industrial - Aula Expositiva - 3U4.pptx
PDF
A Revolução Francesa de 1789 slides história
PPTX
A História da Europa na Baixa Idade Média.pptx
ELEMENTOS E FUNÇÕES DE LINGUAGEM (EMOTIVA, REFERENCIAL, CONATIVA, POÉTICA, FÁ...
Ebook - Matemática_Ensino_Médio_Saeb_V1.pdf
O retorno a origem (islã Islamismo)
Aula 13 - Tópico Frasal - Argumentação.pptx
Reino Monera e Protista: representantes e caracteristicas.pptx
Pedagogia em Ambientes Não Escolares.pptx
Metabolismo_energético_3ano_pre_vest_2026.pdf
História e Evolução dos Computadores domésticos
INDÚSTRIA_ Histórico da industrialização.pptx
brasilcolnia2-101027184359-phpapp02.pptx
O Romantismo e a identidade brasileira..
Trabalho Cidades sustentáveis ou Utopia.pptx
Uma Introdução às Ciências do Alcorão (Islam)
Ciências da Natureza e suas áreas de desenvolvimento
ACIDOS NUCLEICOS - REPLICAÇÃO DO DNA - E.M.
Ementa 2 semestre PEI Orientação de estudo
A relação entre funções executivas e desempenho acadêmico em crianças com Tra...
Revolução Industrial - Aula Expositiva - 3U4.pptx
A Revolução Francesa de 1789 slides história
A História da Europa na Baixa Idade Média.pptx

better faster stronger dagger

  • 2. Rafael Toledo @_rafaeltoledo Android Developer @ Concrete Solutions www.rafaeltoledo.net
  • 3. O que é Injeção de Dependência? @_rafaeltoledo
  • 4. “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. (...)” @_rafaeltoledo
  • 5. “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 @_rafaeltoledo
  • 7. Diz respeito a separação de onde os objetos são criados e onde são utilizados @_rafaeltoledo
  • 8. Em vez de criar, você pede @_rafaeltoledo
  • 9. 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); } } } @_rafaeltoledo
  • 10. 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); } } } @_rafaeltoledo
  • 11. 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); } } } @_rafaeltoledo
  • 12. 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); } } } @_rafaeltoledo
  • 13. 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); } } } @_rafaeltoledo
  • 14. 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); } } } @_rafaeltoledo
  • 15. 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); } } } @_rafaeltoledo
  • 16. 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); } } } @_rafaeltoledo
  • 22. class UserDaoImpl implements UserDao { public UserDaoImpl() { //... } } @_rafaeltoledo
  • 23. class UserDaoImpl implements UserDao { public UserDaoImpl(Context context) { //... } } @_rafaeltoledo
  • 25. Alteração em todas as classes! @_rafaeltoledo
  • 26. Alteração em todas as classes! Muito retrabalho! @_rafaeltoledo
  • 27. Alteração em todas as classes! Muito retrabalho! @_rafaeltoledo
  • 28. Alteração em todas as classes! Muito retrabalho! @_rafaeltoledo
  • 29. 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); } } } @_rafaeltoledo
  • 30. 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); } } } @_rafaeltoledo
  • 31. 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); } } } @_rafaeltoledo
  • 32. DI: Separação do uso e criação de objetos @_rafaeltoledo
  • 33. DI: Separação do uso e criação de objetos não há a necessidade de bibliotecas ou frameworks! @_rafaeltoledo
  • 35. Spring, Guice, Dagger 1 & cia #oldbutgold @_rafaeltoledo
  • 36. Spring, Guice, Dagger 1 & cia #oldbutnot @_rafaeltoledo
  • 39. 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 @_rafaeltoledo
  • 40. 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 @_rafaeltoledo
  • 41. Dagger 2 ● API enxuta! ● Código gerado é debugger-friendly ● Muito performático ● google.github.io/dagger @_rafaeltoledo
  • 42. 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(); } @_rafaeltoledo
  • 43. // JSR-330 public @interface Inject { } public @interface Scope { } public @interface Qualifier { } @_rafaeltoledo
  • 44. Como integro no meu projeto? @_rafaeltoledo
  • 45. // build.gradle buildscript { repositories { jcenter() } dependencies { classpath 'com.android.tools.build:gradle:1.3.1' } } allprojects { repositories { jcenter() } } @_rafaeltoledo
  • 46. // build.gradle buildscript { repositories { jcenter() } dependencies { classpath 'com.android.tools.build:gradle:1.3.1' } } allprojects { repositories { jcenter() } } @_rafaeltoledo
  • 47. // build.gradle buildscript { repositories { jcenter() } dependencies { classpath 'com.android.tools.build:gradle:1.3.1' classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8' } } allprojects { repositories { jcenter() } } @_rafaeltoledo
  • 48. apply plugin: 'com.android.application' android { compileSdkVersion 23 buildToolsVersion '23.0.1' defaultConfig { applicationId 'net.rafaeltoledo.tdc2015' minSdkVersion 15 targetSdkVersion 23 versionCode 1 versionName '1.0' } } dependencies { compile 'com.android.support:appcompat-v7:23.0.1' } @_rafaeltoledo
  • 49. apply plugin: 'com.android.application' apply plugin: 'com.neenbedankt.android-apt' android { compileSdkVersion 23 buildToolsVersion '23.0.1' defaultConfig { applicationId 'net.rafaeltoledo.tdc2015' minSdkVersion 15 targetSdkVersion 23 versionCode 1 versionName '1.0' } } dependencies { compile 'com.android.support:appcompat-v7:23.0.1' compile 'com.google.dagger:dagger:2.0.1' apt 'com.google.dagger:dagger-compiler:2.0.1' provided 'javax.annotation:javax.annotation-api:1.2' } @_rafaeltoledo
  • 50. apply plugin: 'com.android.application' apply plugin: 'com.neenbedankt.android-apt' android { compileSdkVersion 23 buildToolsVersion '23.0.1' defaultConfig { applicationId 'net.rafaeltoledo.tdc2015' minSdkVersion 15 targetSdkVersion 23 versionCode 1 versionName '1.0' } } dependencies { compile 'com.android.support:appcompat-v7:23.0.1' compile 'com.google.dagger:dagger:2.0.1' apt 'com.google.dagger:dagger-compiler:2.0.1' provided 'javax.annotation:javax.annotation-api:1.2' // JSR-330 } @_rafaeltoledo
  • 54. @Inject ● Parte da JSR-330 ● Marca quais dependências devem ser fornecidas pelo Dagger ● Pode aparecer de 3 formas no código @_rafaeltoledo
  • 55. 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 @_rafaeltoledo
  • 56. 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) @_rafaeltoledo
  • 57. 1. No Construtor ● Limitação: não podemos anotar mais que um construtor com a anotação @Inject @_rafaeltoledo
  • 58. 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 @_rafaeltoledo
  • 59. 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! @_rafaeltoledo
  • 60. 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 @_rafaeltoledo
  • 61. 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); } @_rafaeltoledo
  • 62. 3. Em métodos públicos ● O método anotado é chamado automaticamente logo após o construtor @_rafaeltoledo
  • 63. @Module ● Parte da API do Dagger ● Utilizada para identificar classes que fornecem dependências @_rafaeltoledo
  • 64. @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(); } } @_rafaeltoledo
  • 65. @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(); } } @_rafaeltoledo
  • 66. @Provides ● Utilizada nas classes anotadas como @Module para identificar quais métodos retornam dependências @_rafaeltoledo
  • 67. @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(); } } @_rafaeltoledo
  • 68. @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(); } } @_rafaeltoledo
  • 69. @Component ● É a anotação que liga os @Modules aos @Injects ● É colocada em uma interface ● Define quais módulos possui, quem será injetado @_rafaeltoledo
  • 70. @Component ● Precisa especificar obrigatoriamente seu escopo (ciclo de vida de suas dependências) ● Pode publicar dependências ● Pode possuir outros componentes @_rafaeltoledo
  • 71. @Singleton @Component( modules = { DataModule.class, UiModule.class } ) public interface TdcAppComponent { void inject(TdcApplication app); MainActivity inject(MainActivity activity); Application getApplication(); AnalyticsManager getAnalyticsManager(); } @_rafaeltoledo
  • 72. @Singleton // Escopo @Component( modules = { DataModule.class, UiModule.class } ) public interface TdcAppComponent { void inject(TdcApplication app); MainActivity inject(MainActivity activity); Application getApplication(); AnalyticsManager getAnalyticsManager(); } @_rafaeltoledo
  • 73. @Singleton @Component( modules = { DataModule.class, UiModule.class } ) public interface TdcAppComponent { void inject(TdcApplication app); MainActivity inject(MainActivity activity); Application getApplication(); AnalyticsManager getAnalyticsManager(); } @_rafaeltoledo
  • 74. @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(); } @_rafaeltoledo
  • 75. @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* @_rafaeltoledo
  • 76. @Singleton @Component( modules = { DataModule.class, UiModule.class } ) public interface TdcAppComponent { void inject(TdcApplication app); MainActivity inject(MainActivity activity); Application getApplication(); AnalyticsManager getAnalyticsManager(); } @_rafaeltoledo
  • 77. @ActivityScope // Escopo personalizado @Component( modules = TdcActivityModule.class, dependencies = TdcComponent.class ) public interface TdcActivityComponent { TdcActivity inject(TdcActivity activity); TdcActivityPresenter presenter(); } @_rafaeltoledo
  • 78. @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); } } @_rafaeltoledo
  • 79. 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 @_rafaeltoledo
  • 81. Escopo = ciclo de vida do grafo de dependências (componente) @_rafaeltoledo
  • 82. @Singleton @Component( modules = { DataModule.class, UiModule.class } ) public interface TdcAppComponent { void inject(TdcApplication app); MainActivity inject(MainActivity activity); Application getApplication(); AnalyticsManager getAnalyticsManager(); } @_rafaeltoledo
  • 83. @ActivityScope // Escopo personalizado @Component( modules = TdcActivityModule.class, dependencies = TdcComponent.class ) public interface TdcActivityComponent { TdcActivity inject(TdcActivity activity); TdcActivityPresenter presenter(); } @_rafaeltoledo
  • 84. @Scope @Retention(RetentionPolicy.RUNTIME) public @interface UserScope { } Definição de um escopo @_rafaeltoledo
  • 85. Exemplo de uso Miroslaw Stanek frogermcs.github.io @_rafaeltoledo
  • 86. @Singleton @Component(modules = DataModule.class) public interface TdcAppComponent { UserComponent plus(UserModule module); // não é necessário expor as dependências } Implementação @_rafaeltoledo
  • 87. @UserScope @Subcomponent(modules = UserModule.class) public interface UserComponent { UserActivityComponent plus(UserActivityModule module); } Implementação @_rafaeltoledo
  • 88. 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 @_rafaeltoledo
  • 89. Dagger 2 Outras coisas legais! @_rafaeltoledo
  • 90. @Inject Lazy<SharedPreferences> prefs; void salvar() { prefs.get().edit().putString("status", "ok!").apply(); } Dependências “Preguiçosas” @_rafaeltoledo
  • 91. // 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 @_rafaeltoledo
  • 92. // Declarando sua anotação @MapKey(unwrapValue = true) @interface GroupKey { String value(); } @MapKey @_rafaeltoledo
  • 93. // 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 @_rafaeltoledo
  • 94. // 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 @_rafaeltoledo
  • 95. Ok! Tudo muito bonito mas... @_rafaeltoledo
  • 96. O que eu ganho de fato com tudo isso? @_rafaeltoledo
  • 97. 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 @_rafaeltoledo
  • 98. Dagger 2 e Testes ● Programar orientado a interfaces - mocks ● Sobrescrita de Componentes e Módulos @_rafaeltoledo
  • 99. 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") ); } }; } } @_rafaeltoledo
  • 100. Dagger 2 e Testes @Component(modules = DebugMainModule.class) public interface TestMainComponent extends MainComponent { } @_rafaeltoledo
  • 101. 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()); } } @_rafaeltoledo
  • 102. 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); } } @_rafaeltoledo
  • 104. 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
  • 105. OBRIGADO! rafaeltoledo.net @_rafaeltoledo Desenv. Android @ Concrete Solutions concretesolutions.com.br/carreira