【问题标题】:Can I just inject super class when use dagger2 for dependency injection?使用 dagger2 进行依赖注入时,我可以只注入超类吗?
【发布时间】:2015-06-01 12:04:14
【问题描述】:

我在我的 android 应用程序中使用 Dagger2 进行 DI。我发现我必须为每个使用 @Inject 字段的类编写注入方法。有没有一种方法可以只注入父类,这样我就不必在每个子类上调用注入? 以活动为例。我有一个BaseActivity,每个 Activity 都从它扩展而来。有没有办法在BaseActivity的组件中创建一个注入方法,然后在BaseActivity的onCreate中调用inject,子活动中的@inject字段自动注入?

【问题讨论】:

  • 您能添加一些示例代码来说明您的意思吗?
  • 只是一个问题(如果我理解正确你的问题)为什么不在基本活动中定义注入字段并在子活动中使用它。任何这种情况,您希望您的“子活动中的注入字段自动注入”

标签: java android dependency-injection dagger dagger-2


【解决方案1】:

目前无法完成。 Gregory Kick 的解释(来自here):

以下是成员注入方法的工作原理:

  1. 您可以为在其类层次结构中的任何位置具有@Inject 的任何类型创建成员注入方法。如果没有,你会得到一个 错误。
  2. 将注入整个类型层次结构中的所有@Injected 成员:参数类型和所有超类型。
  3. 没有成员将被@Injected 用于参数类型的子类型。

herehere 讨论了此问题,请关注这些以获取更新。但它不太可能很快改变,因为 Dagger 2 是close to release

【讨论】:

  • 他们做出这个决定似乎是有原因的。但遗憾的是他们不支持这一点,因为这有点违反直觉,恕我直言。不过,还是谢谢你的回答!
  • @Chris.Zou 要支持子类注入,您需要在运行时进行反射。 Dagger 2 团队很早就决定要避免在运行时做一些事情,因为它比较慢,而且在你运行应用程序之前你不会发现错误。
【解决方案2】:

我遇到了同样的情况。一种在所有活动中简化来自公共组件的注入的方法如下:

1) 扩展 Application 类,以便能够创建公共组件并保留对它的引用。

public class ApplicationDagger extends Application {

    private ApplicationComponent component;

    @Override
    public void onCreate(){
        super.onCreate();
        component = DaggerApplicationComponent.builder().applicationModule(new ApplicationModule(this)).build();
    }

    public ApplicationComponent getComponent(){
            return component;
    }
}

2) 创建一个抽象 DaggerActivity,它从 Application 获取公共组件并调用抽象方法 injectActivity,将组件作为参数。像这样:

public abstract class DaggerActivity extends Activity {

    @Override
    public void onCreate(Bundle saved){
        super.onCreate(saved);
        ApplicationComponent component = ((ApplicationDagger) getApplication()).getComponent();
        injectActivity(component);
    }

    public abstract void injectActivity(ApplicationComponent component);
}

3) 最后,您必须实际注入每个 Activity 扩展 DaggerActivity。但是现在这可以用更少的努力来完成,因为你必须实现abstract 方法,否则你会得到编译错误。我们开始:

public class FirstActivity extends DaggerActivity {

    @Inject
    ClassToInject object;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        //initialize your Activity
    }

    @Override
    public void injectActivity(ApplicationComponent component) {
        component.inject(this);
    }
}

当然,您仍然需要在组件中显式声明每个 Activity。

更新:将@ActivityScope 对象注入片段

在某些时候,我需要使用 custom scopes 将对象绑定到 Activity 生命周期。我决定扩展这篇文章,因为它可能对某些人有所帮助。

假设您有一个 @ModuleActivityModule 和一个 @Subcomponent 接口 ActivityComponent

您需要修改DaggerActivityActivities 扩展 DaggerActivity 需要实现新方法(更改签名)。

public abstract class ActivityDagger extends AppCompatActivity {

    ActivityComponent component;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        component = ((ApplicationDagger) getApplication()).getComponent().plus(new ActivityModule(this));
        injectActivity(component);
        super.onCreate(savedInstanceState);
    }

    ActivityComponent getComponent() {
        return component;
    }

    public abstract void injectActivity(ActivityComponent component);
}

然后,可以像这样创建一个扩展Fragment 的类FragmentDagger

public abstract class FragmentDagger extends Fragment {

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        ActivityDagger activityDagger = (ActivityDagger) getActivity();
        ActivityComponent component = activityDagger.getComponent();
        injectFragment(component);
    }

    public abstract void injectFragment(ActivityComponent component);

}

对于Activities,扩展FragmentDaggerFragments只有一种实现方法:

public abstract void injectFragment(ActivityComponent component);

你应该能够在任何你想要的地方重复使用Fragments。请注意, ActivityDagger 中的方法 super.onCreated() 应该在组件实例化之后调用。否则,在重新创建Activity 状态时会得到NullPointerException,因为会调用Fragment 的方法super.onCreate()

【讨论】:

    【解决方案3】:

    您可以使用反射做一些小技巧:

    public class UiInjector {
    
        private static final String METHOD_NAME = "inject";
    
        private final UIComponent component;
    
        public UiInjector(final UIComponent component) {
            this.component = component;
        }
    
        public void inject(final Object subject) {
            try {
                component.getClass()
                        .getMethod(METHOD_NAME, subject.getClass())
                        .invoke(component, subject);
            } catch (final NoSuchMethodException exception) {
                throwNoInjectMethodForType(component, subject.getClass());
            } catch (final Exception exception) {
                throwUnknownInjectionError(exception);
            }
        }
    
        private void throwNoInjectMethodForType(final Object component, final Class subjectType) {
            throw new RuntimeException(component.getClass().getSimpleName() +
                    " doesn't have inject method with parameter type : " + subjectType);
        }
    
        private void throwUnknownInjectionError(final Exception cause) {
            throw new RuntimeException("Unknown injection error", cause);
        }
    }

    在这种情况下,您仍然需要在组件中编写注入方法,但您不需要在每个活动、片段、视图等中使用“注入”方法。

    为什么它有效?当我们在注入主题上使用getClass() 时,将得到一个后代类,而不是基类。

    小心!如果你使用 Proguard,你需要添加下一个 -keep class <ComponentClass> { *; } 遵守您的规则,以便在组件中保持注入方法

    【讨论】:

    • dagger 应该在编译时进行检查,所以这会破坏这个目的......
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-01-19
    • 1970-01-01
    • 2023-02-10
    • 1970-01-01
    • 2019-11-24
    • 1970-01-01
    相关资源
    最近更新 更多