Intereting Posts
Android NotificationManager, дающий мне ошибку "no valid small icon" Правильный способ размещения экранов в Libgdx Исключение исключительного исключения FileNotFoundException из приложения Android в дикой природе Убедитесь, что заданное время находится между двумя моментами независимо от даты Android: поддержка приложений для разрешения нескольких экранов планшета Как приложение контактов Android L свернуть свою панель инструментов? Прокрутите до заданной позиции в Android Leanback ListRow Виртуальное устройство, работающее в Genymotion, периодически выходит в автономный режим в ADB Google Maps отлично работает на Android, но я все равно получаю сообщение об ошибке «Не удалось найти класс« maps.ik », на который ссылается метод methods.z.ag.a" Как сделать EditText не сфокусированным при создании Activity Google Maps API Android v2 Наложение маршрута Невозможно вставить в Редактируемый Android In-App Purchase V3 Ошибка: требуется аутентификация Проверка фрагментации Как обнаружить внешние дисплеи в андроиде, предшествующем API 17

Как настроить инъекцию зависимостей 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 .