0

I want to replace our component registry (with dexfile class loader magic) with an dependency injection framework for Android. The first try is dagger.

When trying I get the following error:

11-06 13:05:41.040  16269-16269/com.daggertoolkitexample E/AndroidRuntime﹕ FATAL EXCEPTION: main
java.lang.RuntimeException: Unable to start activity ComponentInfo{daggertoolkitexample/com.dagger.MyActivity}: java.lang.IllegalArgumentException: No inject registered for members/com.dagger.MyActivity. You must explicitly add it to the 'injects' option in one of your modules.
        at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2295)
        ...
 Caused by: java.lang.IllegalArgumentException: No inject registered for members/com.dagger.MyActivity. You must explicitly add it to the 'injects' option in one of your modules.
        at dagger.ObjectGraph$DaggerObjectGraph.getInjectableTypeBinding(ObjectGraph.java:302)
        at dagger.ObjectGraph$DaggerObjectGraph.inject(ObjectGraph.java:279)
        at com.dagger.MyApplication.inject(MyApplication.java:39)
        at com.dagger.MyBaseActivity.onCreate(MyBaseActivity.java:18)
        at com.dagger.MyActivity.onCreate(MyActivity.java:22)
        at android.app.Activity.performCreate(Activity.java:5372)
        at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1104)
        ...

I can fix it if i inject my activity in the @Module. Its work without exception.

@Module(
    library = true,
    injects = MyActivity.class)
public class AuthManagementModul {...}`

But this is not that i want. I don´t can and want to know all users of my component.

Has everyone an idea what's wrong?

Here is my example code:

public class MyBaseActivity extends ActionBarActivity {

  @Override protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    ((MyApplication) getApplication()).inject(this);
  }
}

...

public class MyActivity extends MyBaseActivity {

  @Inject AuthManagement authManagement;

  ...
}

...

public class MyApplication extends Application{

  private ObjectGraph graph;

  @Override
  public void onCreate() {
    super.onCreate();
    graph = ObjectGraph.create(new AuthManagementModul(this));
  }

  public void inject(Object object) {
    graph.inject(object);
  }
}

...

@Module(
    library = true
)
public class AuthManagementModul {

  private final Application application;

  public AuthManagementModul(Application application) {
    this.application = application;
  }

  @Provides
  @Singleton
  AuthManagement provideAuthManagement() {
    return new AuthManagementImpl(application);
 }
}
Christian Gruber
  • 4,691
  • 1
  • 28
  • 28
Marko
  • 21
  • 6

1 Answers1

0

In this case, you don't want to add injects= to your AuthManagementModul, but rather to an activity-specific module which includes it.

Dagger 1.x uses injects= as a signal for what graph-roots to analyze, so they must be present -but they need not be present on leaf-node library modules - just on a module the activity uses. Consider breaking up your modules on more partitioned lines like so:

@Module(
  injects = {
    ... all your activities
  },
  includes = {
    AuthManagementModul.class,
    ApplicationModule.class
  }
)
class EntryPointsModule {}

@Module(library = true, complete = false)
class AuthManagementModul {
  @Provides
  @Singleton
  AuthManagement provideAuthManagement(Application application) {
    return new AuthManagementImpl(application);
  }
}

@Module(library = true)       
class ApplicationModule {

  private final Application application;

  public ApplicationModule(Application application) {
    this.application = application;
  }

  @Provides
  @Singleton
  Application application() {
    return application;
  }
}

Then create your graph like so:

public class MyApplication extends Application{

  private ObjectGraph graph;

  @Override
  public void onCreate() {
    super.onCreate();
    // AuthManagementModul is automatically included because it has a default 
    // constructor and is included by EntryPointsModule
    graph = ObjectGraph.create(new EntryPointsModule(), new ApplicationModule(this));
  }

  public void inject(Object object) {
    graph.inject(object);
  }
}

There are other ways to structure this - you could just have ApplicationModule include the AuthModule and declare injects, so you only have two modules, etc. I suggested this way because ApplicationModule is then a separate concern whose only role is to hoist the Application instance into the graph, AuthManagementModul is exclusively there to support the auth function, and EntryPointsModule is there to be the front of the whole graph.

If you migrate to Dagger2, this structure is also convenient in that EntryPointsModule naturally converts to a @Component.

Christian Gruber
  • 4,691
  • 1
  • 28
  • 28