Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using Dagger Multibinding across Gradle modules

Fellow Dagger users...am I trying to do something impossible? Below is a degraph generated Gradle module view of my app.

modular-android-app

Imagine my app has a navigation drawer. I want the list items in the drawer to be added based on a collection populated via a multibinding. The contributors to this multibinding are across > 1 Gradle module. For example, a list item called "Account" is added from the user module, a 2nd item called "Terms & Conditions" is added from the legal module and a "Search" navigation entry is added from the search Gradle module. These modules can be thought of as stand-alone apps that when bundled together form the complete app experience. They are runnable on their own.

The Dagger documentation on this looks like a copy-paste of the Guice but with one big complication. It states;

"Dagger allows you to bind several objects into a collection even when the objects are bound in different modules using multibindings. "

...but it means Dagger @Modules, right? Is it possible to populate a multibinding across Gradle modules? I've tried something akin to this and it wasn't what I expected (not all contributions were collected);

Parent app

@Module
abstract class PluginModule {
  @Multibinds @NavigationContribution abstract Set<NavigationEntry> navigables();
}

legal Gradle module that contains the Dagger @Module

@Module
class LegalModule {
  @Provides
  @NavigationContribution 
  @IntoSet
  static NavigationEntry provideLegalNavigation() {
    return ...;
  }
}

user Gradle module that contains the Dagger @Module

@Module
class AccountModule {
  @Provides
  @NavigationContribution 
  @IntoSet
  static NavigationEntry provideAccountNavigation() {
    return ...;
  }
}

Upon running the app only the contributions under the app 'context' are available upon calling;

@Inject @NavigationContribution Set<NavigationEntry> navigationEntries();

The other contributions can be accessed but 'manually' by getting hold of the dagger.Component of the child Gradle module and exposing a method to get the entries back.

This defeats the purpose of the multibinder for my application. Is this possible? If not, why?

Update: triage with Jeff

enter image description here

So, the top-level module annotations look like this;

@ApplicationLifecycle
@Component(
    modules = {
        OceanLifeModule.class,
        AddSpotActivityModule.class,
        ModelModule.class,
        PluginModule.class
    },
    dependencies = {
        NavigationComponent.class,
        LegalComponent.class,
        PreferenceComponent.class,
        DomainComponent.class
    }
)
like image 627
BrantApps Avatar asked Oct 30 '22 06:10

BrantApps


1 Answers

@jeff-bowman - all I was missing here was the includes = {} on the PluginModule. A blog post by Zac Sweers on the same topic here pointed me in the right direction.

like image 197
BrantApps Avatar answered Nov 10 '22 13:11

BrantApps