Dagger 2
INJEÇÃO DE DEPENDÊNCIA
Injecão de Dependência
 Dependência é qualquer objeto necessário
para o funcionamento de uma classe;
 Desacoplamento entre classes de alto e
baixo nível;
 Inexistente, manual ou automática.
public class ClassA {
private ClassB mClassB;
public ClassA() {
mClassB = new ClassB();
}
}
public class ClassA {
private ClassB mClassB;
public ClassA() {
mClassB = new ClassB(new ClassC());
}
}
public class ClassA {
private ClassB mClassB;
public ClassA(ClassB classB) {
mClassB = classB;
}
}
Bibliotecas
 Guice
 Dagger (v1)
 Dagger 2
 ...
Funcionamento
@Bind(R.id.home_iv) ImageView mImageView;
ButterKnife.bind(this, view);
view mImageView
findViewbyId
@Bind
mImageView = (ImageView)view.findViewbyId(R.id.home_iv);
Funcionamento
Component Object
“findObjectOfTypeX”
@Inject
Module
Exemplo
Retrofit
bit.ly/di-android-meetup
Retrofit Service
public class GitHubApi {
public static final int CACHE_SIZE = 5 * 1024 * 1024;
public static <S> S createService(Class<S> serviceClass, Context context) {
HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor();
interceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
GsonBuilder gsonBuilder = new GsonBuilder();
gsonBuilder.setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES);
final Gson gson = gsonBuilder.create();
OkHttpClient client = new OkHttpClient.Builder()
.addInterceptor(interceptor)
.cache(new Cache(context.getCacheDir(), CACHE_SIZE))
.readTimeout(30, TimeUnit.SECONDS)
.connectTimeout(30, TimeUnit.SECONDS)
.build();
Retrofit retrofit = new Retrofit.Builder()
.addConverterFactory(GsonConverterFactory.create(gson))
.baseUrl(BuildConfig.API_URL)
.client(client)
.build();
return retrofit.create(serviceClass);
}
}
UserModel
public class GitHubUserModel {
private final GitHubService mService;
public GitHubUserModel(Context context) {
mService = GitHubApi.createService(GitHubService.class, context);
}
public Call<List<GitHubUser>> fetchUsers(int page) {
return mService.getUsers(page);
}
...
}
GitHubUserModel userModel = new GitHubUserModel(getActivity().getApplicationContext());
mActionInteractor = new UsersListPresenter(this, userModel);
mActionInteractor.loadUsersList(false);
Introduzindo Dagger
Dagger API
 @Module + @Provides
 Mecanismo para prover dependências
 @Inject
 Mecanismo para requisitar dependências
 @Component
 Ligação entre módulos e injeções
Dagger
Project/build.gradle
buildscript {
repositories {
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:1.5.0'
classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8’
}
}
App/build.gradle
apply plugin: 'com.neenbedankt.android-apt'
compile 'com.google.dagger:dagger:2.0.2'
apt 'com.google.dagger:dagger-compiler:2.0.2'
provided 'org.glassfish:javax.annotation:10.0-b28'
@Module
public class NetworkModule {
public static final int CACHE_SIZE = 5 * 1024 * 1024;
@Provides
public Retrofit provideRetrofit(Gson gson, OkHttpClient client) {
return new Retrofit.Builder()
.addConverterFactory(GsonConverterFactory.create(gson))
.baseUrl(BuildConfig.API_URL)
.client(client)
.build();
}
@Provides
public OkHttpClient provideHttpClient(HttpLoggingInterceptor interceptor, Cache cache) {
return new OkHttpClient.Builder()
.addInterceptor(interceptor)
.cache(cache)
.connectTimeout(60, TimeUnit.SECONDS)
.readTimeout(60, TimeUnit.SECONDS)
.build();
}
@Provides
public Cache provideCache(Application application) {
return new Cache(application.getCacheDir(), CACHE_SIZE);
}
@Provides
public HttpLoggingInterceptor provideHttpInterceptor() {
HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor();
interceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
return interceptor;
}
@Provides
public Gson provideHttpGson() {
GsonBuilder gsonBuilder = new GsonBuilder();
gsonBuilder.setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES);
return gsonBuilder.create();
}
}
@Module
public class GitHubModule {
public interface GitHubService {
@GET("/users")
@Headers("Authorization: token " + BuildConfig.GITHUB_TOKEN)
Call<List<GitHubUser>> getUsers();
@GET("/users/{login}")
@Headers("Authorization: token " + BuildConfig.GITHUB_TOKEN)
Call<GitHubUser> getUser(@Path("login") String login);
@GET("/users")
@Headers("Authorization: token " + BuildConfig.GITHUB_TOKEN)
Call<List<GitHubUser>> getUsers(@Query("since") int page);
}
@Provides
public GitHubService provideGitHubService(Retrofit retrofit) {
return retrofit.create(GitHubService.class);
}
}
@Module
public class AppModule {
private final Context mApplicationContext;
public AppModule(Context applicationContext) {
mApplicationContext = applicationContext;
}
@Provides
@PerApp
public Context provideApplicationContext() {
return mApplicationContext;
}
}
@Component(modules = {AppModule.class, GitHubModule.class, NetworkModule.class})
public interface AppComponent {
void inject(UsersListFragment fragment);
}
DepencyInjectionApplication.java
@NonNull
protected DaggerAppComponent.Builder prepareAppComponent() {
return DaggerAppComponent.builder()
.networkModule(new NetworkModule())
.gitHubModule(new GitHubModule())
.appModule(new AppModule(this));
}
GitHubUserModel.java
public class GitHubUserModel {
private final GitHubModule.GitHubService mService;
@Inject
public GitHubUserModel(GitHubModule.GitHubService service) {
mService = service;
}
...
}
UsersListFragment.java
@Inject public GitHubUserModel mUserModel;
@Override
protected void onCreate() {
DepencyInjectionApplication.getAppComponent(getActivity()).inject(this);
}
@Override
protected void onResume() {
mActionInteractor = new UsersListPresenter(this, mUserModel);
mActionInteractor.loadUsersList(false);
}
GitHubUserModel
Retrofit
OkHttpClient
Gson
NetworkModule#provideRetrofit
NetworkModule#provideHttpClient
NetworkModule#provideGson
GitHubService GitHubModule#provideGitHubService
Component Dependency
@Component(modules={AppModule.class, NetworkModule.class})
public interface NetComponent {
Retrofit retrofit();
}
@Component(dependencies = NetComponent.class, modules = GitHubModule.class)
public interface AppComponent {
void inject(UsersListFragment fragment);
}
public class DepencyInjectionApplication extends Application {
private AppComponent mAppComponent;
private NetComponent mNetComponent;
private void setupDaggerAppComponent() {
mNetComponent = DaggerNetComponent.builder()
.appModule(new AppModule(this))
// .networkModule(new NetworkModule()) is free
.build();
mAppComponent = DaggerAppComponent.builder()
// .gitHubModule(new GitHubModule()) is free
.netComponent(mNetComponent)
.build();
}
}
Subcomponent
@Subcomponent(modules = GitHubModule.class)
public interface GitHubComponent {
void inject(UsersListFragment fragment);
}
@Component(modules = {NetworkModule.class, AppModule.class})
public interface AppComponent {
Application getApplication();
GitHubComponent plus(GitHubModule gitHubModule);
}
DepencyInjectionApplication.java
private void setupDaggerAppComponent() {
mAppComponent = DaggerAppComponent.builder()
.appModule(new AppModule(this))
.build();
}
UsersListFragment.java
@Override
protected void onCreate() {
DepencyInjectionApplication.getAppComponent(getActivity())
.plus(new GitHubModule())
.inject(this);
}
@Override
protected void onResume() {
mActionInteractor = new UsersListPresenter(this, mUserModel);
mActionInteractor.loadUsersList(false);
}
Scopes
 Determinam a intenção de duração de ciclo de vida de um
component;
 @Singleton é o único suportado out-of-the-box;
 Deve ser usado no nível de aplicação
 Custom scopes permitem maior flexibilidade, mas cabe
ao programador respeitar o ciclo de vida.
@Scope
@Retention(RetentionPolicy.RUNTIME)
public @interface PerActivity {}
@Module
public class MyActivityModule {
@PerActivity
@Named("ActivityScope") @Provides
StringBuilder provideStringBuilderActivityScope() {
return new StringBuilder("Activity");
}
@Named("Unscoped") @Provides
StringBuilder provideStringBuilderUnscoped() {
return new StringBuilder("Unscoped");
}
}
public class MyActivity {
@Inject @Named("ActivityScope")
StringBuilder activityScope1;
@Inject @Named("ActivityScope")
StringBuilder activityScope2;
@Inject @Named("Unscoped")
StringBuilder unscoped1;
@Inject @Named("Unscoped")
StringBuilder unscoped2;
public void onCreate() {
activityScope1.append("123");
activityScope1.toString(); // output: "Activity123"
activityScope2.append("456");
activityScope2.toString(); // output: "Activity123456"
unscoped1.append("123");
unscoped1.toString(); // output: "Unscoped123"
unscoped2.append("456");
unscoped2.toString(); // output: "Unscoped456"
}
}
Bonus
 Lazy;
 Inicialização de Map e Set;
 Producer assíncrono;
Conclusão
 Fácil acesso à variáveis compartilhadas;
 Desacoplamento de dependências complexas;
 Controle de ciclo de vida;
 Performance.
Dúvidas?
edson-menegatti-87898718
3dm1
edson.menegatti.7
Referências
https://www.youtube.com/watch?v=oK_XtfXPkqw
https://github.com/codepath/android_guides/wiki/Dependenc
y-Injection-with-Dagger-2
https://www.parleys.com/tutorial/5471cdd1e4b065ebcfa1d55
7/
https://blog.gouline.net/2015/05/04/dagger-2-even-sharper-
less-square/
https://www.youtube.com/watch?v=SKFB8u0-VA0

Dagger 2 - Injeção de Dependência

  • 1.
  • 2.
    Injecão de Dependência Dependência é qualquer objeto necessário para o funcionamento de uma classe;  Desacoplamento entre classes de alto e baixo nível;  Inexistente, manual ou automática.
  • 3.
    public class ClassA{ private ClassB mClassB; public ClassA() { mClassB = new ClassB(); } }
  • 4.
    public class ClassA{ private ClassB mClassB; public ClassA() { mClassB = new ClassB(new ClassC()); } }
  • 5.
    public class ClassA{ private ClassB mClassB; public ClassA(ClassB classB) { mClassB = classB; } }
  • 6.
    Bibliotecas  Guice  Dagger(v1)  Dagger 2  ...
  • 7.
    Funcionamento @Bind(R.id.home_iv) ImageView mImageView; ButterKnife.bind(this,view); view mImageView findViewbyId @Bind mImageView = (ImageView)view.findViewbyId(R.id.home_iv);
  • 8.
  • 9.
  • 10.
    Retrofit Service public classGitHubApi { public static final int CACHE_SIZE = 5 * 1024 * 1024; public static <S> S createService(Class<S> serviceClass, Context context) { HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor(); interceptor.setLevel(HttpLoggingInterceptor.Level.BODY); GsonBuilder gsonBuilder = new GsonBuilder(); gsonBuilder.setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES); final Gson gson = gsonBuilder.create(); OkHttpClient client = new OkHttpClient.Builder() .addInterceptor(interceptor) .cache(new Cache(context.getCacheDir(), CACHE_SIZE)) .readTimeout(30, TimeUnit.SECONDS) .connectTimeout(30, TimeUnit.SECONDS) .build(); Retrofit retrofit = new Retrofit.Builder() .addConverterFactory(GsonConverterFactory.create(gson)) .baseUrl(BuildConfig.API_URL) .client(client) .build(); return retrofit.create(serviceClass); } }
  • 11.
    UserModel public class GitHubUserModel{ private final GitHubService mService; public GitHubUserModel(Context context) { mService = GitHubApi.createService(GitHubService.class, context); } public Call<List<GitHubUser>> fetchUsers(int page) { return mService.getUsers(page); } ... } GitHubUserModel userModel = new GitHubUserModel(getActivity().getApplicationContext()); mActionInteractor = new UsersListPresenter(this, userModel); mActionInteractor.loadUsersList(false);
  • 12.
  • 13.
    Dagger API  @Module+ @Provides  Mecanismo para prover dependências  @Inject  Mecanismo para requisitar dependências  @Component  Ligação entre módulos e injeções
  • 14.
    Dagger Project/build.gradle buildscript { repositories { jcenter() } dependencies{ classpath 'com.android.tools.build:gradle:1.5.0' classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8’ } } App/build.gradle apply plugin: 'com.neenbedankt.android-apt' compile 'com.google.dagger:dagger:2.0.2' apt 'com.google.dagger:dagger-compiler:2.0.2' provided 'org.glassfish:javax.annotation:10.0-b28'
  • 15.
    @Module public class NetworkModule{ public static final int CACHE_SIZE = 5 * 1024 * 1024; @Provides public Retrofit provideRetrofit(Gson gson, OkHttpClient client) { return new Retrofit.Builder() .addConverterFactory(GsonConverterFactory.create(gson)) .baseUrl(BuildConfig.API_URL) .client(client) .build(); } @Provides public OkHttpClient provideHttpClient(HttpLoggingInterceptor interceptor, Cache cache) { return new OkHttpClient.Builder() .addInterceptor(interceptor) .cache(cache) .connectTimeout(60, TimeUnit.SECONDS) .readTimeout(60, TimeUnit.SECONDS) .build(); } @Provides public Cache provideCache(Application application) { return new Cache(application.getCacheDir(), CACHE_SIZE); } @Provides public HttpLoggingInterceptor provideHttpInterceptor() { HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor(); interceptor.setLevel(HttpLoggingInterceptor.Level.BODY); return interceptor; } @Provides public Gson provideHttpGson() { GsonBuilder gsonBuilder = new GsonBuilder(); gsonBuilder.setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES); return gsonBuilder.create(); } }
  • 16.
    @Module public class GitHubModule{ public interface GitHubService { @GET("/users") @Headers("Authorization: token " + BuildConfig.GITHUB_TOKEN) Call<List<GitHubUser>> getUsers(); @GET("/users/{login}") @Headers("Authorization: token " + BuildConfig.GITHUB_TOKEN) Call<GitHubUser> getUser(@Path("login") String login); @GET("/users") @Headers("Authorization: token " + BuildConfig.GITHUB_TOKEN) Call<List<GitHubUser>> getUsers(@Query("since") int page); } @Provides public GitHubService provideGitHubService(Retrofit retrofit) { return retrofit.create(GitHubService.class); } }
  • 17.
    @Module public class AppModule{ private final Context mApplicationContext; public AppModule(Context applicationContext) { mApplicationContext = applicationContext; } @Provides @PerApp public Context provideApplicationContext() { return mApplicationContext; } }
  • 18.
    @Component(modules = {AppModule.class,GitHubModule.class, NetworkModule.class}) public interface AppComponent { void inject(UsersListFragment fragment); } DepencyInjectionApplication.java @NonNull protected DaggerAppComponent.Builder prepareAppComponent() { return DaggerAppComponent.builder() .networkModule(new NetworkModule()) .gitHubModule(new GitHubModule()) .appModule(new AppModule(this)); }
  • 19.
    GitHubUserModel.java public class GitHubUserModel{ private final GitHubModule.GitHubService mService; @Inject public GitHubUserModel(GitHubModule.GitHubService service) { mService = service; } ... } UsersListFragment.java @Inject public GitHubUserModel mUserModel; @Override protected void onCreate() { DepencyInjectionApplication.getAppComponent(getActivity()).inject(this); } @Override protected void onResume() { mActionInteractor = new UsersListPresenter(this, mUserModel); mActionInteractor.loadUsersList(false); }
  • 20.
  • 21.
  • 22.
    @Component(modules={AppModule.class, NetworkModule.class}) public interfaceNetComponent { Retrofit retrofit(); } @Component(dependencies = NetComponent.class, modules = GitHubModule.class) public interface AppComponent { void inject(UsersListFragment fragment); } public class DepencyInjectionApplication extends Application { private AppComponent mAppComponent; private NetComponent mNetComponent; private void setupDaggerAppComponent() { mNetComponent = DaggerNetComponent.builder() .appModule(new AppModule(this)) // .networkModule(new NetworkModule()) is free .build(); mAppComponent = DaggerAppComponent.builder() // .gitHubModule(new GitHubModule()) is free .netComponent(mNetComponent) .build(); } }
  • 23.
  • 24.
    @Subcomponent(modules = GitHubModule.class) publicinterface GitHubComponent { void inject(UsersListFragment fragment); } @Component(modules = {NetworkModule.class, AppModule.class}) public interface AppComponent { Application getApplication(); GitHubComponent plus(GitHubModule gitHubModule); } DepencyInjectionApplication.java private void setupDaggerAppComponent() { mAppComponent = DaggerAppComponent.builder() .appModule(new AppModule(this)) .build(); } UsersListFragment.java @Override protected void onCreate() { DepencyInjectionApplication.getAppComponent(getActivity()) .plus(new GitHubModule()) .inject(this); } @Override protected void onResume() { mActionInteractor = new UsersListPresenter(this, mUserModel); mActionInteractor.loadUsersList(false); }
  • 25.
    Scopes  Determinam aintenção de duração de ciclo de vida de um component;  @Singleton é o único suportado out-of-the-box;  Deve ser usado no nível de aplicação  Custom scopes permitem maior flexibilidade, mas cabe ao programador respeitar o ciclo de vida.
  • 26.
    @Scope @Retention(RetentionPolicy.RUNTIME) public @interface PerActivity{} @Module public class MyActivityModule { @PerActivity @Named("ActivityScope") @Provides StringBuilder provideStringBuilderActivityScope() { return new StringBuilder("Activity"); } @Named("Unscoped") @Provides StringBuilder provideStringBuilderUnscoped() { return new StringBuilder("Unscoped"); } }
  • 27.
    public class MyActivity{ @Inject @Named("ActivityScope") StringBuilder activityScope1; @Inject @Named("ActivityScope") StringBuilder activityScope2; @Inject @Named("Unscoped") StringBuilder unscoped1; @Inject @Named("Unscoped") StringBuilder unscoped2; public void onCreate() { activityScope1.append("123"); activityScope1.toString(); // output: "Activity123" activityScope2.append("456"); activityScope2.toString(); // output: "Activity123456" unscoped1.append("123"); unscoped1.toString(); // output: "Unscoped123" unscoped2.append("456"); unscoped2.toString(); // output: "Unscoped456" } }
  • 28.
    Bonus  Lazy;  Inicializaçãode Map e Set;  Producer assíncrono;
  • 29.
    Conclusão  Fácil acessoà variáveis compartilhadas;  Desacoplamento de dependências complexas;  Controle de ciclo de vida;  Performance.
  • 30.
  • 31.