我收到“循环依赖”Android Dagger Hilt 错误

Posted

技术标签:

【中文标题】我收到“循环依赖”Android Dagger Hilt 错误【英文标题】:I'm getting the 'circular dependency' Android Dagger Hilt error 【发布时间】:2021-10-17 20:39:14 【问题描述】:

我从头开始检查了所有内容,但找不到错误。找不到错误,请问是什么问题?

我收到以下编译错误;

HomeViewModel.java:6: error: [ComponentProcessor:MiscError] dagger.internal.codegen.ComponentProcessor was unable to process this class because not all of its dependencies could be resolved. Check for compilation errors or a circular dependency with generated code.
public final class HomeViewModel extends androidx.lifecycle.ViewModel 
             ^

清单文件

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.movielistandroid">

    <uses-permission android:name="android.permission.INTERNET"/>

    <application
        android:name="com.example.movielistandroid.Application"
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/Theme.MovieListAndroid">
        <activity android:name=".ui.MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        <meta-data
            android:name="preloaded_fonts"
            android:resource="@array/preloaded_fonts" />
    </application>

</manifest>

Application.kt

package com.example.movielistandroid

import android.app.Application
import dagger.hilt.android.HiltAndroidApp

@HiltAndroidApp
class Application : Application() 

AppModule.kt

package com.example.movielistandroid.di

import com.example.movielistandroid.BuildConfig
import com.example.movielistandroid.data.remote.MovieService
import com.example.movielistandroid.data.repositories.MoviesRepository
import com.example.movielistandroid.usecase.repositories.MoviesRepositoryImpl
import com.example.movielistandroid.utils.Constants
import dagger.Module
import dagger.Provides
import dagger.hilt.InstallIn
import dagger.hilt.android.components.ApplicationComponent
import dagger.hilt.components.SingletonComponent
import okhttp3.OkHttpClient
import okhttp3.logging.HttpLoggingInterceptor
import retrofit2.Retrofit
import retrofit2.converter.gson.GsonConverterFactory
import javax.inject.Singleton

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

    @Singleton
    @Provides
    fun provideOkHttpClient(): OkHttpClient = if (BuildConfig.DEBUG) 
        val loggingInterceptor = HttpLoggingInterceptor()
        loggingInterceptor.level = HttpLoggingInterceptor.Level.BODY
        OkHttpClient.Builder()
            .addInterceptor(loggingInterceptor)
            .build()
     else 
        OkHttpClient
            .Builder()
            .build()
    

    @Singleton
    @Provides
    fun provideRetrofit(okHttpClient: OkHttpClient): Retrofit = Retrofit.Builder()
        .addConverterFactory(GsonConverterFactory.create())
        .baseUrl("$Constants.BASE_URL$Constants.API_KEY")
        .client(okHttpClient)
        .build()

    @Provides
    @Singleton
    fun provideApiService(retrofit: Retrofit): MovieService = retrofit.create(MovieService::class.java)


    @Provides
    @Singleton
    fun provideMoviesRepository(movieService: MovieService): MoviesRepository = MoviesRepositoryImpl(movieService)


MoviesRepository.kt

package com.example.movielistandroid.data.repositories

import MoviesResponseModel
import com.example.movielistandroid.data.remote.MovieService

interface MoviesRepository 
    suspend fun getCurrentPlayingMovies(): MoviesResponseModel
    suspend fun getUpComingMovies(): MoviesResponseModel

MoviesRepositoryImpl.kt

package com.example.movielistandroid.usecase.repositories

import com.example.movielistandroid.data.remote.MovieService
import com.example.movielistandroid.data.remote.MovieService.Companion.MOVIE_API_KEY
import com.example.movielistandroid.data.repositories.MoviesRepository
import javax.inject.Inject
import javax.inject.Singleton

class MoviesRepositoryImpl
@Inject constructor(
    private val movieService: MovieService
) : MoviesRepository 

    override suspend fun getCurrentPlayingMovies() = movieService.getCurrentPlayingMovies(apiKey = MOVIE_API_KEY)
    override suspend fun getUpComingMovies() = movieService.getUpComingMovies(apiKey = MOVIE_API_KEY);

HomeViewModel.kt

package com.example.movielistandroid.ui.home

import androidx.lifecycle.ViewModel
import androidx.lifecycle.liveData
import com.example.movielistandroid.data.repositories.MoviesRepository
import com.example.movielistandroid.utils.Resource
import kotlinx.coroutines.Dispatchers
import javax.inject.Inject

class HomeViewModel
@Inject constructor(
    private val moviesRepository: MoviesRepository
) : ViewModel() 

    fun getUpComingMovies() = liveData(Dispatchers.IO) 
        emit(Resource.loading(data = null))
        try 
            emit(Resource.success(data = moviesRepository.getUpComingMovies()))
         catch (exception: Exception) 
            emit(Resource.error(data = null, message = exception.message ?: "Error Occurred!"))
        
    

    fun getCurrentPlayingMovies() = liveData(Dispatchers.IO) 
        emit(Resource.loading(data = null))
        try 
            emit(Resource.success(data = moviesRepository.getCurrentPlayingMovies()))
         catch (exception: Exception) 
            emit(Resource.error(data = null, message = exception.message ?: "Error Occurred!"))
        
    

HomeViewModel.java(生成)

package com.example.movielistandroid.ui.home;

import java.lang.System;

@kotlin.Metadata(mv = 1, 5, 1, k = 1, d1 = "\u0000\"\n\u0002\u0018\u0002\n\u0002\u0018\u0002\n\u0000\n\u0002\u0018\u0002\n\u0002\b\u0002\n\u0002\u0018\u0002\n\u0002\u0018\u0002\n\u0002\u0018\u0002\n\u0002\b\u0002\u0018\u00002\u00020\u0001B\u000f\b\u0007\u0012\u0006\u0010\u0002\u001a\u00020\u0003\u00a2\u0006\u0002\u0010\u0004J\u0012\u0010\u0005\u001a\u000e\u0012\n\u0012\b\u0012\u0004\u0012\u00020\b0\u00070\u0006J\u0012\u0010\t\u001a\u000e\u0012\n\u0012\b\u0012\u0004\u0012\u00020\b0\u00070\u0006R\u000e\u0010\u0002\u001a\u00020\u0003X\u0082\u0004\u00a2\u0006\u0002\n\u0000\u00a8\u0006\n", d2 = "Lcom/example/movielistandroid/ui/home/HomeViewModel;", "Landroidx/lifecycle/ViewModel;", "moviesRepository", "Lcom/example/movielistandroid/data/repositories/MoviesRepository;", "(Lcom/example/movielistandroid/data/repositories/MoviesRepository;)V", "getCurrentPlayingMovies", "Landroidx/lifecycle/LiveData;", "Lcom/example/movielistandroid/utils/Resource;", "LMoviesResponseModel;", "getUpComingMovies", "app_debug")
public final class HomeViewModel extends androidx.lifecycle.ViewModel 
    private final com.example.movielistandroid.data.repositories.MoviesRepository moviesRepository = null;
    
    @javax.inject.Inject()
    public HomeViewModel(@org.jetbrains.annotations.NotNull()
    com.example.movielistandroid.data.repositories.MoviesRepository moviesRepository) 
        super();
    
    
    @org.jetbrains.annotations.NotNull()
    public final androidx.lifecycle.LiveData<com.example.movielistandroid.utils.Resource<MoviesResponseModel>> getUpComingMovies() 
        return null;
    
    
    @org.jetbrains.annotations.NotNull()
    public final androidx.lifecycle.LiveData<com.example.movielistandroid.utils.Resource<MoviesResponseModel>> getCurrentPlayingMovies() 
        return null;
    

build.gradle(应用程序)

plugins 
    id 'com.android.application'
    id 'kotlin-android'
    id 'kotlin-android-extensions'
    id 'androidx.navigation.safeargs.kotlin'
    id 'kotlin-kapt'
    id 'dagger.hilt.android.plugin'


android 
    compileSdkVersion 30
    buildToolsVersion "30.0.3"

    defaultConfig 
        applicationId "com.example.movielistandroid"
        minSdkVersion 19
        targetSdkVersion 30
        versionCode 1
        versionName "1.0"
        multiDexEnabled true

        testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
    

    buildTypes 
        release 
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
        
    
    compileOptions 
        sourceCompatibility JavaVersion.VERSION_1_8
        targetCompatibility JavaVersion.VERSION_1_8
    
    kotlinOptions 
        jvmTarget = '1.8'
    
    buildFeatures 
        viewBinding true
    


dependencies 
    def nav_version = "2.3.5"
    def retrofit_version = "2.9.0"
    def glide_version = "4.12.0"

    implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
    implementation 'androidx.core:core-ktx:1.6.0'
    implementation 'androidx.appcompat:appcompat:1.3.1'
    implementation 'com.google.android.material:material:1.4.0'
    implementation 'androidx.constraintlayout:constraintlayout:2.1.0'
    implementation 'androidx.legacy:legacy-support-v4:1.0.0'
    implementation 'androidx.recyclerview:recyclerview:1.2.1'
    implementation 'androidx.multidex:multidex:2.0.1'



    implementation 'androidx.fragment:fragment-ktx:1.3.6'
    implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:2.3.1"
    implementation "androidx.lifecycle:lifecycle-extensions:2.2.0"
    implementation 'androidx.lifecycle:lifecycle-common:2.3.1'
    implementation 'androidx.lifecycle:lifecycle-runtime-ktx:2.3.1'
    implementation 'androidx.lifecycle:lifecycle-livedata-ktx:2.3.1'
    implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.4.1'


    implementation "androidx.navigation:navigation-fragment-ktx:$nav_version"
    implementation "androidx.navigation:navigation-ui-ktx:$nav_version"
    implementation "androidx.navigation:navigation-dynamic-features-fragment:$nav_version"


    implementation "com.squareup.retrofit2:retrofit:$retrofit_version"
    implementation "com.squareup.retrofit2:converter-gson:$retrofit_version"
    implementation 'com.google.code.gson:gson:2.8.6'
    implementation 'com.squareup.okhttp3:logging-interceptor:4.5.0'

    implementation "com.github.bumptech.glide:glide:$glide_version"
    annotationProcessor "com.github.bumptech.glide:compiler:$glide_version"



    implementation "com.google.dagger:hilt-android:2.38.1"
    kapt "com.google.dagger:hilt-compiler:2.38.1"


    testImplementation 'junit:junit:4.13.2'
    androidTestImplementation 'androidx.test.ext:junit:1.1.3'
    androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'

build.gradle(项目)

// Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript 
    ext.kotlin_version = "1.5.21"
    repositories 
        google()
        mavenCentral()
    
    dependencies 
        def nav_version = "2.3.5"
        classpath "com.android.tools.build:gradle:4.2.2"
        classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
        classpath "androidx.navigation:navigation-safe-args-gradle-plugin:$nav_version"
        classpath 'com.google.dagger:hilt-android-gradle-plugin:2.38.1'
    


allprojects 
    repositories 
        google()
        mavenCentral()
    


task clean(type: Delete) 
    delete rootProject.buildDir

【问题讨论】:

您忘记将@HiltViewModel 添加到您的ViewModel 类dagger.dev/hilt/view-model.html 是的,只需在 ViewModel 类的顶部添加这个注解 @HiltViewModel 我添加了 '@HiltViewModel' 注释,但我仍然有这个错误。 @IR42 【参考方案1】:

如果您使用 hilt vm factory 将 vm 注入到您的活动/片段中,则需要在您的 vm 中添加 @HiltViewModel

另外,您可以将MoviesRepositoryImplMoviesRepository 绑定 您已经在为 MoviesRepositoryImpl 使用构造函数注入,而不是为其编写提供程序

怎么样-

@Module
@InstallIn(SingletonComponent::class)
interface MoviesRepositoryImplModule 
    @Binds
    fun bindMoviesRepositoryImpl(movieRepoImp: MoviesRepositoryImpl): MoviesRepository

并删除

    @Provides
    @Singleton
    fun provideMoviesRepository(movieService: MovieService): MoviesRepository = MoviesRepositoryImpl(movieService)

来自AppModule

【讨论】:

我做了你写的,但问题仍然存在。同样的错误。 :( 你能补充一下,代码 sn-p,你是如何在活动/片段中注入 VM 的?您还可以尝试在编译器选项中使用选项 --stracktrace 运行应用程序以获取更详细的错误日志。 我发现了 --stacktrace 编译器选项的问题。我的问题不在于匕首柄。我遇到这个问题是因为我创建的模型类没有“包”前缀。 @SalihCan 感谢您的信息!我真的去一一检查package的事情,它解决了! Dagger-hilt应该改进他们的错误提示技能omg! 感谢@SalihCan 的分享。我遇到了同样的错误

以上是关于我收到“循环依赖”Android Dagger Hilt 错误的主要内容,如果未能解决你的问题,请参考以下文章

打破 Dagger 中的循环依赖

Android 上的 Dagger 2,缺少错误消息

Dagger 2 - 为啥我收到循环引用错误?

dagger android支持proguard规则

Dagger 2 注入 Android 应用程序上下文

没有Dagger2的Android Kotlin MVVM结构