Home > OS >  Hilt jCannot create an instance of class com.therealbluepandabear.pixapencil.screens.new.NewScreenVi
Hilt jCannot create an instance of class com.therealbluepandabear.pixapencil.screens.new.NewScreenVi

Time:10-17

I found a solution please do not read on

I am creating an app with Hilt which stores some data using Room.

My ViewModel:

@HiltViewModel
class NewScreenViewModel @Inject constructor(private val repository: QuickPresetsRepository) : ViewModel() {

    private val _state = mutableStateOf(
        NewScreenState(
            quickPresets = emptyList()
        )
    )

    private val textValidator = TextValidator()

    val state: State<NewScreenState>
        get() = _state

    init {
        getQuickPresets()
    }

    private fun getQuickPresets() {
        viewModelScope.launch {
            val quickPresets = repository.getQuickPresets()

            _state.value = _state.value.copy(
                quickPresets = quickPresets
            )
        }
    }
}

Repo:

@Singleton
class QuickPresetsRepository @Inject constructor(private val dao: QuickPresetsDao) {
    suspend fun getQuickPresets(): List<QuickPreset> {
        return withContext(Dispatchers.IO) {
            return@withContext dao.getAll()
        }
    }
}

Module:

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

    @Provides
    fun provideRoomDao(database: QuickPresetsDb): QuickPresetsDao {
        return database.dao
    }

    @Singleton
    @Provides
    fun provideRoomDatabase(app: Application): QuickPresetsDb {
        return QuickPresetsDb.getInstance(app)
    }
}

Dao:

@Dao
interface QuickPresetsDao {
    @Query("SELECT * FROM quickpresets")
    suspend fun getAll(): List<QuickPreset>

    @Insert
    suspend fun insert(quickPreset: QuickPreset)
}

Db:

@Database(
    entities = [QuickPreset::class],
    version = 1,
)
abstract class QuickPresetsDb : RoomDatabase() {

    abstract val dao: QuickPresetsDao

    companion object {
        @Volatile
        private var INSTANCE: QuickPresetsDb? = null

        fun getInstance(app: Application): QuickPresetsDb {
            return INSTANCE ?: synchronized(this) {
                INSTANCE ?: buildDatabase(app).also {
                    INSTANCE = it
                }
            }
        }

        private fun buildDatabase(app: Application) =
            Room.databaseBuilder(app, QuickPresetsDb::class.java, "quickpresets_db")
                .addCallback(
                    object : Callback() {
                        override fun onCreate(db: SupportSQLiteDatabase) {
                            super.onCreate(db)

                            CoroutineScope(Dispatchers.IO).launch {
                                prePopulateDb(getInstance(app).dao)
                            }
                        }
                    }
                )
                .build()

        private suspend fun prePopulateDb(dao: QuickPresetsDao) {
            dao.insert(
                QuickPreset(5, 5)
            )
        }
    }
}

Model:

@Entity(tableName = "quickpresets")
data class QuickPreset(
    @ColumnInfo(name = "qp_width")
    val width: Int,
    @ColumnInfo(name = "qp_height")
    val height: Int
) {
    @PrimaryKey(autoGenerate = true) var id: Int = 0
}

MainActivity:

composable(route = "new") {
    val viewModel: NewScreenViewModel = hiltViewModel()
    val state = viewModel.state.value

    NewScreen(
        viewModel,
        state
    ) { width, height ->

        navController.currentBackStackEntry?.arguments?.apply {
            putInt("width", width)
            putInt("height", height)
        }

        navController.navigate("draw")
    }
}

The problem is, whenever I run the app, I keep getting this exception:

java.lang.RuntimeException: Cannot create an instance of class com.therealbluepandabear.pixapencil.screens.new.NewScreenViewModel
                                                                                                        at androidx.lifecycle.ViewModelProvider$NewInstanceFactory.create(ViewModelProvider.kt:204)
                                                                                                        at androidx.lifecycle.ViewModelProvider$AndroidViewModelFactory.create(ViewModelProvider.kt:322)
                                                                                                        at androidx.lifecycle.ViewModelProvider$AndroidViewModelFactory.create(ViewModelProvider.kt:304)
                                                                                                        at androidx.lifecycle.ViewModelProvider$AndroidViewModelFactory.create(ViewModelProvider.kt:278)
                                                                                                        at androidx.lifecycle.SavedStateViewModelFactory.create(SavedStateViewModelFactory.kt:128)
                                                                                                        at dagger.hilt.android.internal.lifecycle.HiltViewModelFactory.create(HiltViewModelFactory.java:118)
                                                                                                        at androidx.lifecycle.ViewModelProvider.get(ViewModelProvider.kt:187)
                                                                                                        at androidx.lifecycle.ViewModelProvider.get(ViewModelProvider.kt:153)
                                                                                                        at androidx.lifecycle.viewmodel.compose.ViewModelKt.get(ViewModel.kt:215)
                                                                                                        at androidx.lifecycle.viewmodel.compose.ViewModelKt.get$default(ViewModel.kt:195)
                                                                                                        at androidx.lifecycle.viewmodel.compose.ViewModelKt.viewModel(ViewModel.kt:120)
                                                                                                        at com.therealbluepandabear.pixapencil.activities.main.MainActivity$PixaPencil$1$2.invoke(MainActivity.kt:208)
                                                                                                        at com.therealbluepandabear.pixapencil.activities.main.MainActivity$PixaPencil$1$2.invoke(MainActivity.kt:109)
                                                                                                        at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:116)
                                                                                                        at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:34)
                                                                                                        at androidx.navigation.compose.NavHostKt$NavHost$4$2.invoke(NavHost.kt:163)
                                                                                                        at androidx.navigation.compose.NavHostKt$NavHost$4$2.invoke(NavHost.kt:162)
                                                                                                        at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:107)
                                                                                                        at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:34)
                                                                                                        at androidx.compose.runtime.CompositionLocalKt.CompositionLocalProvider(CompositionLocal.kt:228)
                                                                                                        at androidx.compose.runtime.saveable.SaveableStateHolderImpl.SaveableStateProvider(SaveableStateHolder.kt:84)
                                                                                                        at androidx.navigation.compose.NavBackStackEntryProviderKt.SaveableStateProvider(NavBackStackEntryProvider.kt:60)
                                                                                                        at androidx.navigation.compose.NavBackStackEntryProviderKt.access$SaveableStateProvider(NavBackStackEntryProvider.kt:1)
                                                                                                        at androidx.navigation.compose.NavBackStackEntryProviderKt$LocalOwnersProvider$1.invoke(NavBackStackEntryProvider.kt:52)
                                                                                                        at androidx.navigation.compose.NavBackStackEntryProviderKt$LocalOwnersProvider$1.invoke(NavBackStackEntryProvider.kt:51)
                                                                                                        at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:107)
                                                                                                        at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:34)
                                                                                                        at androidx.compose.runtime.CompositionLocalKt.CompositionLocalProvider(CompositionLocal.kt:228)
                                                                                                        at androidx.navigation.compose.NavBackStackEntryProviderKt.LocalOwnersProvider(NavBackStackEntryProvider.kt:47)
                                                                                                        at androidx.navigation.compose.NavHostKt$NavHost$4.invoke(NavHost.kt:162)
                                                                                                        at androidx.navigation.compose.NavHostKt$NavHost$4.invoke(NavHost.kt:141)
                                                                                                        at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:116)
                                                                                                        at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:34)
                                                                                                        at androidx.compose.animation.CrossfadeKt$Crossfade$5$1.invoke(Crossfade.kt:133)
                                                                                                        at androidx.compose.animation.CrossfadeKt$Crossfade$5$1.invoke(Crossfade.kt:128)
                                                                                                        at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:107)
                                                                                                        at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:34)
                                                                                                        at androidx.compose.animation.CrossfadeKt.Crossfade(Crossfade.kt:142)
                                                                                                        at androidx.compose.animation.CrossfadeKt.Crossfade(Crossfade.kt:73)
                                                                                                        at androidx.navigation.compose.NavHostKt.NavHost(NavHost.kt:141)
                                                                                                        at androidx.navigation.compose.NavHostKt$NavHost$5.invoke(Unknown Source:13)
2022-10-16 18:18:55.632  3957-3957  AndroidRuntime          com.therealbluepandabear.pixapencil  E      at androidx.navigation.compose.NavHostKt$NavHost$5.invoke(Unknown Source:10)
                                                                                                        at androidx.compose.runtime.RecomposeScopeImpl.compose(RecomposeScopeImpl.kt:145)
                                                                                                        at androidx.compose.runtime.ComposerImpl.recomposeToGroupEnd(Composer.kt:2375)
                                                                                                        at androidx.compose.runtime.ComposerImpl.skipCurrentGroup(Composer.kt:2643)
                                                                                                        at androidx.compose.runtime.ComposerImpl$doCompose$2$5.invoke(Composer.kt:3260)
                                                                                                        at androidx.compose.runtime.ComposerImpl$doCompose$2$5.invoke(Composer.kt:3238)
                                                                                                        at androidx.compose.runtime.SnapshotStateKt__DerivedStateKt.observeDerivedStateRecalculations(DerivedState.kt:341)
                                                                                                        at androidx.compose.runtime.SnapshotStateKt.observeDerivedStateRecalculations(Unknown Source:1)
                                                                                                        at androidx.compose.runtime.ComposerImpl.doCompose(Composer.kt:3238)
                                                                                                        at androidx.compose.runtime.ComposerImpl.recompose$runtime_release(Composer.kt:3203)
                                                                                                        at androidx.compose.runtime.CompositionImpl.recompose(Composition.kt:771)
                                                                                                        at androidx.compose.runtime.Recomposer.performRecompose(Recomposer.kt:1031)
                                                                                                        at androidx.compose.runtime.Recomposer.access$performRecompose(Recomposer.kt:125)
                                                                                                        at androidx.compose.runtime.Recomposer$runRecomposeAndApplyChanges$2$2.invoke(Recomposer.kt:534)
                                                                                                        at androidx.compose.runtime.Recomposer$runRecomposeAndApplyChanges$2$2.invoke(Recomposer.kt:503)
                                                                                                        at androidx.compose.ui.platform.AndroidUiFrameClock$withFrameNanos$2$callback$1.doFrame(AndroidUiFrameClock.android.kt:34)
                                                                                                        at androidx.compose.ui.platform.AndroidUiDispatcher.performFrameDispatch(AndroidUiDispatcher.android.kt:109)
                                                                                                        at androidx.compose.ui.platform.AndroidUiDispatcher.access$performFrameDispatch(AndroidUiDispatcher.android.kt:41)
                                                                                                        at androidx.compose.ui.platform.AndroidUiDispatcher$dispatchCallback$1.doFrame(AndroidUiDispatcher.android.kt:69)
                                                                                                        at android.view.Choreographer$CallbackRecord.run(Choreographer.java:1035)
                                                                                                        at android.view.Choreographer.doCallbacks(Choreographer.java:845)
                                                                                                        at android.view.Choreographer.doFrame(Choreographer.java:775)
                                                                                                        at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:1022)
                                                                                                        at android.os.Handler.handleCallback(Handler.java:938)
                                                                                                        at android.os.Handler.dispatchMessage(Handler.java:99)
                                                                                                        at android.os.Looper.loopOnce(Looper.java:201)
                                                                                                        at android.os.Looper.loop(Looper.java:288)
                                                                                                        at android.app.ActivityThread.main(ActivityThread.java:7870)
                                                                                                        at java.lang.reflect.Method.invoke(Native Method)
                                                                                                        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:548)
                                                                                                        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1003)
                                                                                                        Suppressed: kotlinx.coroutines.DiagnosticCoroutineContextException: [androidx.compose.runtime.PausableMonotonicFrameClock@7dee98d, androidx.compose.ui.platform.MotionDurationScaleImpl@5209742, StandaloneCoroutine{Cancelling}@c02b353, AndroidUiDispatcher@4fbd490]
                                                                                                    Caused by: java.lang.InstantiationException: java.lang.Class<com.therealbluepandabear.pixapencil.screens.new.NewScreenViewModel> has no zero argument constructor
                                                                                                        at java.lang.Class.newInstance(Native Method)
                                                                                                        at androidx.lifecycle.ViewModelProvider$NewInstanceFactory.create(ViewModelProvider.kt:202)
                                                                                                        ... 71 more

Build.gradle (root):

// Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript {
    repositories {
        google()
        mavenCentral()
    }

    dependencies {
        classpath 'com.android.tools.build:gradle:7.3.0'
        classpath 'org.jetbrains.kotlin:kotlin-gradle-plugin:1.6.10'
        classpath 'com.google.dagger:hilt-android-gradle-plugin:2.42'
    }

    ext {
        compose_version = '1.3.0-rc01'
    }
}

plugins {
    id 'com.autonomousapps.dependency-analysis' version "1.4.0"
    id 'org.jetbrains.kotlin.android' version '1.6.10' apply false
}

task clean(type: Delete) {
    delete rootProject.buildDir
}

Build.gradle (module):

plugins {
    id 'com.android.application'
    id 'kotlin-android'
    id 'kotlin-kapt'
    id 'dagger.hilt.android.plugin'
}

android {
    compileSdk 33

    testOptions {
        execution 'ANDROIDX_TEST_ORCHESTRATOR'
    }

    defaultConfig {
        applicationId "com.therealbluepandabear.pixapencil"
        minSdk 26
        targetSdk 33
        versionCode 26
        versionName "0.1.8"

        testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"

        javaCompileOptions {
            annotationProcessorOptions {
                arguments  = ["room.schemaLocation": "$projectDir/schemas".toString()]
            }
        }
    }

    composeOptions {
        kotlinCompilerExtensionVersion '1.1.1'
    }

    testOptions {
        execution 'ANDROID_TEST_ORCHESTRATOR'
    }

    configurations {
        androidTestImplementation {
            exclude group: 'io.mockk', module: 'mockk-agent-jvm'
        }
    }

    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
        compose true
    }
    namespace 'com.therealbluepandabear.pixapencil'
    testOptions {
        unitTests.returnDefaultValues = true
    }
    kotlin.sourceSets.all {
        languageSettings.optIn("kotlin.RequiresOptIn")
    }
}

dependencies {
    implementation 'androidx.core:core-ktx:1.9.0'
    implementation 'androidx.appcompat:appcompat:1.5.1'
    implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
    implementation "androidx.room:room-runtime:2.4.3"
    implementation "androidx.room:room-ktx:2.4.3"
    implementation "androidx.lifecycle:lifecycle-runtime-ktx:2.5.1"
    implementation 'androidx.coordinatorlayout:coordinatorlayout:1.2.0'
    implementation "androidx.fragment:fragment-ktx:1.5.3"
    implementation 'com.github.tianscar:quickbitmap:1.0.2.6'
    implementation 'net.yslibrary.keyboardvisibilityevent:keyboardvisibilityevent:3.0.0-RC3'
    implementation 'io.github.beyka:Android-TiffBitmapFactory:0.9.9.0'
    implementation 'com.github.bumptech.glide:glide:4.13.2'
    implementation 'com.github.duanhong169:colorpicker:1.1.6'
    implementation 'com.google.android.material:material:1.6.1'
    implementation 'com.google.code.gson:gson:2.9.1'
    implementation 'com.android.volley:volley:1.2.1'
    implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.6.4'
    implementation 'androidx.activity:activity-compose:1.6.0'
    implementation "androidx.compose.ui:ui:$compose_version"
    implementation "androidx.compose.ui:ui-tooling-preview:$compose_version"
    implementation 'androidx.compose.material3:material3:1.0.0-rc01'
    implementation "androidx.lifecycle:lifecycle-viewmodel-compose:2.5.1"
    implementation "androidx.navigation:navigation-compose:2.5.2"
    implementation "com.google.dagger:hilt-android:2.44"
    implementation 'androidx.hilt:hilt-navigation-compose:1.0.0'
    kapt "com.google.dagger:hilt-compiler:2.44"
    debugImplementation "androidx.compose.ui:ui-tooling:$compose_version"
    debugImplementation "androidx.compose.ui:ui-test-manifest:$compose_version"
    runtimeOnly 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.6.4'
    testImplementation 'junit:junit:4.13.2'
    testImplementation 'io.mockk:mockk-agent-jvm:1.12.3'
    testImplementation 'io.mockk:mockk-android:1.12.3'
    androidTestImplementation "androidx.compose.ui:ui-test-junit4:$compose_version"
    androidTestImplementation 'androidx.test.ext:junit-ktx:1.1.3'
    androidTestImplementation 'junit:junit:4.13.2'
    androidTestImplementation "org.jetbrains.kotlin:kotlin-test-junit:1.6.10"
    androidTestImplementation "io.mockk:mockk-android:1.12.3"
    androidTestImplementation "io.mockk:mockk-agent-jvm:1.12.3"
    androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'
    androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
    androidTestImplementation 'com.android.support.test.espresso:espresso-contrib:3.0.2'
    androidTestImplementation 'androidx.test:rules:1.4.0'
    androidTestImplementation 'androidx.test:runner:1.4.0'
    androidTestImplementation 'org.jetbrains.kotlinx:kotlinx-coroutines-test:1.6.4'
    androidTestImplementation "org.mockito.kotlin:mockito-kotlin:4.0.0"
    androidTestImplementation "androidx.arch.core:core-testing:2.1.0"
    androidTestImplementation "org.jetbrains.kotlin:kotlin-test:1.6.10"
    androidTestUtil 'androidx.test:orchestrator:1.4.1'
    kapt "androidx.room:room-compiler:2.4.3"
    annotationProcessor 'com.github.bumptech.glide:compiler:4.13.2'
}

I have been almost going insane trying to fix this issue, as I have tried almost everything. I have looked through Stack Overflow posts of people asking similar questions.

I do:

  • Have the appropriate @HiltAndroidApp annotation
  • Have the appropriate @HiltViewModel annotation
  • Have the appropriate @AndroidEntryPoint annotation
  • Have the appropriate @Inject annotation
  • Have used hiltViewModel to construct the ViewModel instance
  • Have the right Gradle dependencies

I have no idea as to what I am doing wrong as I am following the rules that are required, I have even read a book on Hilt and followed many tutorials without issue, but for some reason my app is getting an exception.

CodePudding user response:

I don't annotate my Repo class. Instead I annotate in my Module class. Try something like this instead.

Repo:

class QuickPresetsRepository @Inject constructor(private val dao: QuickPresetsDao) {
suspend fun getQuickPresets(): List<QuickPreset> {
    return withContext(Dispatchers.IO) {
        return@withContext dao.getAll()
    }
}

Module:

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

@Provides
@Singleton
fun providesQuickPresetsRepository(dao: QuickPresetsDao): QuickPresetsRepository {
    return QuickPresetsRepository(dao)
}

@Provides
fun provideRoomDao(database: QuickPresetsDb): QuickPresetsDao {
    return database.dao
}

@Singleton
@Provides
fun provideRoomDatabase(app: Application): QuickPresetsDb {
    return QuickPresetsDb.getInstance(app)
}
}

CodePudding user response:

After battling the issue for hours, I found a solution.

The issue stemmed - believe it or not - because I named my directory 'new', which seems to have been a reserved directory name which was confusing Hilt.

Changing the directory name in which the Composables were stored in to something other than 'new' fixed the issue.

  • Related