简体   繁体   中英

Can't successfully provide dependency using Hilt

I'm new to Hilt. I want to provide DataRepository for ViewModel . My code in AppModule is:

@Module
@InstallIn(SingletonComponent::class)
object AppModule {

    @Singleton
    @Provides
    fun provideDataRepository(): DataRepository {
        return DataRepository()
    }
}

And then I want to inject it to the constructor of ViewModel like private val dataRepository: DataRepository but I'm getting No value passed for parameter 'FeaturesApi' because FeaturesApi is dependecy of DataRepository . What I want to do is just simply inject dependency without passing any values. How can I do it?

Before using Hilt you should really try and understand how Dagger works. Since, Hilt is built on top of Dagger!

So, Dagger requires you to provide a dependency graph. Which means for each class which is injectable (using Dagger or Hilt) you must also provide a way for Dagger to create instances of its dependencies as well.

Considering the scenario posted in the OP. We have,

class DataViewModel(val dataRepository: DataRepository): ViewModel() {
}

&

class DataRepository(val featuresApi: FeaturesApi) {
}

As you have pointed out yourself featuresApi is a dependency of DataRepository and Dagger has no way of knowing how to create FeaturesApi object.

Now, Dagger provides three ways for you to tell it, how to create an instance of any class/type.

  1. @Inject

You can use @Inject annotation on a constructor of a class defined in your own code to tell Dagger how to create that object. Like so:

class DataRepository: @Inject constructor(
    private val featuresApi: FeaturesApi
)

Which will act similar to:

@Module
@InstallIn(SingletonComponent::class)
object AppModule {

    @Singleton
    @Provides
    fun provideDataRepository(): DataRepository {
        return DataRepository()
    }
}

Note that there must only be a singular @Inject annotated constructor in any given class , since providing multiple @Inject annotated constructors will confuse Dagger on which constructor to use.

  1. @Provides

You are already familiar with this annotation which can be used in a @Module annotated class .

This annotation is usually reserved to provide Dagger a way to create instances of classes/types which are not editable for you (Usually library classes or objects created by a library). Which in this case will be, assuming your FeaturesApi object is created by Retrofit (which is the most popular networking library in Android).

So, by rewriting your AppModule class a bit:

@Module
@InstallIn(SingletonComponent::class)
object AppModule {

    @Singleton
    @Provides
    fun provideFeaturesApi(retrofit: Retrofit): FeaturesApi {
        return retrofit.create(FeaturesApi::class.java)
    }
}

And now Dagger knows how to create a features FeaturesApi object.

Note: At this point in your code you'd notice that you've now introduced a dependency for FeaturesApi ie Retrofit . So, now you must also provide a way for Dagger to know how to create Retrofit instance. Otherwise Dagger will throw a similar error to No value passed for parameter 'Retrofit' .

I'm leaving out the third way for you to figure out and study since that is not related to this question.


Further Notes:

  • These annotations (with the exception of @InstallIn ) are in no way related to Hilt but are infact used by Dagger .
  • Also note that the better approach to access lower level objects (in this case DataRepository ) is through an interface .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM