Посібник для 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 .
Також для цього покрокового посібника з міграції я знайшов після написання цієї публікації.
А для пояснення обсягу Кирилом.
Ще більше інформації в офіційній документації .