question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

@ContributesAndroidInjector: strange code generation and error - Module must be set

See original GitHub issue

Hi! I’m trying to inject activity dependencies into fragment presenter. App structure is very simple.

TabsActivity - viewpager – TabFragment - page item – […]

TabsActivity shows view TabsActivityModule - provides FragmentManager (for example) and some stuff for TabsActivity TabFragmentModule provides stuff for TabFragment. Every TabFragment has own Presenter. Presenter injects TabActivityModule dependencies. In my case - Presenter injects FragmentManager

Here is code:

Application class

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

    @Override
    public AndroidInjector<Activity> activityInjector() {
        return dispatchingAndroidInjector;
    }
   /*
   blah blah creating app component onCreate() ...
   DaggerAppComponent
                .builder()
                .context(this)
                .build()
                .inject(this);
   */ 
}

Root application component

@Singleton
@Component(modules = {InjectorsModule.class})
public interface AppComponent {

    @Component.Builder
    interface Builder {
        @BindsInstance
        Builder context(Context context);

        AppComponent build();
    }

    void inject(App app);
}

Here is android views contributors InjectorsModule

@Module(includes = {AndroidSupportInjectionModule.class})
public abstract class InjectorsModule {

    @ActivityScope
    @ContributesAndroidInjector(modules = {TabsActivityModule.class})
    abstract TabsActivity tabsActivityInjector();
}

Activity TabsActivityModule

@Module
public abstract class TabsActivityModule {

    @Provides
    @ActivityScope
    public FragmentManager provideFragmentManager(TabsActivity activity) {
        return activity.getFragmentManager();
    }

    @Provides @Named("activity")
    @ActivityScope
    public Context provideActivityContext(TabsActivity activity) {
        return activity;
    }

    // Here contributes tab fragment
    @FragmentScope
    @ContributesAndroidInjector(modules = {TabFragmentModule.class})
    public abstract TabFragment tabFragment();
}

Fragment TabFragmentModule

@Module
public abstract class TabFragmentModule {
    @Provides @Named("answer")
    @FragmentScope
    public int provideSomeInt() {
        return 42;
    }
}

And last, just for example - TabPresenter

public class TabPresenter {
    @Inject @Named("answer") int mAnswer;
    @Inject @Named("activity") mActivityContext;
    @Inject FragmentManager mFragmentManager;

    @Inject
    public TabPresenter() {}

    public void doNothingWithAnswerAndContextAndFragmentManager() {
        mAnswer *= 1;
    }
}

After this all, build finishes with success status. But at runtime, i’m getting InvalidStateException immediately while fragment injects: fragment

onAttach(Activity activity) {
    AndroidInjection.inject(this);
    super.onAttach(activity);
} 

Exception stacktrace:

FATAL EXCEPTION: main
Process: com.example.drive.dagger2new, PID: 3064
 java.lang.RuntimeException: 
Unable to start activity 
ComponentInfo{com.example.drive.dagger2new/com.example.ui.TabsActivity}:
java.lang.IllegalStateException:
com.example.dagger.modules.main.TabsActivityModule must be set

 at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2680)
 at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2741)
 at android.app.ActivityThread.-wrap12(ActivityThread.java)
 at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1488)
 at android.os.Handler.dispatchMessage(Handler.java:102)
 at android.os.Looper.loop(Looper.java:154)
 at android.app.ActivityThread.main(ActivityThread.java:6169)
 at java.lang.reflect.Method.invoke(Native Method)
 at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:888)
 at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:778)

Caused by: java.lang.IllegalStateException: com.example.dagger.modules.main.TabsActivityModule must be set
 at com.example.dagger.components.DaggerAppComponent$TabsActivitySubcomponentBuilder.build(DaggerAppComponent.java:116)
 at com.example.dagger.components.DaggerAppComponent$TabsActivitySubcomponentBuilder.build(DaggerAppComponent.java:106)
 at dagger.android.AndroidInjector$Builder.create(AndroidInjector.java:68)
 at dagger.android.DispatchingAndroidInjector.maybeInject(DispatchingAndroidInjector.java:79)
 at dagger.android.DispatchingAndroidInjector.inject(DispatchingAndroidInjector.java:104)
 at dagger.android.AndroidInjection.inject(AndroidInjection.java:61)
 at com.example.base.BaseActivity.onCreate(BaseActivity.java:35)
 at com.example.ui.TabsActivity.onCreate(TabsActivity.java:13)
 at android.app.Activity.performCreate(Activity.java:6679)
 at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1118)
 at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2633)
 at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2741) 
 at android.app.ActivityThread.-wrap12(ActivityThread.java) 
 at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1488) 
 at android.os.Handler.dispatchMessage(Handler.java:102) 
 at android.os.Looper.loop(Looper.java:154) 
 at android.app.ActivityThread.main(ActivityThread.java:6169) 
 at java.lang.reflect.Method.invoke(Native Method) 
 at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:888) 
 at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:778) 

After looking at this, i though, that i just forget to set some new module instance. But, I don’t doing this, because @ContributesAndroidInjector do it for me. Ok, when i look at generated code, i saw that TabsActivitySubcomponentBuilder does not have a setter for TabsActivityModule.

private final class TabsActivitySubcomponentBuilder
      extends InjectorsModule_TabsActivityInjector.TabsActivitySubcomponent.Builder {
    private TabsActivityModule tabsActivityModule;

    private TabsActivity seedInstance;

    @Override
    public InjectorsModule_TabsActivityInjector.TabsActivitySubcomponent build() {
      if (tabsActivityModule == null) {
// Exceptions throws here
        throw new IllegalStateException(
            TabsActivityModule.class.getCanonicalName() + " must be set");
      }
      if (seedInstance == null) {
        throw new IllegalStateException(TabsActivity.class.getCanonicalName() + " must be set");
      }
      return new TabsActivitySubcomponentImpl(this);
    }

    // here we seeing setter for activity
    @Override
    public void seedInstance(TabsActivity arg0) {
      this.seedInstance = Preconditions.checkNotNull(arg0);
    }

   // and for module??
  }

And finally, AndroidInjector.Builder sets only activity instance:

abstract class Builder<T> implements AndroidInjector.Factory<T> {
    @Override
    public final AndroidInjector<T> create(T instance) {
// here
      seedInstance(instance);
// and here must be seedModule(module), but nothing
      return build();
    }

    /**
     * Provides {@code instance} to be used in the binding graph of the built {@link
     * AndroidInjector}. By default, this is used as a {@link BindsInstance} method, but it may be
     * overridden to provide any modules which need a reference to the activity.
     *
     * <p>This should be the same instance that will be passed to {@link #inject(Object)}.
     */
    @BindsInstance
    public abstract void seedInstance(T instance);

    /** Returns a newly-constructed {@link AndroidInjector}. */
    public abstract AndroidInjector<T> build();
  }

Sorry for so long answer, maybe i don’t understand something? Thanks!

Issue Analytics

  • State:closed
  • Created 6 years ago
  • Comments:5

github_iconTop GitHub Comments

1reaction
ronshapirocommented, Sep 8, 2017

Ah, there’s an issue for this already. You can fix your code by making your @Provides methods static.

0reactions
edwardstockcommented, Sep 8, 2017

@ronshapiro Works like magic! Thank you!

Read more comments on GitHub >

github_iconTop Results From Across the Web

Dagger @ContributesAndroidInjector ComponentProcessor ...
I've had a very weird error when converting a Module file to ... Check for compilation errors or a circular dependency with generated...
Read more >
Dagger 2 with ContributesAndroidInjector - Is it easy? - Medium
Module that returns a concrete Android framework type. The method should have no parameters.” This annotation will generate an AndroidInjector< ...
Read more >
[Solved]-Dagger/MissingBinding but module exists-kotlin
INotificationService is ViewModel dependency and it should bind with ViewModel lifecycle so instead of this @Module @InstallIn(ActivityComponent::class) ...
Read more >
Dagger - What's the one thing you struggle with the most when ...
Modules specified in the @ContributesAndroidInjector can reference it. ... Code generation is always suck when something goes wrong.
Read more >
Diff - platform/packages/apps/TV - Google Git
-The following files are only in the android repository and must be ... unless the is_compiled_selector parameter was set during + * code...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found