Кинжал 2: предоставить один и тот же экземпляр между несколькими компонентами с одинаковой областью действия на разных библиотечных модулях

У меня есть базовая Android-библиотека, в которой я определяю объявление CoreComponent с использованием области @Singleton для ввода экземпляров классов, предоставляемых CoreModule.

@Singleton @Component(modules = {CoreModule.class}) public interface CoreComponent { void inject(SomeClass target); } @Module public class CodeModule { @Singleton @Provides CoreRepository provideCoreRepository() { return new CoreRepositoryImpl(); } } 

Я хотел бы получить доступ к тем же экземплярам @Singleton из другой библиотеки Android, которая зависит от базовой библиотеки и использует другой компонент.

 @Singleton @FooScope @Component(modules = {CoreModule.class, FooModule.class}) public interface FooComponent { void inject(SomeActivity target); } public class FooActivity extends AppCompatActivity { @Inject public CoreRepository repo; @Override protected void onCreate(@Nullable Bundle savedInstanceState) { injectDependencies(); super.onCreate(savedInstanceState); } [...] } 

Вышеописанный код создается, но область @Singleton является «локальной» для компонента. Другими словами, есть два экземпляра singleton, один для CoreComponent и один для FooComponent.

 Android Application ├── Foo Library | └── Core Library ├── Bar Library | └── Core Library · · · └── Core Library 

Я считаю, что лучшим решением должно быть использование подкомпонента, но, к сожалению, это не представляется возможным, поскольку в основной библиотеке нет видимости других библиотек.

Есть ли другой способ поделиться с Кинжалом одним и тем же экземпляром одного класса между компонентами, если класс аннотируется с той же областью?

Solutions Collecting From Web of "Кинжал 2: предоставить один и тот же экземпляр между несколькими компонентами с одинаковой областью действия на разных библиотечных модулях"

Удалите сайты инъекций из вашего CoreComponent – теперь у него есть единственная функция разоблачения привязки для CoreRepository к его зависимым компонентам:

 @Singleton @Component(modules = {CoreModule.class}) public interface CoreComponent { CoreRepository coreRepository(); } 

Создайте ссылку на этот компонент с одним ядром внутри приложения:

 public class MyApplication extends Application { private final CoreComponent coreComponent; @Override public void onCreate() { super.onCreate(); coreComponent = DaggerCoreComponent .coreModule(new CoreModule()) .build(); } public static CoreComponent getCoreComponent(Context context) { return ((MyApplication) context.getApplicationContext()).coreComponent; } } 

Создайте новую более узкую область:

 @Scope @Retention(RetentionPolicy.RUNTIME) public @interface PerActivity {} 

Создайте новый компонент, который отслеживает эту область, в комплекте с местами инъекций, которые вы хотите:

 @PerActivity @Component(dependencies = {CoreComponent.class}) public interface ActivityComponent { void inject(FooActivity activity); void inject(BarActivity activity); } 

Когда вы получаете доступ к этому компоненту с областью действия в месте инъекции, вам необходимо предоставить экземпляр CoreComponent для строителя. Теперь вы можете вводить в свою Activity

 public class FooActivity extends AppCompatActivity { @Inject public CoreRepository repo; @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); CoreComponent coreComponent = MyApplication.getCoreComponent(this); DaggerActivityComponent.builder() .coreComponent(coreComponent) .build() .inject(this); } } }