我在我的Android应用程序中使用Dagger2进行DI。我发现我必须为每个使用@Inject字段的类编写inject方法。有没有办法可以注入父类,这样我就不必在每个子类上调用注入?
以活动为例。我有一个BaseActivity
,每个Activity都来自。{1}}。有没有办法可以在组件中为BaseActivity创建一个注入方法,只需在BaseActivity中调用注入onCreate,子活动中的@inject字段会自动注入?
答案 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
。
您需要修改DaggerActivity
。 Activities
扩展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):
以下是成员注入方法的工作原理:
- 您可以为其类层次结构中任何位置
@Inject
的任何类型创建成员注入方法。如果没有,你会得到一个 错误。- 将注入整个类型层次结构中的所有
@Inject
ed成员:参数类型和所有超类型。- 对于参数类型的子类型,不会有
醇>@Inject
个成员。
此问题已在here和here中进行了讨论,请跟进这些问题以获取更新。但它不太可能很快改变,因为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> { *; }
遵守您的规则,以便按照组件中的方式保留注入方法