我可以在使用 dagger2 进行依赖注入时只注入 super class 吗?
Can I just inject super class when use dagger2 for dependency injection?
我在 android 应用程序中使用 Dagger2 作为 DI。我发现我必须为每个使用 @Inject 字段的 class 编写注入方法。有没有一种方法可以只注入父 class,这样我就不必在每个子 class 上调用注入?
以 Activity 为例。我有一个 BaseActivity
,每个 Activity 都从中扩展。有没有一种方法可以让我在组件中为 BaseActivity 创建一个注入方法,然后在 BaseActivity 的 onCreate 中调用注入,子活动中的@inject 字段会自动注入?
现在无法完成。
Gregory Kick 的解释(来自 here):
Here's how members injection methods work:
- You can make a members injection method for any type that has
@Inject
anywhere in its class hierarchy. If it doesn't, you'll get an
error.
- All
@Inject
ed members in the entire type hierarchy will be injected: the argument type and all supertypes.
- No members will be
@Inject
ed for subtypes of the argument type.
已讨论此问题 here and here, follow up these for updates. But it is unlikely to change soon, cause Dagger 2 is close to release。
我遇到了同样的情况。一种减轻所有活动中公共组件注入的方法如下:
1) 扩展应用程序 class 以能够创建通用组件并保留对它的引用。
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。
更新:将@Activity范围对象注入片段
在某些时候,我需要使用 custom scopes 将对象绑定到
Activity
生命周期。我决定扩展这个 post,因为它可能对某些人有所帮助。
假设你有一个 @Module class 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);
}
然后,可以像这样创建 class FragmentDagger
扩展 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
,扩展FragmentDagger
的Fragments
只有一个实现方法:
public abstract void injectFragment(ActivityComponent component);
您应该可以在任何地方重复使用 Fragments
。请注意,
ActivityDagger
中的方法 super.onCreated()
应该在组件实例化之后调用。否则,当重新创建 Activity
状态时,您将获得 NullPointerException,因为将调用 Fragment
的方法 super.onCreate()
。
您可以使用反射进行一些修改:
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);
}
}
在这种情况下,您仍然需要在组件中编写注入方法,但是您不需要在每个activity、片段、视图等中编写'inject'方法。
为什么有效?当我们在注入对象上使用 getClass()
时,将得到一个后代 class,而不是 base.
注意!如果你使用 Proguard,你需要添加 next
-keep class <ComponentClass> { *; }
遵守您的规则,以便保持组件中的注入方法
我在 android 应用程序中使用 Dagger2 作为 DI。我发现我必须为每个使用 @Inject 字段的 class 编写注入方法。有没有一种方法可以只注入父 class,这样我就不必在每个子 class 上调用注入?
以 Activity 为例。我有一个 BaseActivity
,每个 Activity 都从中扩展。有没有一种方法可以让我在组件中为 BaseActivity 创建一个注入方法,然后在 BaseActivity 的 onCreate 中调用注入,子活动中的@inject 字段会自动注入?
现在无法完成。 Gregory Kick 的解释(来自 here):
Here's how members injection methods work:
- You can make a members injection method for any type that has
@Inject
anywhere in its class hierarchy. If it doesn't, you'll get an error.- All
@Inject
ed members in the entire type hierarchy will be injected: the argument type and all supertypes.- No members will be
@Inject
ed for subtypes of the argument type.
已讨论此问题 here and here, follow up these for updates. But it is unlikely to change soon, cause Dagger 2 is close to release。
我遇到了同样的情况。一种减轻所有活动中公共组件注入的方法如下:
1) 扩展应用程序 class 以能够创建通用组件并保留对它的引用。
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。
更新:将@Activity范围对象注入片段
在某些时候,我需要使用 custom scopes 将对象绑定到
Activity
生命周期。我决定扩展这个 post,因为它可能对某些人有所帮助。
假设你有一个 @Module class 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);
}
然后,可以像这样创建 class FragmentDagger
扩展 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
,扩展FragmentDagger
的Fragments
只有一个实现方法:
public abstract void injectFragment(ActivityComponent component);
您应该可以在任何地方重复使用 Fragments
。请注意,
ActivityDagger
中的方法 super.onCreated()
应该在组件实例化之后调用。否则,当重新创建 Activity
状态时,您将获得 NullPointerException,因为将调用 Fragment
的方法 super.onCreate()
。
您可以使用反射进行一些修改:
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);
}
}
在这种情况下,您仍然需要在组件中编写注入方法,但是您不需要在每个activity、片段、视图等中编写'inject'方法。
为什么有效?当我们在注入对象上使用 getClass()
时,将得到一个后代 class,而不是 base.
注意!如果你使用 Proguard,你需要添加 next
-keep class <ComponentClass> { *; }
遵守您的规则,以便保持组件中的注入方法