Intereting Posts
Возможно ли создать навигационное приложение поворотного хода на Android с помощью Google Maps? Дизайн виджета Android – черный фон по умолчанию Как масштабировать растровое изображение до размера экрана? Создание скриншотов iPhone и iPad, включая раму устройства Android 5.x: Почему Dialog.Builder отключает текст? Отправка URL-адреса с Android на Windows Phone через NFC дает ссылку Play Store Как использовать API мобильного зрения с помощью TextureView и камеры Чтение простого текстового файла Рекомендации по подключению таблиц и уведомление ContentObservers в Android ContentProvider Игнорировать несколько предупреждений в Android lint Реализация onKeyPreIme (int keyCode, событие KeyEvent) в фрагменте Как получить объект View, на котором была запущена анимация …? Универсальный загрузчик изображений не может загружать изображения иногда Как получать уведомления о каждом новом изображении, видимом в приложении галереи? Выберите элементы в RecyclerView

Как настроить инъекцию зависимостей DAGGER с нуля в проекте Android?

Как использовать Кинжал? Как настроить кинжал для работы в моем проекте Android?

Я бы хотел использовать Dagger в своем Android-проекте, но я нахожу это запутанным.

EDIT: Dagger2 также выходит с 2015 года 04 15, и это еще более запутанно!

[Этот вопрос является «заглушкой», на которой я добавляю свой ответ, когда я больше узнал о Dagger1 и узнал больше о Dagger2. Этот вопрос скорее скорее является руководством , чем «вопросом».]

Solutions Collecting From Web of "Как настроить инъекцию зависимостей DAGGER с нуля в проекте Android?"

Руководство для 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} в кинжале 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 ), вы можете использовать аннотированный конструктор @Inject .

 public class Something { OtherThing otherThing; @Inject public Something(OtherThing otherThing) { this.otherThing = otherThing; } } 

Кроме того, если вы используете конструктор @Inject , вы можете использовать полевую инъекцию без явного вызова @Inject component.inject(this) :

 public class Something { @Inject OtherThing otherThing; @Inject public Something() { } } 

Эти @Inject конструктора @Inject автоматически добавляются к компоненту той же области без необходимости явно указывать их в модуле.

@Singleton @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() { } } 

Вам необходимо «привязать» конкретную реализацию к интерфейсу с помощью @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 Builder 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() или область 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 .

Также для этого пошагового руководства по миграции, которое я нашел после написания этого сообщения.

И для объяснения сферы действия Кирилла.

Еще больше информации в официальной документации .

Руководство для кинжала 1.x :

Шаги следующие:

1.) добавьте Dagger в файл build.gradle для зависимостей

 dependencies { compile fileTree(dir: 'libs', include: ['*.jar']) ... compile 'com.squareup.dagger:dagger:1.2.2' provided 'com.squareup.dagger:dagger-compiler:1.2.2' 

Кроме того, добавьте параметр « packaging-option чтобы предотвратить ошибку о duplicate APKs .

 android { ... packagingOptions { // Exclude file to avoid // Error: Duplicate files during packaging of APK exclude 'META-INF/services/javax.annotation.processing.Processor' } } 

2.) создать класс Injector для обработки ObjectGraph .

 public enum Injector { INSTANCE; private ObjectGraph objectGraph = null; public void init(final Object rootModule) { if(objectGraph == null) { objectGraph = ObjectGraph.create(rootModule); } else { objectGraph = objectGraph.plus(rootModule); } // Inject statics objectGraph.injectStatics(); } public void init(final Object rootModule, final Object target) { init(rootModule); inject(target); } public void inject(final Object target) { objectGraph.inject(target); } public <T> T resolve(Class<T> type) { return objectGraph.get(type); } } 

3.) Создайте RootModule чтобы связать ваши будущие модули вместе. Обратите внимание, что вы должны включать injects чтобы указать каждый класс, в котором вы будете использовать аннотацию @Inject , потому что иначе Dagger выбрасывает RuntimeException .

 @Module( includes = { UtilsModule.class, NetworkingModule.class }, injects = { MainActivity.class } ) public class RootModule { } 

4.) Если у вас есть другие подмодули внутри ваших модулей, указанных в корне, создайте для них модули:

 @Module( includes = { SerializerModule.class, CertUtilModule.class } ) public class UtilsModule { } 

5.) создать листовые модули, которые получают зависимости в качестве параметров конструктора. В моем случае не было круговой зависимости, поэтому я не знаю, может ли Кинжал разрешить это, но я нахожу это маловероятным. Параметры конструктора также должны быть предоставлены в модуле кинжалом, если вы укажете complete = false то он также может быть в других модулях.

 @Module(complete = false, library = true) public class NetworkingModule { @Provides public ClientAuthAuthenticator providesClientAuthAuthenticator() { return new ClientAuthAuthenticator(); } @Provides public ClientCertWebRequestor providesClientCertWebRequestor(ClientAuthAuthenticator clientAuthAuthenticator) { return new ClientCertWebRequestor(clientAuthAuthenticator); } @Provides public ServerCommunicator providesServerCommunicator(ClientCertWebRequestor clientCertWebRequestor) { return new ServerCommunicator(clientCertWebRequestor); } } 

6.) Расширьте Application и инициализируйте Injector .

 @Override public void onCreate() { super.onCreate(); Injector.INSTANCE.init(new RootModule()); } 

7.) В своем MainActivity вызовите Инжектор в onCreate() .

 @Override protected void onCreate(Bundle savedInstanceState) { Injector.INSTANCE.inject(this); super.onCreate(savedInstanceState); ... 

8.) Используйте @Inject в своем MainActivity .

 public class MainActivity extends ActionBarActivity { @Inject public ServerCommunicator serverCommunicator; ... 

Если вы получили ошибку, no injectable constructor found , убедитесь, что вы не забыли аннотации @Provides .