使用dagger2进行依赖注入时,我可以注入超类吗?

时间:2015-03-28 02:14:09

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

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

3 个答案:

答案 0 :(得分:41)

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

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);
    }
}

当然,您仍然必须在Component中明确声明每个Activity。

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

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

假设您有一个 @Module ActivityModule和一个 @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);
}

然后,可以像这样创建一个扩展FragmentDagger的{​​{1}}类:

Fragment

对于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扩展Fragments只有一种方法可以实现:

FragmentDagger

您应该可以在任何地方重复使用public abstract void injectFragment(ActivityComponent component); 。请注意 组件实例化后应调用Fragments中的方法super.onCreated()。否则,在重新创建ActivityDagger状态时,您将获得NullPointerException,因为Activity的方法super.onCreate()将被调用。

答案 1 :(得分:28)

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

  

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

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

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

答案 2 :(得分:2)

你可以使用反射进行一些破解:



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> { *; }遵守您的规则,以便按照组件中的方式保留注入方法