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.

Hilt: Question, How to reuse a module and provide its bindings

See original GitHub issue

We are trying out Hilt for our production project, we have a use case that I’m not sure how Hilt would handle it This is our approach towards providing different bindidngs when resuing a module:

Note I simplified the code below our actual use case has lots of modules and using Qulifiers is not convenient

@Module
class WidgetListModule {

    @Provides
    @FragmentScope
    fun provideCategoryViewModelFactory(
        widgetListDataSource: WidgetListDataSource<*>, // Not provided anywhere, user should provide it
        compositeDisposable: CompositeDisposable,
        threads: Threads,
        alak: Alak,
    ): ViewModelProvider.Factory {
        return viewModelFactory {
            WidgetListViewModel(
                compositeDisposable = compositeDisposable,
                dataSource = widgetListDataSource,
                threads = threads,
                alak = alak,
            )
        }
    }
}

The module that includes this module

@Module(includes = [WidgetListModule::class])
class ManageModule {

    @Provides
    @FragmentScope
    fun provideWidgetListDataSource(
        api: ManagePostAPI
    ): WidgetListDataSource<*> {
        return WidgetListGetDataSource(api::getPage)
    }
}
@FragmentScope
@Subcomponent(modules = [ManageModule::class])
interface ManageFragmentInjector {
    fun inject(manageFragment: ManageFragment)
}

And we have cases that the injector being used to inject a field is determined at run time like this:

override fun inject() {
        if (args.source == "foo") {
            mainActivityComponent.fooFragmentInjector()
                .inject(this)
        } else {
            mainActivityComponent.barFragmentInjector()
                .inject(this)
        }
    }

So my question is how can I resuse a module and provide its dependencies with hilt?

Issue Analytics

  • State:closed
  • Created 3 years ago
  • Comments:7

github_iconTop GitHub Comments

1reaction
MRezaNasirloocommented, Nov 25, 2020

For anyone coming to this issue, the solution provided by @bcorso works with a bit of adjustment, since the injection has not happened yet, you will get an NPE exception if you access the fooWidgetListdataSource so you can’t have @Inject annotation on it like @Inject FooWidgetListdataSource fooWidgetListdataSource; instead, you can access your dependence with an entry point interface

override val widgetListRepository: WidgetListRepository by lazy {
        EntryPoints.get(this, ManageEntryPoint::class.java).manageRepository()
    }

    @EntryPoint
    @InstallIn(FragmentComponent::class)
    interface ManageEntryPoint {

        @Named(MANAGE)
        fun manageRepository(): WidgetListRepository
    }
1reaction
bcorsocommented, Oct 9, 2020

Yeah, this is a case where it’s possible to do with Hilt but you will loose a bit of the compile-time guarantees for that binding.

One solution is to provide the implementation from each fragment via an interface and have the @Provides method delegate to the fragment (there’s a similar use case in the migration guide, here). For example:

// Implemented by Fragments that provide a custom WidgetListdataSource.
interface HasWidgetListdataSource {
  WidgetListDataSource getWidgetListDataSource();
}

// Provides the WidgetListDataSource for a specific fragment or null if the fragment doesn't provide it
@Module
@InstallIn(FragmentComponent.class)
interface WidgetListdataSourceModule {
  @Provides
  @Nullable
  WidgetListDataSource provideWidgetListDataSource(Fragment fragment) {
    return (fragment instanceof HasWidgetListdataSource)
        ? ((HasWidgetListdataSource) fragment).getWidgetListDataSource();
        : null; // or DefaultWidgetListDataSource
  }
}

// Provides FooWidgetListdataSource to any dependency requesting WidgetListdataSource
class FooFragment extends HasWidgetListdataSource {
  @Inject FooWidgetListdataSource fooWidgetListdataSource;

  @Override
  WidgetListDataSource getWidgetListDataSource() {
    return fooWidgetListdataSource;
  }
}

// Provides BarWidgetListdataSource to any dependency requesting WidgetListdataSource
class BarFragment extends HasWidgetListdataSource {
  @Inject BarWidgetListdataSource barWidgetListdataSource;

  @Override
  WidgetListDataSource getWidgetListDataSource() {
    return barWidgetListdataSource;
  }
}
Read more comments on GitHub >

github_iconTop Results From Across the Web

Dependency injection with Hilt | Android Developers
Installing a module into a component allows its bindings to be accessed as a dependency of other bindings in that component or in...
Read more >
Understanding Dependency Injection with Hilt. - Nyame Bismark
@Provides is an annotation that tells Hilt how a certain binding should be provided during injections. @Module is an annotation that tells Hilt...
Read more >
How can Hilt be used effectively in multi-module apps ...
Unfortunately, Hilt uses a monolithic approach currently. This means that your app module will have access to ALL your modules.
Read more >
Hilt - Providing Retrofit Instance and Repository - YouTube
The BEST android courses in the world: https://codingwithmitch.com/In this video I show two different ways to provide objects as ...
Read more >
Frequently Asked Questions - Dagger
Only after Dagger examines each module and still cannot find an appropriate binding does it then check for the presence of @Inject constructors....
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