首页 > 解决方案 > 您如何将由 AndroidInjector 注入的 android 对象(Service、Activity ...)重新注入其他对象?

问题描述

我有一个具有 DaggerServiceComponent 的服务,它将成功注入所有服务依赖项。

问题是我还有一个 ServiceManager 类,它需要引用 Service 才能“管理”服务任务。IE

应用

  public class ApplicationBase extends Application implements HasServiceInjector {

    @Inject
    DispatchingAndroidInjector<Service> dispatchingAndroidServiceInjector;

    protected void setupServiceComponent(Context context) {
        ServiceContextModule serviceContextModule = new ServiceContextModule(context);
        ServiceComponent serviceComponent = DaggerServiceComponent.builder().serviceContextModule(serviceContextModule).build();
        serviceComponent.inject(this);

    }


    @Override
    public AndroidInjector<Service> serviceInjector() {
        return dispatchingAndroidServiceInjector;
    }

}

零件

@Singleton
@Component(modules = {  /* modules */})
public interface ServiceComponent extends AndroidInjector<ApplicationBase > {

    ServiceManager provideServiceManager();
    void inject(ApplicationBase appBase);
    // ..
}

模块

@Module
public abstract class MediaPlaybackServiceModule {

    @ContributesAndroidInjector
    abstract MediaPlaybackService provideMediaPlaybackService();

}

MediaPlaybackService 我的服务

public class MediaPlaybackService extends MediaBrowserServiceCompat {
   // ...
  private ServiceManager serviceManager;

  @Override
  public void onCreate() {
    init();
    super.onCreate();
    // ...
  }
  /**
   * TO BE CALLED BEFORE SUPER CLASS
   */
  private void init() {
    AndroidInjection.inject(this);
    serviceManager.setMediaPlaybackService(this);
  }

  //...
  // declaration of other dependencies
}

如果你看看我目前在做什么,我手动添加了对 setter 方法的调用,以在成功注入的 ServiceManager 类中设置“服务”引用。

服务管理器类如下所示:

public class ServiceManager {

    @Inject
    public ServiceManager(MediaSessionAdapter mediaSession,
                          MyNotificationManager myNotificationManager) {
        this.mediaSession = mediaSession;
        this.notificationManager = myNotificationManager;
    }

    // BODY OF CLASS

    public void setMediaPlaybackService(MediaPlaybackService mediaPlaybackService) {
        this.service = mediaPlaybackService;
    }
}

但理想情况下,我希望服务管理器构造函数看起来像

@Inject
public ServiceManager(MediaPlaybackService mediaPlaybackService, MediaSessionAdapter mediaSession,
                      MyNotificationManager myNotificationManager) {
    this.service = mediaPlaybackService;
    this.mediaSession = mediaSession;
    this.notificationManager = myNotificationManager;
}

我需要对我的 dagger2 代码进行哪些更改才能实现此目的?

注意:为简单起见,我删除了应用程序中使用的额外代码,但可以在此处找到

标签: androiddagger-2

解决方案


因此,对于所有面临与我自己类似问题的人,我已经对 dagger-android 进行了很多实验,并发现执行以下操作要简单得多:

1)使活动抽象

public abstract MainActivity extends AppCompatActivity {
  ...
  abstract void initDependencies();
  ...

  @Inject
  public void setMyDependency(MyDependency myDependency) { ... }
}

2)创建一个子类来初始化你的依赖项,从而在你的活动中删除一个匕首依赖项

public MainActivityProduction extends MainActivity  {
  @Override
  void initDependencies() {
     DaggerMainActivityComponent.factory().create(..., this)
     .inject(this);
  }
  @Override
  public void onCreate() {
    initDependencies();
    super.onCreate();
  }
}

请注意,这允许一个单独的组件可用于测试,如匕首文档https://dagger.dev/testing中建议的那样,即

public MainActivityTesting extends MainActivity  {
  @Override
  void initDependencies() {
     DaggerMainActivityTestingComponent.factory().create(..., this)
     .inject(this);
  }
  @Override
  public void onCreate() {
    initDependencies();
    super.onCreate();
  }
}

3)因此,您的组件将如下所示:

@Component(modules = { /* modules */})
public interface MainActivityComponent {
  ...
  @Component.Factory
  interface Factory {
    MainActivityComponent create(...,
                    @BindsInstance MainActivity);
  }
}

这意味着您可以让任何模块引用您的 MainActivity

@Module
public class MyDependencyModule {

  @Provides
  public MyDependency providesMyDependency(MainActivity MainActivity) {
     return new MyDependency(mainActivity);
  }
}

这个解决方案:

  1. 将样板设置代码与主代码分离
  2. 允许轻松注入测试实现
  3. 删除对 Application 类的依赖以设置您的依赖项。

推荐阅读