How to get MainActivity inside module using AndroidInjector

With the help, dagger-android

you can simply write the following and successfully inject the application dependencies:

@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();
   }
}

      

A very trivial example. Basically hook everything up to be able to get the object Whatever

with the correct fragment manager. This is fine and works.

However, what if I want to use the main activity inside the module? Let's say I want to Whatever

explicitly display the dependency with the fragment manager by changing the constructor argument:

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

      

Now I have to provide this dependency. How can I do that? So I tried the following:

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

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

      

Now the dagger complains that he cannot find it @Providers

for MainActivity

. I thought the method @ContributesAndroidInjector

would be able to provide activity. I am also a bit puzzled about how it has no problem with dependency injection in the first case, but now it cannot do it.

I also tried to create a factory for this, for example:

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();
  }
}

      

The end ends with the same error.

Has anyone been able to do this? Before this was pretty straightforward, one could just build a module with an instance, MainActivity

save it in a field and provide that. Now ... everything happens behind the curtains.

Would be grateful for your help!

+3


source to share


1 answer


In my setup, I have a package di/

at the root sub-di-packages

in my package ui/

. In the package, ui/di

I have declared the following module and component:

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

      

MainActivitySubcomponent

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

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

      

in the di

top-level package where I save ApplicationComponent

mine, I have an additionalmodule



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

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

}

      

And as you can imagine BuildersModule

, is part @Component(modules = {

of ApplicationComponent

.


Disclaimer: <Sub> I'm new to dagger2 and I am still trying to find a lot of stuff. There may be better ways to achieve what you need. sub>

+7


source







All Articles