Руководство для 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() {
}
}
Вам нужно будет «привязать» конкретную реализацию к интерфейсу с помощью @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.) Пожалуйста, ответьте на другие вопросы Stack Overflow, касающиеся Dagger2, они предоставляют много информации. Например, моя текущая структура Dagger2 указана в этом ответе.
Спасибо
Благодарим вас за руководства на Github, TutsPlus, Джо Стил, Froger MCS и Google.
Также для этого пошагового руководства по миграции, которое я нашел после написания этого сообщения.
И за объяснение объема Кирилла.
Дополнительную информацию можно найти в официальной документации.
person
Community
schedule
29.04.2015
ViewModel
иPageKeyedDataSource
? Как я использую RxJava2 и хочу, чтобы CompositeDisposable совместно использовался обоими классами, и если пользователь нажимает кнопку возврата, я хочу очистить объект Disposable. Я добавил здесь случай: stackoverflow .com / questions / 62595956 / - person AndroidDev   schedule 26.06.2020ViewModel
и, возможно, передать тот же композитныйDisposable в качестве аргумента конструктора вашего настраиваемого PageKeyedDataSource, но я бы не стал использовать Dagger для этой части, потому что тогда вам понадобятся подкомпоненты с подзаданной областью, а Hilt на самом деле не будет поддерживать это так просто для тебя. - person EpicPandaForce   schedule 26.06.2020