Search code examples
androidretrofit2kotlin-coroutinesdagger-hiltandroid-mvvm

Cannot be provided without an @provides-annotated method - Dagger/Hilt


I'm trying to use Dagger Hilt with Retrofit and Corroutines to make a simple API consumption project. However, whenever I try to run the App, "DataQuoteApi cannot be provided without an @Provides-annotated method." And honestly I don't know how to solve this kind of problem, as I can't put a @Provides in the interface or something like that

My interface:

interface DataQuoteApi {

    @GET("/quotes")
    suspend fun getAllQuotes(): List<QuoteModel>

}

My repository:

class QuoteRepository @Inject constructor(
    private var api:DataQuoteApi
) {

    suspend fun getQuotes():List<QuoteModel>?{
           return api.getAllQuotes()
    }

}

My module:

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

    @Singleton
    @Provides
    fun provideRetrofit(): Retrofit {
        return Retrofit
            .Builder()
            .baseUrl("https://thesimpsonsquoteapi.glitch.me")
            .addConverterFactory(GsonConverterFactory.create()).build()
    }

    @Singleton
    @Provides
    fun provideGetQuotes(apiQuote : DataQuoteApi): QuoteRepository {
        return QuoteRepository(apiQuote)
    }

}

Meu ViewModel:

@HiltViewModel
class QuoteViewModel @Inject constructor(

    private var repository: QuoteRepository

    ):ViewModel() {

    var isLoading = MutableLiveData<Boolean>()
    var quote = MutableLiveData<QuoteModel>()

    fun getQuotes(){

        viewModelScope.launch {
            isLoading.postValue(true)
            var response = repository.getQuotes()
            if(!response.isNullOrEmpty()){
                quote.postValue(response[0])
                isLoading.postValue(false)
            }

        }

    }

    fun onCreate() {

        viewModelScope.launch {

            isLoading.postValue(true)
            var allQuotes = repository.getQuotes()
            if (!allQuotes.isNullOrEmpty()) {
                quote.postValue(allQuotes[0])
                isLoading.postValue(false)
            }
        }

    }


}

Does anyone know what I'm doing wrong?


Solution

  • Let me tell you a brief story about how Dagger actually works. Dagger is a Dependency Injection Library that is fully static and compiles time. With Annotation @Inject in a class constructor or field or method(actually deprecated, do not use it), Dagger Add this class or Object to its dependency graph. Dagger know how to instantiate a simple class that does not have a dependency like this example:

    class Example @Inject constructor() {}
    

    this is a class with no-args constructor and dagger can instantiate this class and add it to the dependency graph.

    in some cases like to use third-party libraries that use builder pattern or interface and abstract class that can not instantiate easily dagger does not know how to create an instance of that class or dependency, so you must use Module and tell them how to create an instance of that dependency.

    so do it like this example:

    @Module
    @InstallIn(SingletonComponent::class)
    object NetworkModule {
    
    @Singleton
    @Provides
    fun provideRetrofit(): Retrofit {
        return Retrofit
            .Builder()
            .baseUrl("https://thesimpsonsquoteapi.glitch.me")
            .addConverterFactory(GsonConverterFactory.create()).build()
    }
    
    // You provide retrofit so dagger use it in this method
    @Singleton
    @Provides
    fun provideGetQuotes(retrofit: Retrofit): DataQuoteApi {
        return retrofit.create(DataQuoteApi::class.java)
    }
    
    }