android - Dagger 2 : Injecting to Activities from multiple subcomponents

标签 android dependency-injection dagger-2

This tutorial在一个非常简单的示例中展示了如何使用 Dagger 2 的 AndroidInjectionModule 将依赖项注入(inject) Activity 。我的用例有点复杂:

  • App extends Application implements HasDispatchingActivityInjector,
  • ActivityOne 使用 ActivityModule 进行初始化。使用此 Activity ,创建依赖项 DepOne
  • ActivityTwo 具有依赖项 DepTwo,如果没有预先存在的 DepOne 则无法正确初始化。

我想到的解决方案是:

  • 创建一个AppComponent作为应用的主要组件,
  • 创建一个 ComponentTwo 作为 AppComponent 的子组件。在运行时添加它,只要 DepOne 可用,并在其中提供 DepTwo
  • ComponentTwo 中注入(inject) ActivityTwo

然而,这需要 ActivityModule,目前看起来是这样的:

@Module(subcomponents = {
    ActivityOneSubcomponent.class,
    ActivityTwoSubcomponent.class
})
public abstract class ActivityModule {
    @Binds
    @IntoMap
    @ActivityKey(ActivityOne.class)
    abstract AndroidInjector.Factory<? extends Activity> bindLoginActivityInjectorFactory(ActivityOneSubcomponent.Builder builder);

    @Binds
    @IntoMap
    @ActivityKey(ActivityTwo.class)
    abstract AndroidInjector.Factory<? extends Activity> bindWorldActivityInjectorFactory(ActivityTwoSubcomponent.Builder builder);
}

分成两个不同的模块,一个用于 ActivityOne 并与 AppComponent 绑定(bind),另一个用于 ActivityTwo(以及其他 future Activity ) 与 ComponentTwo 绑定(bind)。

我这样做了,但是 Dagger 在尝试注入(inject) ActivityTwo 时在运行时抗议:

Caused by: java.lang.IllegalArgumentException: No injector factory bound for Class<ActivityTwo>

应用程序似乎看不到添加的子组件提供的注入(inject)器工厂。

有什么想法/提示吗?


编辑:我根据要求在下面发布了重现代码(那里实际上没有 Dagger 可注入(inject)的属性,因为我把它们刮掉了):

ActivityOne.java

public class ActivityOne extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        AndroidInjection.inject(this);
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_login);

        enterPartTwo();
    }

    private void enterPartTwo() {
        App.app(this).makeComponentTwo();
        ActivityTwo.start(this);
        finish();
    }
}

ActivityOneModule.java

@Module(subcomponents = {
        ActivityOneSubcomponent.class
})
public abstract class ActivityOneModule {
    @Binds
    @IntoMap
    @ActivityKey(ActivityOne.class)
    abstract AndroidInjector.Factory<? extends Activity> bindActivityOneInjectorFactory(ActivityOneSubcomponent.Builder builder);
}

ActivityOneSubcomponent.java

@Subcomponent
public interface ActivityOneSubcomponent extends AndroidInjector<ActivityOne> {
    @Subcomponent.Builder
    abstract class Builder extends AndroidInjector.Builder<ActivityOne> {}
}

ActivityTwo.java

public class ActivityTwo extends AppCompatActivity {
    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        AndroidInjection.inject(this);
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_world);
    }

    public static void start(Context from) {
        Intent intent = new Intent(from, ActivityTwo.class);
        from.startActivity(intent);
    }
}

ActivityTwoModule.java

@Module(subcomponents = {
        ActivityTwoSubcomponent.class
})
public abstract class ActivityTwoModule {
    @Binds
    @IntoMap
    @ActivityKey(ActivityTwo.class)
    abstract AndroidInjector.Factory<? extends Activity> bindActivityTwoInjectorFactory(ActivityTwoSubcomponent.Builder builder);
}

ActivityTwoSubcomponent.java

@Subcomponent
public interface ActivityTwoSubcomponent extends AndroidInjector<ActivityTwo> {
    @Subcomponent.Builder
    abstract class Builder extends AndroidInjector.Builder<ActivityTwo> {}
}

App.java

public class App extends Application implements HasDispatchingActivityInjector {
    @Inject
    DispatchingAndroidInjector<Activity> dispatchingAndroidInjector;
    AppComponent appComponent;
    ComponentTwo componentTwo;

    @Override
    public void onCreate() {
        super.onCreate();
        appComponent = DaggerAppComponent.create();
        appComponent.inject(this);
    }

    @Override
    public DispatchingAndroidInjector<Activity> activityInjector() {
        return dispatchingAndroidInjector;
    }

    public void makeComponentTwo() {
        componentTwo = appComponent.inGameComponent()
                .build();
    }

    public static App app(Context context) {
        return (App) context.getApplicationContext();
    }
}

AppComponent.java

@Singleton
@Component(modules = {ActivityOneModule.class,
        AndroidInjectionModule.class})
public interface AppComponent {
    void inject(App app);

    ComponentTwo.Builder inGameComponent();
}

ComponentTwo.java

@ScopeTwo
@Subcomponent(modules = {ActivityTwoModule.class})
public interface ComponentTwo {
    @Subcomponent.Builder
    interface Builder {
        ComponentTwo build();
    }
}

ScopeTwo.java

@Qualifier
@Retention(RetentionPolicy.RUNTIME)
public @interface ScopeTwo {
}

堆栈跟踪:

E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.example.abc, PID: 5923
java.lang.RuntimeException: Unable to start activity ComponentInfo{com.example.abc/com.example.abc.ActivityTwo}: java.lang.IllegalArgumentException: No injector factory bound for Class<com.example.abc.ActivityTwo>
   at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2416)
   at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2476)
   at android.app.ActivityThread.-wrap11(ActivityThread.java)
   at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1344)
   at android.os.Handler.dispatchMessage(Handler.java:102)
   at android.os.Looper.loop(Looper.java:148)
   at android.app.ActivityThread.main(ActivityThread.java:5417)
   at java.lang.reflect.Method.invoke(Native Method)
   at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:726)
   at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616)
Caused by: java.lang.IllegalArgumentException: No injector factory bound for Class<com.example.abc.ActivityTwo>
   at dagger.android.DispatchingAndroidInjector.inject(DispatchingAndroidInjector.java:105)
   at dagger.android.AndroidInjection.inject(AndroidInjection.java:61)
   at com.example.abc.ActivityTwo.onCreate(ActivityTwo.java:22)
   at android.app.Activity.performCreate(Activity.java:6237)
   at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1107)
   at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2369)
   at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2476) 
   at android.app.ActivityThread.-wrap11(ActivityThread.java) 
   at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1344) 
   at android.os.Handler.dispatchMessage(Handler.java:102) 
   at android.os.Looper.loop(Looper.java:148) 
   at android.app.ActivityThread.main(ActivityThread.java:5417) 
   at java.lang.reflect.Method.invoke(Native Method)

希望对回答问题有所帮助。

最佳答案

让 ActivityTwo 实现 HasSupportFragmentInjector

public class ActivityTwo extends AppCompatActivity implements HasSupportFragmentInjector {

@Inject
DispatchingAndroidInjector<Fragment> fragmentDispatchingAndroidInjector;

@Override
protected void onCreate(Bundle savedInstanceState) {
AndroidInjection.inject(this);
super.onCreate(savedInstanceState);

}

@Inject
DispatchingAndroidInjector<Fragment> fragmentDispatchingAndroidInjector;

@Override
public AndroidInjector<Fragment> supportFragmentInjector() {
    return fragmentDispatchingAndroidInjector;
}
} // end of class

其次,对于小型实现而言,您的样板代码太多了。使用@ContributesAndroidInjector 为您的 Activity 创建子组件。使用这篇文章可以最简单地实现此 https://medium.com/@idee4ril/dagger-2-11-with-android-a606c132826c

关于android - Dagger 2 : Injecting to Activities from multiple subcomponents,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43952252/

相关文章:

java - 如何在由六个三角形条组成的矩形上显示纹理(opengl es)

java - Android Studio - 未安装 HAX 内核模块

Symfony TwigBundle 不加载任何自定义扩展

java - 适当设计全局数据访问和修改

android - 使用 kapt 时,Dagger 会跳过 Google 服务模块的工厂生成

android - Dagger 不为 androidTest 生成组件类

android - 在 appComponent dagger 2 中动态添加测试模块?

android - 单独的圆角(不是所有角)

android - 以编程方式设置 BOTTOM 和 CENTER 的重力

c# - 关于使用 Ninject 的问题