Dagger 2
Dependency Injection - это шаблон
разработки программного объектного
программирования, который реализует
инверсию управления (Inversion of Control)
для предоставления зависимостей
компонентам
DI фреймворки
• Google Guice
• Spring DI
• Java 6 EE CDI
• Dagger
Проблемы DI фреймворков
• Полностью или частично используют Reflection
API
• Конфигурирование зависимостей в XML
• Валидация графа зависимостей во время
выполнения кода
• Генерация кода, трудного для чтения человеком
• Код, который трудно отлаживать
Почему Dagger 2
• Первый DI фреймворк, который полностью
использует только сгенерированный код
• JSR-330
• Легкий и читаемый код, который не отличается от
написанного человеком
• Полная валидация во время компиляции
• Код, который легко отлаживать
• Высокая производительность
Основные компоненты
• Inject

Target для передачи зависимостей
• Module

Предоставляет зависимости
• Component

Связывает Targets и Modules, а также устанавливаются
отношения между Component и их осуществляют их настройку
Пример
OkHttpClient	client	=	new	OkHttpClient();	
	//	Инициализируем	кэш	для	OkHttp	
	Cache	cache	=	new	Cache(getApplication().getCacheDir(),	10	*	1024	*	1024);	
	client.setCache(cache);	
	//	Хранилище	для	токена	сессии	пользователя	
	SharedPreferences	sharedPrefeences	=	
	PreferenceManager.getDefaultSharedPreferences(this);	
	//	Создаем	экземпляр	Gson	
	Gson	gson	=	new	GsonBuilder().create();	
	GsonConverterFactory	converterFactory	=	GsonConverterFactory.create(Gson);	
	//	Создаем	экземпляр	Retrofit	
	Retrofit	retrofit	=	new	Retrofit.Builder()	
																													.baseUrl(“https://onboarding2016.com")	
																													.addConverterFactory(converterFactory)	
																													.client(client)		//	задаем	клиент	
																													.build();
@Module	
public	class	AppModule	{	
				Application	mApplication;	
				public	AppModule(Application	application)	{	
								mApplication	=	application;	
				}	
				@Provides	@Singleton	
				Application	providesApplication()	{	
								return	mApplication;	
				}	
}
@Module	
public	class	NetModule	{	
			String	mBaseUrl;	
			public	NetModule(String	baseUrl)	{	mBaseUrl	=	baseUrl;	}	
			@Provides	@Singleton	
			SharedPreferences	providesSharedPreferences(Application	application)	{	
							return	PreferenceManager.getDefaultSharedPreferences(application);	
			}	
			@Provides	@Singleton	
			Cache	provideOkHttpCache(Application	application)	{		
							return	new	Cache(application.getCacheDir(),	10	*	1024	*	1024);	
			}	
			@Provides	@Singleton	
			Gson	provideGson()	{			
							return	new	GsonBuilder().create();	
			}	
			@Provides	@Singleton	
			OkHttpClient	provideOkHttpClient(Cache	cache)	{	
							OkHttpClient	client	=	new	OkHttpClient();	
							client.setCache(cache);	
							return	client;	
			}	
			@Provides	@Singleton	
			Retrofit	provideRetrofit(Gson	gson,	OkHttpClient	okHttpClient)	{	
									return	new	Retrofit.Builder()	
																.addConverterFactory(GsonConverterFactory.create(gson))	
																.baseUrl(mBaseUrl)	
																.client(okHttpClient)	
																.build();	
				}	
}
public	class	Dagger2SampleActivity	extends	Activity	{	
			@Inject	MyTwitterApiClient	mTwitterApiClient;	
			@Inject	SharedPreferences	sharedPreferences;	
		public	void	onCreate(Bundle	savedInstance)	{	
							//	Инициализируем	поля,	помеченные	@Inject	
							InjectorClass.inject(this);	
			}		
}
@Singleton	
@Component(modules	=	{AppModule.class,	NetModule.class})	
public	interface	NetComponent	{	
			void	inject(Dagger2SampleActivity	activity);	
			//	void	inject(MyFragment	fragment);	
			//	void	inject(MyService	service);	
}
public	class	Dagger2SampleApp	extends	Application	{	
				private	NetComponent	mNetComponent;	
				@Override	
				public	void	onCreate()	{	
								super.onCreate();	
								//	Сгенерированный	компонент	Dagger%COMPONENT_NAME%	
								mNetComponent	=	DaggerNetComponent.builder()	
																.appModule(new	AppModule(this))	
																.netModule(new	NetModule(“https://onboarding2016.com"))	
																.build();	
				}	
				public	NetComponent	getNetComponent()	{	
							return	mNetComponent;	
				}	
}
@Provides	@Singleton	
OkHttpClient	provideOkHttpClient(Cache	cache)	{	
				OkHttpClient	client	=	new	OkHttpClient();	
				client.setCache(cache);	
				return	client;	
}	
@Provides	@Singleton	
OkHttpClient	provideOkHttpClient()	{	
				OkHttpClient	client	=	new	OkHttpClient();	
				return	client;	
}
@Provides	@Named(“cached")	@Singleton	
OkHttpClient	provideOkHttpClient(Cache	cache)	{	
				OkHttpClient	client	=	new	OkHttpClient();	
				client.setCache(cache);	
				return	client;	
}	
@Provides	@Named("non_cached")	@Singleton	
OkHttpClient	provideOkHttpClient()	{	
				OkHttpClient	client	=	new	OkHttpClient();	
				return	client;	
}
@Inject	@Named("cached")	OkHttpClient	clientWithCache;	
@Inject	@Named("non_cached")	OkHttpClient	clientWithoutCache;
@Qualifier	
@Retention(CLASS)	
public	@interface	DefaultPreferences	{	
}
Зависимости
компонентов
Ограничения зависимых
Component-ов
• 2 зависимых Component не могут использовать
один и тот же Scope
• Обязанность по созданию и удалению ссылок,
которые соответствуют ожидаемому поведению,
полностью лежит на вас
• При описание зависимостей между Component,
родительский Component должен явно описать
объекты, которые могут быть переданы в
зависимые от него Component
@UserScope	//	Используем	ранее	объявленый	Scope	
@Component(dependencies	=	NetComponent.class,	
											modules	=	GitHubModule.class)	
public	interface	GitHubComponent	{	
				void	inject(MainActivity	activity);	
}
@Module	
public	class	GitHubModule	{	
				public	interface	GitHubApiInterface	{	
						@GET("/org/{orgName}/repos")	
						Call<ArrayList<Repository>>	getRepository(	
																						@Path("orgName")	String	orgName);	
				}	
				@Provides	
				@UserScope	//	Должен	соответствовать	Scope	Component-а	
				public	GitHubApiInterface	providesGitHubInterface(Retrofit	retrofit)	{	
								return	retrofit.create(GitHubApiInterface.class);	
				}	
}
@Singleton	
@Component(modules	=	{AppModule.class,	NetModule.class})	
public	interface	NetComponent	{	
				Retrofit	retrofit();	
				OkHttpClient	okHttpClient();	
				SharedPreferences	sharedPreferences();	
}
NetComponent	mNetComponent	=	DaggerNetComponent.builder()	
																.appModule(new	AppModule(this))	
																.netModule(new	NetModule("https://onboarding2016.com"))	
																.build();	
GitHubComponent	gitHubComponent	=	DaggerGitHubComponent.builder()	
																.netComponent(mNetComponent)	
																.gitHubModule(new	GitHubModule())	
																.build();
@Module	
public	class	MyActivityModule	{	
				private	final	MyActivity	activity;	
				public	MyActivityModule(MyActivity	activity)	{this.activity	=	activity;}	
				@Provides	@MyActivityScope	@Named("sample_list")	
				public	ArrayAdapter	providesMyListAdapter()	{	
								return	new	ArrayAdapter<String>(	...	);	
				}	
}	
@MyActivityScope	
@Subcomponent(modules={	MyActivityModule.class	})	
public	interface	MyActivitySubComponent	{	
				@Named("sample_list")	ArrayAdapter	myListAdapter();	
}	
@Singleton	
@Component(modules={	...	})	
public	interface	MyApplicationComponent	{	
				MyActivitySubComponent	newMyActivitySubcomponent(	
																																		MyActivityModule	activityModule);	
}
public	class	MyActivity	extends	Activity	{	
		@Inject	ArrayAdapter	arrayAdapter;	
		public	void	onCreate(Bundle	savedInstance)	{	
								((Dagger2SampleApp)	getApplication()).getApplicationComponent())	
												.newMyActivitySubcomponent(new	MyActivityModule(this))	
												.inject(this);	
				}		
}
Ссылки
• Documentation
• Codepath Guide
• GitHub page

Dagger 2