J'ai un BaseUiFragment dans le module de base, j'ai besoin d'injecter un UiComponent.Comment utiliser AndroidInjection dans la classe de base?
public abstract class BaseUiFragment extends Fragment {
@Inject
UiComponent mUiComponent;
@Override
public final void onAttach(Context context) {
AndroidSupportInjection.inject(this); //this is subclass
super.onAttach(context);
}
}
@Subcomponent
public interface BaseUiFragmentSubcomponent extends AndroidInjector<BaseUiFragment> {
@Subcomponent.Builder
abstract class Builder extends AndroidInjector.Builder<BaseUiFragment> {
}
}
@Module(subcomponents = BaseUiFragmentSubcomponent.class)
public abstract class BaseUiFragmentModule {
@Binds
@IntoMap
@FragmentKey(BaseUiFragment.class) // key in MapProviderFactory
abstract AndroidInjector.Factory<? extends Fragment>
bindBaseUiFragmentInjectorFactory(BaseUiFragmentSubcomponent.Builder builder);
private BaseUiFragmentModule() {}
}
Dans le module d'application, UiComponentModule fournir UIComponent, MainFragment étend BaseUiFragment.
@Module
public class UiComponentModule {
@Provides
static UiComponent provideUiComponent() {
return new UiComponent() {};
}
}
@Singleton
@Component(modules = {AndroidSupportInjectionModule.class, BaseUiFragmentModule.class, UiComponentModule.class})
public interface ApplicationComponent extends AndroidInjector<MainApplication> {
@Component.Builder
abstract class Builder extends AndroidInjector.Builder<MainApplication> {
}
}
public class MainFragment extends BaseUiFragment {
@Override
public View onCreateViewImpl(Bundle savedInstanceState) {
return new View(getContext());
}
}
lorsque AndroidSupportInjection.inject (this); courir, ça ne marche pas. Parce que maybeInject() return false
injectorFactories de DispatchingAndroidInjector a (BaseUiFragment.class, ...) pas a (MainFragment.class, ...), mais AndroidSupportInjection.inject (this); c'est MainFragment.
public boolean maybeInject(T instance) {
Provider<AndroidInjector.Factory<? extends T>> factoryProvider =
injectorFactories.get(instance.getClass());
if (factoryProvider == null) { // factoryProvider is null
return false;
}
// ...
}
Alors, Comment utiliser AndroidInjection (AndroidSupportInjection) dans la classe de base?
Après quelques jours d'analyse:
injectent de Google impl: il est seulement instance.getClass()
public boolean maybeInject(T instance) {
Provider<AndroidInjector.Factory<? extends T>> factoryProvider =
injectorFactories.get(instance.getClass());
if (factoryProvider == null) {
return false;
}
// ...
}
Mon impl: traversal et sa superclasse, le problème est résolu , mais il utilise la réflexion qui obtient le factoryProvider.
public boolean maybeInject(T instance) {
Provider<AndroidInjector.Factory<? extends Fragment>> factoryProvider
= injectorFactories.get(fragment.getClass());
Class fragmentSuperclass = fragment.getClass().getSuperclass();
while (factoryProvider == null && fragmentSuperclass != Fragment.class) {
factoryProvider = injectorFactories.get(fragmentSuperclass);
fragmentSuperclass = fragmentSuperclass.getSuperclass();
}
if (factoryProvider == null) {
return false;
}
// ...
}
Alors, est-ce que cette façon? Et Google peut changer la mise en œuvre?
« créer un sous-composant pour chaque feuille de votre hiérarchie d'héritage » est pas une bonne façon, je pense. ce n'est pas sympathique pour l'appelant qui utilise ma bibliothèque de base. –
@ApolunorJing Dagger est une solution de génération de code _compile-time. Si 'FooFragment' a un champ' @Inject Bar bar', Dagger ne peut pas le peupler sans l'inspecter au moment de la compilation (donc il peut écrire un setter pour cela), et la façon de le dire est exactement comme Trev l'a ici. +1 à la réponse –