如何在基类中使用AndroidInjection?

时间:2017-05-21 16:16:25

标签: dagger-2

我在基础模块中有一个BaseUiFragment,需要注入一个UiComponent。

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() {}
}

在app模块中,UiComponentModule提供UiComponent,MainFragment扩展了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());
    }
}

当AndroidSupportInjection.inject(this);运行,它不起作用。 因为DispatchingAndroidInjector的maybeInject()返回false

injectorFactories有(BaseUiFragment.class,...)没有(MainFragment.class,...),但AndroidSupportInjection.inject(this);这是MainFragment。

public boolean maybeInject(T instance) {
    Provider<AndroidInjector.Factory<? extends T>> factoryProvider =
        injectorFactories.get(instance.getClass());
    if (factoryProvider == null) { // factoryProvider is null
      return false;
    }
    // ...
}

那么,如何在基类中使用AndroidInjection(AndroidSupportInjection)?

经过几天的分析:

Google注入impl:它只是 instance.getClass()

public boolean maybeInject(T instance) {
    Provider<AndroidInjector.Factory<? extends T>> factoryProvider =
            injectorFactories.get(instance.getClass());
    if (factoryProvider == null) {
        return false;
    }
    // ...
}

我的impl:遍历它和它的超类,问题解决了,但是它使用了获取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;
    }
    // ...
}

那么,只是这样吗?谷歌可以改变实施吗?

1 个答案:

答案 0 :(得分:2)

您只创建了一个知道如何注入BaseUiFragment的子组件。由于这就是匕首所能看到的,它只会知道如何生成代码以处理注入BaseUiFragment

您需要为继承层次结构的每个叶子创建一个子组件。

这样的事情是我喜欢做片段组件的方式

@Subcomponent
public interface MainFragmentComponent extends AndroidInjector<MainFragment> {
    @Subcomponent.Builder
    abstract class Builder extends AndroidInjector.Builder<MainFragment> {}

    @Module(subcomponents = MainFragmentComponent.class)
    abstract class BindingModule {
        @Binds
        @IntoMap
        @FragmentKey(MainFragment.class)
        abstract Factory<? extends Fragment> mainFragmentComponentBuilder(Builder impl);
    }
}