J'ai une Core Android Library où je définis une annonce CoreComponent en utilisant la portée @Singleton pour injecter des instances de classes fournies par un CoreModule.
@Singleton
@Component(modules = {CoreModule.class})
public interface CoreComponent {
void inject(SomeClass target);
}
@Module
public class CoreModule {
@Singleton
@Provides
CoreRepository provideCoreRepository() {
return new CoreRepositoryImpl();
}
}
Je voudrais accéder aux mêmes instances @Singleton à partir d'une autre Android qui dépend de la bibliothèque principale et utilise un autre composant.
@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);
}
[...]
}
Le code ci-dessus est généré mais la portée @Singleton est "locale" pour le composant. En d'autres termes, il existe deux instances singleton, l'une pour le CoreComponent et l'autre pour le FooComponent.
Android Application
├── Foo Library
| └── Core Library
├── Bar Library
| └── Core Library
·
·
·
└── Core Library
Je pense que la meilleure solution devrait être d'utiliser un sous-composant mais, malheureusement, cela ne semble pas possible car la Core Library n'a pas de visibilité sur les autres bibliothèques.
Existe-t-il un autre moyen de partager avec Dagger la même instance d'une classe entre les composants si la classe est annotée avec la même portée?
Supprimez les sites d'injection de votre CoreComponent
- il a désormais pour seule fonction d'exposer la liaison de CoreRepository
à ses composants dépendants:
@Singleton
@Component(modules = {CoreModule.class})
public interface CoreComponent {
CoreRepository coreRepository();
}
Créez une référence à ce composant de portée singleton dans votre application:
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;
}
}
Créez une nouvelle portée plus étroite:
@Scope
@Retention(RetentionPolicy.RUNTIME) public @interface PerActivity {}
Créez un nouveau composant qui suit cette portée avec les sites d'injection souhaités:
@PerActivity
@Component(dependencies = {CoreComponent.class})
public interface ActivityComponent {
void inject(FooActivity activity);
void inject(BarActivity activity);
}
Lorsque vous accédez à ce composant à portée d'activité dans le site d'injection, vous devez fournir l'instance de CoreComponent
au générateur. Vous pouvez maintenant injecter dans votre 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);
}
}
}