Посібник для Dagger 2.x (переглянутий випуск 6) :
Кроки такі:
1.) додати Daggerдо своїх build.gradleфайлів:
- Верхній рівень build.gradle :
.
// Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript {
repositories {
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:2.2.0'
classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8' //added apt for source code generation
}
}
allprojects {
repositories {
jcenter()
}
}
- build.gradle рівня програми :
.
apply plugin: 'com.android.application'
apply plugin: 'com.neenbedankt.android-apt' //needed for source code generation
android {
compileSdkVersion 24
buildToolsVersion "24.0.2"
defaultConfig {
applicationId "your.app.id"
minSdkVersion 14
targetSdkVersion 24
versionCode 1
versionName "1.0"
}
buildTypes {
debug {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}
dependencies {
apt 'com.google.dagger:dagger-compiler:2.7' //needed for source code generation
compile fileTree(dir: 'libs', include: ['*.jar'])
compile 'com.android.support:appcompat-v7:24.2.1'
compile 'com.google.dagger:dagger:2.7' //dagger itself
provided 'org.glassfish:javax.annotation:10.0-b28' //needed to resolve compilation errors, thanks to tutplus.org for finding the dependency
}
2.) Створіть свій AppContextModuleклас, який забезпечує залежності.
@Module //a module could also include other modules
public class AppContextModule {
private final CustomApplication application;
public AppContextModule(CustomApplication application) {
this.application = application;
}
@Provides
public CustomApplication application() {
return this.application;
}
@Provides
public Context applicationContext() {
return this.application;
}
@Provides
public LocationManager locationService(Context context) {
return (LocationManager) context.getSystemService(Context.LOCATION_SERVICE);
}
}
3.) створити AppContextComponentклас, який надає інтерфейс, щоб отримати класи, які можна вводити.
public interface AppContextComponent {
CustomApplication application(); //provision method
Context applicationContext(); //provision method
LocationManager locationManager(); //provision method
}
3.1.) Ось як би ви створили модуль із реалізацією:
@Module //this is to show that you can include modules to one another
public class AnotherModule {
@Provides
@Singleton
public AnotherClass anotherClass() {
return new AnotherClassImpl();
}
}
@Module(includes=AnotherModule.class) //this is to show that you can include modules to one another
public class OtherModule {
@Provides
@Singleton
public OtherClass otherClass(AnotherClass anotherClass) {
return new OtherClassImpl(anotherClass);
}
}
public interface AnotherComponent {
AnotherClass anotherClass();
}
public interface OtherComponent extends AnotherComponent {
OtherClass otherClass();
}
@Component(modules={OtherModule.class})
@Singleton
public interface ApplicationComponent extends OtherComponent {
void inject(MainActivity mainActivity);
}
Остерігайтеся: Вам потрібно надати @Scopeанотацію (наприклад, @Singletonабо @ActivityScope) на @Providesанотованому методі модуля, щоб отримати провайдера в межах вашого генерованого компонента, інакше він буде недописаний, і ви отримаєте новий екземпляр щоразу, коли будете вводити.
3.2.) Створіть компонент, що охоплює додаток, який визначає, що ви можете вводити (це те саме, що injects={MainActivity.class}в Dagger 1.x):
@Singleton
@Component(module={AppContextModule.class}) //this is where you would add additional modules, and a dependency if you want to subscope
public interface ApplicationComponent extends AppContextComponent { //extend to have the provision methods
void inject(MainActivity mainActivity);
}
3.3.) Для залежностей, які ви можете створити за допомогою конструктора самостійно і не хочете перевизначати за допомогою @Module(наприклад, ви використовуєте аромати побудови замість того, щоб змінити тип реалізації), ви можете використовувати @Injectконстатований конструктор.
public class Something {
OtherThing otherThing;
@Inject
public Something(OtherThing otherThing) {
this.otherThing = otherThing;
}
}
Крім того, якщо ви використовуєте @Injectконструктор, ви можете використовувати введення поля, не вимагаючи явного виклику component.inject(this):
public class Something {
@Inject
OtherThing otherThing;
@Inject
public Something() {
}
}
Ці @Injectкласи конструкторів автоматично додаються до компонента того ж діапазону без необхідності чітко їх вказувати в модулі.
@SingletonОбласті видимості @Injectконструктора клас буде розглядатися в @Singletonконтекстних компонентах.
@Singleton // scoping
public class Something {
OtherThing otherThing;
@Inject
public Something(OtherThing otherThing) {
this.otherThing = otherThing;
}
}
3.4.) Після того, як ви визначили конкретну реалізацію для даного інтерфейсу, наприклад:
public interface Something {
void doSomething();
}
@Singleton
public class SomethingImpl {
@Inject
AnotherThing anotherThing;
@Inject
public SomethingImpl() {
}
}
Вам потрібно буде "прив'язати" конкретну реалізацію до інтерфейсу з a @Module.
@Module
public class SomethingModule {
@Provides
Something something(SomethingImpl something) {
return something;
}
}
Короткий огляд для цього, оскільки Dagger 2.4 є наступним:
@Module
public abstract class SomethingModule {
@Binds
abstract Something something(SomethingImpl something);
}
4.) створити Injectorклас для обробки компонента на рівні програми (він замінює монолітний ObjectGraph)
(Примітка: Rebuild Projectстворити DaggerApplicationComponentклас будівельника за допомогою APT)
public enum Injector {
INSTANCE;
ApplicationComponent applicationComponent;
private Injector(){
}
static void initialize(CustomApplication customApplication) {
ApplicationComponent applicationComponent = DaggerApplicationComponent.builder()
.appContextModule(new AppContextModule(customApplication))
.build();
INSTANCE.applicationComponent = applicationComponent;
}
public static ApplicationComponent get() {
return INSTANCE.applicationComponent;
}
}
5.) створити свій CustomApplicationклас
public class CustomApplication
extends Application {
@Override
public void onCreate() {
super.onCreate();
Injector.initialize(this);
}
}
6.) додати CustomApplicationдо свого AndroidManifest.xml.
<application
android:name=".CustomApplication"
...
7.) Введіть свої заняття вMainActivity
public class MainActivity
extends AppCompatActivity {
@Inject
CustomApplication customApplication;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Injector.get().inject(this);
//customApplication is injected from component
}
}
8.) Насолоджуйтесь!
+1.) Ви можете вказати Scopeдля своїх компонентів, за допомогою яких можна створити компоненти на рівні активності . Підскопи дозволяють забезпечити залежності, які вам потрібні лише для певного субскопа, а не для всієї програми. Зазвичай кожна активність отримує власний модуль із цим налаштуванням. Зауважте, що провайдер, що охоплює область, існує на компонент , тобто для того, щоб зберегти екземпляр для цієї діяльності, сам компонент повинен пережити зміну конфігурації. Наприклад, це може вижити через onRetainCustomNonConfigurationInstance()або мінометний розмах.
Для отримання додаткової інформації про субскопіювання ознайомтеся з посібником Google . Також дивіться цей сайт про методи надання, а також розділ залежностей від компонентів ) та тут .
Щоб створити власну область, потрібно вказати примітку про класифікатор області:
@Scope
@Retention(RetentionPolicy.RUNTIME)
public @interface YourCustomScope {
}
Щоб створити підскоп, потрібно вказати область для вашого компонента та вказати ApplicationComponentяк його залежність. Очевидно, вам потрібно вказати субскоп і на методах постачальника модулів.
@YourCustomScope
@Component(dependencies = {ApplicationComponent.class}, modules = {CustomScopeModule.class})
public interface YourCustomScopedComponent
extends ApplicationComponent {
CustomScopeClass customScopeClass();
void inject(YourScopedClass scopedClass);
}
І
@Module
public class CustomScopeModule {
@Provides
@YourCustomScope
public CustomScopeClass customScopeClass() {
return new CustomScopeClassImpl();
}
}
Зверніть увагу, що лише один компонент, що охоплює область, може бути вказаний як залежність. Подумайте про це саме так, як множинне успадкування не підтримується на Java.
+2.) Про @Subcomponent: по суті, масштаб @Subcomponentможе замінити залежність компонента; але замість того, щоб використовувати будівельник, наданий процесором анотацій, вам потрібно використовувати заводський метод компонентів.
Отже це:
@Singleton
@Component
public interface ApplicationComponent {
}
@YourCustomScope
@Component(dependencies = {ApplicationComponent.class}, modules = {CustomScopeModule.class})
public interface YourCustomScopedComponent
extends ApplicationComponent {
CustomScopeClass customScopeClass();
void inject(YourScopedClass scopedClass);
}
Стає таким:
@Singleton
@Component
public interface ApplicationComponent {
YourCustomScopedComponent newYourCustomScopedComponent(CustomScopeModule customScopeModule);
}
@Subcomponent(modules={CustomScopeModule.class})
@YourCustomScope
public interface YourCustomScopedComponent {
CustomScopeClass customScopeClass();
}
І це:
DaggerYourCustomScopedComponent.builder()
.applicationComponent(Injector.get())
.customScopeModule(new CustomScopeModule())
.build();
Стає таким:
Injector.INSTANCE.newYourCustomScopedComponent(new CustomScopeModule());
+3.): Будь ласка, ознайомтеся з іншими питаннями переповнення стека щодо Dagger2, і вони містять багато інформації. Наприклад, моя відповідна структура Dagger2 вказана у цій відповіді .
Дякую
Дякуємо за путівники Github , TutsPlus , Joe Steele , Froger MCS та Google .
Також для цього покрокового посібника з міграції я знайшов після написання цієї публікації.
А для пояснення обсягу Кирилом.
Ще більше інформації в офіційній документації .