Как повторно внедрить объект Android (Service, Activity ...), в который AndroidInjector вводится, в другие объекты? - PullRequest
0 голосов
/ 25 июня 2019

У меня есть служба с DaggerServiceComponent, которая будет успешно внедрять все зависимости служб.

Проблема в том, что у меня также есть класс ServiceManager, для которого требуется ссылка на службу для «управления«сервисные задачи.т.е.

Приложение

  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 MyService

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
}

Если вы посмотрите на то, что я сейчас делаю, я вручную добавляю вызов метода set для установки ссылки «service» в классе 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 былв состоянии достичь этого?

ПРИМЕЧАНИЕ: для простоты я удалил дополнительный код, используемый в приложении, но его можно найти здесь

1 Ответ

0 голосов
/ 02 июля 2019

Так что для всех тех, кто сталкивается с подобной для меня проблемой, я много экспериментировал с 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 для настройки ваших зависимостей.
...