android - 如果没有 @Provides 注释的方法,则无法提供 Dagger 柄

标签 android kotlin dagger-hilt android-mvvm

我是 Dagger 的新手。所以,我无法解决这有什么问题。我只是想在这里请求解决。

这是错误:

C:\Users\msi\Documents\MyAndroidProjects\MovieProjects\app\build\generated\hilt\component_sources\debug\com\example\movieapp\App_HiltComponents.java:128: error: [Dagger/MissingBinding] com.example.movieapp.api.MovieAppService cannot be provided without an @Provides-annotated method. public abstract static class SingletonC implements App_GeneratedInjector, ^ com.example.movieapp.api.MovieAppService is injected at com.example.movieapp.repository.MovieRepository(movieAppService) com.example.movieapp.repository.MovieRepository is injected at com.example.movieapp.viewmodel.MainViewModel(repository, �) com.example.movieapp.viewmodel.MainViewModel is injected at com.example.movieapp.viewmodel.MainViewModel_HiltModules.BindsModule.binds(arg0) @dagger.hilt.android.internal.lifecycle.HiltViewModelMap java.util.Map<java.lang.String,javax.inject.Provider<androidx.lifecycle.ViewModel>> is requested at dagger.hilt.android.internal.lifecycle.HiltViewModelFactory.ViewModelFactoriesEntryPoint.getHiltViewModelMap() [com.example.movieapp.App_HiltComponents.SingletonC ? com.example.movieapp.App_HiltComponents.ActivityRetainedC ? com.example.movieapp.App_HiltComponents.ViewModelC]

MainViewModel.kt

@HiltViewModel
class MainViewModel@Inject constructor(
    private val repository: MovieRepository,
    @ApplicationContext private val context: Context
) : ViewModel() {

    val movieList = MutableLiveData<Resource<Movie>>()

    fun getAllMovies(movieName: String) {
        movieList.postValue(Resource.Loading())
        viewModelScope.launch {
            try {
                if (hasInternetConnection(context)) {
                    val response = repository.getMovies(movieName, "ffe9063f")
                    movieList.postValue(Resource.Success(response.body()!!))
                } else
                    movieList.postValue(Resource.Error("Internet yok"))
            } catch (ex: Exception) {
                when (ex) {
                    is IOException -> movieList.postValue(Resource.Error("Network Failure " + ex.localizedMessage))
                    else -> movieList.postValue(Resource.Error("Conversion Error"))
                }
            }
        }
    }
}

MovieRepository.kt

@Singleton
class MovieRepository @Inject constructor(private val movieAppService: MovieAppService) {

    suspend fun getMovies(title: String, aKey: String): Response<Movie> = withContext(
        Dispatchers.IO
    ) {
        val movies = movieAppService.getMovies(title = title, aKey = aKey)
        movies
    }
}

ApiModule.kt

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

        @Provides
        @Singleton
        fun provideLoggingInterceptor(): HttpLoggingInterceptor {
            return HttpLoggingInterceptor().setLevel(HttpLoggingInterceptor.Level.BODY)
        }

        @Provides
        @Singleton
        fun provideOkHttpClient(logging: HttpLoggingInterceptor): OkHttpClient {
            return OkHttpClient.Builder()
                .addInterceptor(logging)
                .connectTimeout(15, TimeUnit.SECONDS) // connect timeout
                .readTimeout(15, TimeUnit.SECONDS)
                .build()
        }

        @Provides
        @Singleton
        fun provideRetrofit(client: OkHttpClient): Retrofit {
            return Retrofit.Builder()
                .baseUrl(ENDPOINT)
                .addConverterFactory(GsonConverterFactory.create())
                .client(client)
                .build()
        }

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

MovieAppService.kt

interface MovieAppService {

    companion object {
        const val ENDPOINT = "http://www.omdbapi.com/"
    }

    @GET(".")
    suspend fun getMovies(@Query("t") title: String,@Query("apikey") aKey: String): Response<Movie>
}

最佳答案

不要使用同名类来包装您的单例对象模块。像这样更改模块文件或更改类名

@Module
@InstallIn(SingletonComponent::class)
object ApiModule {
    
    @Provides
    @Singleton
    fun provideLoggingInterceptor(): HttpLoggingInterceptor {
        return HttpLoggingInterceptor().setLevel(HttpLoggingInterceptor.Level.BODY)
    }

    @Provides
    @Singleton
    fun provideOkHttpClient(logging: HttpLoggingInterceptor): OkHttpClient {
        return OkHttpClient.Builder()
            .addInterceptor(logging)
            .connectTimeout(15, TimeUnit.SECONDS) // connect timeout
            .readTimeout(15, TimeUnit.SECONDS)
            .build()
    }

    @Provides
    @Singleton
    fun provideRetrofit(client: OkHttpClient): Retrofit {
        return Retrofit.Builder()
            .baseUrl(ENDPOINT)
            .addConverterFactory(GsonConverterFactory.create())
            .client(client)
            .build()
    }

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

关于android - 如果没有 @Provides 注释的方法,则无法提供 Dagger 柄,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/72337318/

相关文章:

java - 在kotlin中将接口(interface)定义为接口(interface)的属性并在接口(interface)实现中提供具体的实现是行不通的

android - 如何在 google play 上将 android 应用程序限制为 64 位平台下载

Java Android - XmlPullParser - 如何再次从头开始解析?

android - 仅在谷歌地图中显示当前用户位置一次

java - 如何在运行时请求位置权限

intellij-idea - 升级到 Kotlin 1.3 后我仍然无法使用合约

android - 在 Firebase 中更新目标

android - 具有由 Hilt 在仪器测试零参数构造函数中注入(inject)的可组合项的真实 ViewModel

android - 编译项目时出现 Dagger 错误

android - Dagger - 刀柄 : Do we need to mark all activities with @AndroidEntryPoint