Как получить MainActivity внутри модуля с помощью AndroidInjector

С помощью dagger-android теперь можно просто написать следующее и успешно внедрить зависимости приложения:

@Module
public abstract class MainActivityModule {
  @ContributesAndroidInjector
  abstract MainActivity contributesMainActivity();
}

@Singleton
@Component(modules = {
    AndroidSupportInjectionModule.class,
    AndroidInjectionModule.class,
    AppModule.class,
    MainActivityModule.class
})
public interface ApplicationComponent {
  void inject(BaseApplication baseApplication);

  @Component.Builder
  interface Builder {
    @BindsInstance
    Builder application(Application application);

    ApplicationComponent build();
  }
}

@Module
public abstract class AppModule {}

public class MainActivity extends AppCompatActivity implements 
  HasSupportFragmentInjector {
  @Inject
  DispatchingAndroidInjector<Fragment> dispatchingAndroidInjector;
  @Inject
  Whatever whatever;

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

  @Override
  public AndroidInjector<Fragment> supportFragmentInjector() {
    return dispatchingAndroidInjector;
  }
}


public class BaseApplication extends Application implements 
  HasActivityInjector {
  @Inject
  DispatchingAndroidInjector<Activity> dispatchingAndroidInjector;

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

  @Override
  public void onCreate() {
    DaggerApplicationComponent.builder()
            .application(this)
            .build()
            .inject(this);
    super.onCreate();
  }
}

public class Whatever {
   private final FragmentManager fragmentManager;

   @Inject
   Whatever(MainActivity mainActivity) {
    this.fragmentManager = mainActivity.getSupportFragmentManager();
   }
}

Очень тривиальный пример. В основном подключите все, чтобы иметь возможность получить объект Whatever с правильным внедренным менеджером фрагментов. Это нормально и работает.

Однако что, если я хочу использовать основную активность внутри модуля? Скажем, я хочу сделать так, чтобы Whatever явно выставляла зависимость диспетчеру фрагментов, изменив аргумент конструктора:

@Inject
Whatever(FragmentManager fragmentManager) {...}

Теперь мне нужно предоставить эту зависимость. Как это сделать? Итак, я пробовал следующее:

@Module
public abstract class MainActivityModule {
  @ContributesAndroidInjector
  abstract MainActivity contributesMainActivity();

  @Provides
  static FragmentManager providesFragmentManager(MainActivity activity) {
     return activity.getSupportFragmentManager();
  }
}

Теперь кинжал жалуется, что не может найти @Providers для MainActivity. Я думал, что метод @ContributesAndroidInjector сможет обеспечить активность. Я также немного озадачен тем, как у него не было проблем с внедрением зависимости в первом случае, но теперь он не может этого сделать.

Я также пытался построить для этого фабрику, например:

public FragmentManagerFactory {
   private final FragmentManager fm;

   @Inject
   FragmentManagerFactory(MainActivity mainActivity){
     this.fm = mainActivity.getSupportFragmentManager();
   }

   public FragmentManager get() {
     return fm;
   }
}

@Module
public abstract class MainActivityModule {
  @ContributesAndroidInjector
  abstract MainActivity contributesMainActivity();

  @Provides
  static FragmentManager providesFragmentManager(FragmentManagerFactory fragmentManagerFactory) {
     return fragmentManagerFactory.get();
  }
}

Что заканчивается той же ошибкой.

Кому-нибудь удалось это сделать?? Раньше это было довольно просто, можно было просто построить модуль с экземпляром MainActivity, сохранить его в поле и предоставить его. Теперь... все происходит за кулисами.

Был бы очень признателен за помощь!


person Fred    schedule 27.07.2017    source источник
comment
До того, как это было довольно просто, можно было просто создать модуль с экземпляром MainActivity, сохранить его в поле и предоставить его.. Вы все еще можете сделать это, используя @Subcomponent для MainActivity   -  person Blackbelt    schedule 27.07.2017
comment
Хочешь опубликовать пример? Такое ощущение, что это противоречит цели использования AndroidInjector   -  person Fred    schedule 27.07.2017


Ответы (1)


В моей настройке у меня есть пакет di/ в корне sub-di-packages в моем пакете ui/. В пакете ui/di я объявил следующий модуль и компонент:

@dagger.Module
public class MainActivityModule {
   @Provides
   FragmentManager provideFragmentManager(MainActivity mainActivity) {
    return mainActivity.getSupportFragmentManager();
   }
}

Подкомпонент MainActivity

@Subcomponent(modules = MainActivityModule.class)
public interface MainActivitySubcomponent  extends AndroidInjector<MainActivity> {

    @Subcomponent.Builder
    abstract class Builder extends AndroidInjector.Builder<MainActivity> {
    }
}

в пакете di верхнего уровня, где я храню свой ApplicationComponent, у меня есть дополнительный module

@Module(subcomponents = {MainActivitySubcomponent.class })
public abstract class BuildersModule {

   @Binds
   @IntoMap
   @ActivityKey(MainActivity.class)
   abstract AndroidInjector.Factory<? extends Activity> mainActivityBinder(MainActivitySubcomponent.Builder builder);

}

И, как вы понимаете, BuildersModule является частью @Component(modules = { из ApplicationComponent.


Отказ от ответственности: Я новичок в dagger2 и все еще пытаюсь разобраться во многих вещах. Возможно, есть лучшие способы добиться того, что вам нужно.

person Blackbelt    schedule 27.07.2017
comment
Хорошо, спасибо! И как вы собираетесь внедрять основную активность? Вы все еще используете AndroidInjector.inject(this) или создаете компоненты вручную? - person Fred; 27.07.2017
comment
С AndroidInjector.inject(this). У меня есть базовый класс, который расширяет каждое вводимое действие. - person Blackbelt; 27.07.2017
comment
Еще раз, большое спасибо. Я попробовал, но с этим решением я получаю ошибку времени выполнения, когда я вызываю AndroidInjection.inject(this) в основном действии. Исключение говорит, что MainActivityModule должен быть установлен. Вы сами пробовали? - person Fred; 27.07.2017
comment
Извините за это, моя ошибка. Я сохранил MainActivityModule реферат. Большое спасибо! - person Fred; 27.07.2017
comment
простое решение! Потрясающий - person Vlad; 13.10.2017