Dagger 2 Добавление подкомпонента к родительскому компоненту
Привет, сообщество. У меня проблема с пониманием того, что кинжал 2 добавляет субкомпонент новым способом (добавлен в кинжал 2.7). Смотрите пример ниже:
@Component(modules = {AppModule.class, MainActivityBinder.class})
@Singleton
interface AppComponent
{
inject(MyApplication _)
}
@Subcomponent(modules = ActivityModule.class)
interface ActivitySubcomponent
{
inject(MainActivity _)
@Subcomponent.Builder
interface Builder
{
@BindInstance
Builder activity(Activity activity)
ActivitySubcomponent build();
}
}
Начальный шаг: у меня есть AppComponent
это мой корневой компонент, который обеспечивает AppModule
с синглетами (дооснащение, охттп и т. д.) в ActivitySubcomponent
Я предоставляю ActivityModule
с имеет зависимости, указанные для этого действия. Теперь подкомпонент должен быть добавлен в AppComponent
, так что по-новому я создаю указанный модуль под названием MainActivityBinder
, который имеет аннотации @Module.subcomponents с указанием на то, что связывает подкомпонент, но у меня есть первая проблема, что должно быть в теле этого модуля связывания?
@Module(subcomponents = ActivitySubcomponent.class)
public class MainActivityBinder
{
//what body of this class should be ??
}
Я знаю, что идея заключается в том, что я могу связать субкомпонента или их строителя. Второй вопрос, когда связывать строителя, а когда связывать подкомпонент? Например мой ActivitySubcomponent
требуемый контекст активности, поэтому я создаю конструктор, который предоставляет контекст для ActivityModule
в этом случае будет лучше обеспечить в MainActivityBinder
строитель? Третий вопрос, как вызвать компоновщик компонентов и как получить подкомпонент для компонента приложения? В стандартном субкомпонентном заводе я добавил AppComponent
метод, который возвращает подкомпонент, и я могу определить параметры (например, дать контекст действия, указанный ниже)
@Component(modules = {AppModule.class})
@Singleton
interface AppComponent
{
ActivitySubcomponents newActivitySubcomponents(Activity activity);
inject(MyApplication _);
}
// in MainActivity
appComponent.newActivitySubcomponents(this).build().inject(this);
так достигнуть этого поведения в новом добавленном методе подкомпонента?
1 ответ
Ваш модуль MainActivityBinder может быть пустым, и должен быть, если у вас нет ничего, чтобы связать с ним. Пустые (только аннотации) модули также полезны, когда вы используете только
Module.includes
Например, когда вы хотите хранить список модулей в одном месте, а не дублировать его среди нескольких компонентов.subcomponents
Атрибут в аннотации достаточен для того, чтобы Даггер понял, что вы пытаетесь сделать.Вы можете внедрить FooSubcomponent или Provider тогда и только тогда, когда у него нет методов @BindsInstance или инстанцируемых модулей (которые Dagger не может создать). Если все ваши модули являются интерфейсами, абстрактными классами или модулями, имеющими открытые конструкторы с нулевым аргументом, то вы можете напрямую внедрить подкомпонент. В противном случае вы должны вместо этого ввести свой компонент субкомпонента.
Вы можете добраться до вашего компоновщика подкомпонентов, создав метод, который возвращает его в вашем AppComponent, так же, как вы можете для любой привязки, существующей в графе:
@Component(modules = {AppModule.class, MainActivityBinder.class}) @Singleton interface AppComponent { ActivitySubcomponent.Builder activitySubcomponentBuilder(); inject(MyApplication _) }
Вы также можете ввести его в объект по вашему выбору.
@Inject ActivitySubcomponent.Builder activitySubComponentBuilder; activitySubComponentBuilder.activity(this).build().inject(this); // You can also inject a Provider<ActivitySubcomponent.Builder> if you want, // which is a good idea if you are injecting this directly into your Application. // Your Application will outlive your Activity, and may need to inject several // instances of the Activity across application lifetime. @Inject Provider<ActivitySubcomponent.Builder> activitySubComponentBuilderProvider; activitySubComponentBuilderProvider.get().activity(this).build().inject(this);
Несмотря на то, что, по-видимому, нет большого преимущества для внедрения построителя подкомпонентов, когда вы можете так же легко вызвать метод компонента (либо для возврата построителя, либо для возврата подкомпонента), есть несколько преимуществ для внедрения построителя:
- Dagger не может определить, вызываете ли вы метод для компонента, поэтому он генерирует и компилирует код, даже если ваш подкомпонент не используется. Dagger может определить, пытались ли вы когда-нибудь внедрить конструктор, поэтому, если нет вложений подкомпонента / построителя и нет методов, Dagger пропустит генерацию кода для подкомпонента.
- Если ваша кодовая база настолько велика, что вам нужно разделить ее на разные цели для компиляции, метод фабричного метода может поймать вас в некоторых циклах зависимостей, где компонент и модули вашего приложения зависят от всего, и вы можете получить доступ к своему подкомпоненту только из своего сам компонент. Благодаря инжектируемым компоновщикам субкомпонентов у вас есть больше вариантов того, как добраться до вашего субкомпонента или компоновщика.