简体   繁体   English

Jetpack Compose + Hilt:java.lang.RuntimeException:无法创建 class ViewModel 的实例

[英]Jetpack Compose + Hilt: java.lang.RuntimeException: Cannot create an instance of class ViewModel

I started trying jetpack Compose recently and used hilt & hilt-navigation-compose for my app.我最近开始尝试 jetpack Compose,并在我的应用程序中使用了 hilt 和 hilt-navigation-compose。 It works fine with the first ViewModel.它适用于第一个 ViewModel。 However, when I try the same code on another ViewModel of my second screen, it always crashes with java.lang.RuntimeException: Cannot create an instance of class .但是,当我在第二个屏幕的另一个 ViewModel 上尝试相同的代码时,它总是崩溃并出现 java.lang.RuntimeException: Cannot create an instance of class But if I remove the parameter repository(Injected using Hilt) in its constructor, it can be initialized successfully.但是如果我在它的构造函数中去掉参数repository(Injected using Hilt),就可以初始化成功。

Currently in my navigation graph there are four screens.HOME, RECORD, SETTING screen can be navigated to via BottomBar, and their viewModel works properly;NEW screen can be navigated to via FloatingActionButton, but its viewModel cannot be created like the others.目前在我的导航图中有四个屏幕。HOME、RECORD、SETTING 屏幕可以通过 BottomBar 导航到,它们的 viewModel 工作正常;NEW 屏幕可以通过 FloatingActionButton 导航到,但它的 viewModel 不能像其他屏幕一样创建。 I can't figure out the problem.我无法弄清楚问题所在。 Here is my backstack trace:这是我的后台跟踪:

java.lang.RuntimeException: Cannot create an instance of class com.eynnzerr.cpbookkeeping_compose.ui.new.NewViewModel
...
Caused by: java.lang.InstantiationException: java.lang.Class<com.eynnzerr.cpbookkeeping_compose.ui.new.NewViewModel> has no zero argument constructor

Seems that Hilt only knows how to create NewViewModel with no-arg constructor and neglects its parameter repository?似乎 Hilt 只知道如何使用无参数构造函数创建 NewViewModel 而忽略其参数存储库?

Here is my code: (1)Hilt Application class:这是我的代码:(1)Hilt Application class:

    @HiltAndroidApp
    class CPApplication: Application() {
        override fun onCreate() {
            super.onCreate()
            context = applicationContext
        }

        companion object {
            @SuppressLint("StaticFieldLeak")
            lateinit var context: Context
        }
    }

(2)MainActivity: (2)主要活动:

@AndroidEntryPoint
class MainActivity : ComponentActivity() {
    @RequiresApi(Build.VERSION_CODES.N)
    @ExperimentalAnimationApi
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            BookkeepingApp()         
        }
    }
}

@ExperimentalAnimationApi
@Composable
fun BookkeepingApp() {
    CPBookkeepingcomposeTheme {
        val navController = rememberNavController()
        BasicScreen(
            navController = navController
        )
    }
}

@ExperimentalAnimationApi
@Composable
fun BasicScreen(
    navController: NavController
) {
    ...
    Scaffold(
        topBar = {
            //Change according to currentScreen in composable.
            CPTopBar(currentScreen)
        },
        floatingActionButton = {
            //only show up when it's HOME screen.
            if(currentScreen.value == Destinations.HOME_ROUTE) {
                DraggableFloatingButton(
                    onClick = {
                        navController.navigateTo(Destinations.NEW_ROUTE)
                    }
                )
            } else Unit
        },
        bottomBar = {
            //only show up when it's HOME, RECORD, SETTING screens.
            AnimatedVisibility(listState.isScrollingUp()) {
                when(currentScreen.value) {
                    Destinations.HOME_ROUTE,
                    Destinations.RECORD_ROUTE,
                    Destinations.SETTING_ROUTE -> FlutterNavigation(navController = navController, items)
                    else -> Unit
                }
            }
        }
    ) {
        NavGraph(
            navController = navController as NavHostController,
            listState = listState
        )
    }
}

(3)NavGraph: (3)导航图:

@Composable
fun NavGraph(
    navController: NavHostController = rememberNavController(),
    listState: LazyListState = rememberLazyListState(),
    startDestination: String = Destinations.HOME_ROUTE
) {
    NavHost(navController = navController, startDestination = "home") {
        composable(Destinations.HOME_ROUTE){
            //can create ViewModel.
            val homeViewModel: HomeViewModel = hiltViewModel()
            ...
        }
        ...
        composable(Destinations.NEW_ROUTE){
            //cannot create ViewModel?
            val newViewModel: NewViewModel = hiltViewModel()
            ...
        }
    }
}

(4)HomeViewModel(Which works well): (4)HomeViewModel(效果很好):

data class HomeUiState(
    val billsToday: List<Bill> = emptyList(),
    val homeData: HomeData = HomeData()
)

@HiltViewModel
class HomeViewModel @Inject constructor(
    private val billRepository: BillRepositoryImpl
): ViewModel() {
    private val _uiState = MutableStateFlow(HomeUiState())
    val uiState: StateFlow<HomeUiState> = _uiState 

    init {
        viewModelScope.launch {
            _uiState.update { it.copy(homeData = getAllData(0f)) }
            billRepository.getBillsFlow().collect { bills ->
                _uiState.update { it.copy(billsToday = bills) }
            }
        }
    }
}

(5)NewViewModel(which cannot be created except for deleting billRepository): (5)NewViewModel(除了删除billRepository不能创建):

data class TabState(
    val amount: String = "¥0",
    val selectedIndex: Int = 0
)

@HiltViewModel
class NewViewModel @Inject constructor(
    private val billRepository: BillRepositoryImpl //After deleting this, it can work properly
) : ViewModel() {

    //uiState for expenseTab
    private val _exTabState = MutableStateFlow(TabState())
    val exTabState: StateFlow<TabState> = _exTabState.asStateFlow()

    //uiState for revenueTab
    private val _reTabState = MutableStateFlow(TabState())
    val reTabState: StateFlow<TabState> = _reTabState.asStateFlow()

    private val _remarkState = MutableStateFlow("add remark")
    val remarkState: StateFlow<String> = _remarkState.asStateFlow()

    fun updateRemark(remark: String) {
        _remarkState.update { remark }
    }

    fun updateTab(category: Int, amount: String, selectedIndex: Int) {
        when(category) {
            -1 -> _exTabState.update { it.copy(amount = amount, selectedIndex = selectedIndex) }
            1 -> _reTabState.update { it.copy(amount = amount, selectedIndex = selectedIndex) }
        }
    }

    fun insertBill(bill: Bill) {
        viewModelScope.launch {
            billRepository.insertBills(bill)
        }
    }
}

(6)billRepository: (6)票据库:

class BillRepositoryImpl @Inject constructor() : BillRepository {
    private val billDao = BillDatabase.getInstance(context).getDao()

    override suspend fun getBillsFlow(): Flow<List<Bill>> = billDao.getAllBills()

    override suspend fun insertBills(vararg bill: Bill) = billDao.insertBills(*bill)

    override suspend fun deleteBills(vararg bill: Bill) = billDao.deleteBills(*bill)

    override suspend fun updateBills(vararg bill: Bill) = billDao.updateBills(*bill)
}

interface BillRepository {

    suspend fun getBillsFlow(): Flow<List<Bill>>

    suspend fun insertBills(vararg bill: Bill)

    suspend fun deleteBills(vararg bill: Bill)

    suspend fun updateBills(vararg bill: Bill)
}

(7)build.gradle(project): (7)build.gradle(项目):

buildscript {
    ext {
        compose_version = '1.1.0-beta02'
        hilt_version = "2.37"
        work_version = "2.7.1"
        datastore_version = "1.0.0"
    }
    repositories {
        google()
        mavenCentral()
    }
    dependencies {
        classpath 'com.android.tools.build:gradle:7.0.4'
        classpath 'org.jetbrains.kotlin:kotlin-gradle-plugin:1.5.31'

        classpath "com.google.dagger:hilt-android-gradle-plugin:$hilt_version"
        // NOTE: Do not place your application dependencies here; they belong
        // in the individual module build.gradle files
    }
}

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

(8)build.gradle(app): (8)build.gradle(app):

plugins {
    id 'com.android.application'
    id 'kotlin-android'
    id 'kotlin-parcelize'
}

apply plugin: 'kotlin-kapt'//hilt support
apply plugin: 'dagger.hilt.android.plugin'//hilt support

android {
    compileSdk 31

    defaultConfig {
        applicationId "com.eynnzerr.cpbookkeeping_compose"
        minSdk 21
        targetSdk 31
        versionCode 1
        versionName "1.0"

        testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
        vectorDrawables {
            useSupportLibrary true
        }

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

    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'
        useIR = true
    }
    buildFeatures {
        compose true
    }
    composeOptions {
        kotlinCompilerExtensionVersion compose_version
        kotlinCompilerVersion '1.5.31'
    }
    packagingOptions {
        resources {
            excludes += '/META-INF/{AL2.0,LGPL2.1}'
        }
    }
}

dependencies {

    implementation "io.github.vanpra.compose-material-dialogs:datetime:0.6.2"

    implementation "androidx.datastore:datastore-preferences:$datastore_version"
    implementation "androidx.datastore:datastore:$datastore_version"
    implementation "androidx.work:work-runtime-ktx:$work_version"

    def room_version = "2.4.0-beta02"
    implementation "androidx.room:room-runtime:$room_version"
    implementation "androidx.room:room-ktx:$room_version"
    kapt "androidx.room:room-compiler:$room_version"

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

    implementation "androidx.hilt:hilt-navigation-compose:1.0.0-beta01"
    implementation "androidx.navigation:navigation-compose:2.4.0-beta02"

    implementation 'androidx.core:core-ktx:1.7.0'
    implementation 'androidx.appcompat:appcompat:1.3.1'
    implementation 'com.google.android.material:material:1.3.0'
    implementation "androidx.compose.ui:ui:$compose_version"
    implementation "androidx.compose.foundation:foundation:$compose_version"
    implementation "androidx.compose.material:material:$compose_version"
    implementation "androidx.compose.material:material-icons-core:$compose_version"
    implementation "androidx.compose.material:material-icons-extended:$compose_version"
    implementation "androidx.compose.ui:ui-tooling-preview:$compose_version"
    implementation 'androidx.lifecycle:lifecycle-runtime-ktx:2.3.1'
    implementation 'androidx.activity:activity-compose:1.4.0'
    testImplementation 'junit:junit:4.+'
    androidTestImplementation 'androidx.test.ext:junit:1.1.2'
    androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0'
    androidTestImplementation "androidx.compose.ui:ui-test-junit4:$compose_version"
    debugImplementation "androidx.compose.ui:ui-tooling:$compose_version"
}

I got the answer right after I raised this question... It seems that U can't name a package by "new", which I did in my app: com.eynnzerr.cpbookkeeping_compose.ui.new.NewViewModel For it's reserved and U can't even use it to name your package... After editing it my problem got solved...在我提出这个问题后我马上得到了答案......看来你不能用“新”来命名 package,我在我的应用程序中这样做了:com.eynnzerr.cpbookkeeping_compose.ui.new.NewViewModel 因为它是保留的和你甚至不能用它来命名你的 package ......编辑后我的问题得到了解决......

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 java.lang.RuntimeException:无法创建 class ViewModel [Kotlin] 的实例 - java.lang.RuntimeException: Cannot create an instance of class ViewModel [Kotlin] java.lang.RuntimeException:无法创建 ViewModel class 的实例 - java.lang.RuntimeException: Cannot create an instance of ViewModel class 刀柄匕首错误 java.lang.RuntimeException:无法创建 class HomeFragmentViewModel 的实例 - Hilt Dagger Error java.lang.RuntimeException: Cannot create an instance of class HomeFragmentViewModel java.lang.RuntimeException:当android重新创建Activity和Fragment时,无法创建类ViewModel的实例 - java.lang.RuntimeException: Cannot create an instance of class ViewModel, when android recreates Activity and Fragment java.lang.RuntimeException:无法创建 class com.example.cookpadapp.viewmodel.CookpadViewModel+ 的实例 - java.lang.RuntimeException: Cannot create an instance of class com.example.cookpadapp.viewmodel.CookpadViewModel+ at java.lang.RuntimeException:无法创建 yodgorbek.komilov.musobaqayangiliklari.viewmodel.MainViewModel 类的实例? - java.lang.RuntimeException: Cannot create an instance of class yodgorbek.komilov.musobaqayangiliklari.viewmodel.MainViewModel? java.lang.RuntimeException:无法在单元测试中创建 class ViewModel 的实例 - java.lang.RuntimeException: Cannot create an instance of class ViewModel in unit test java.lang.RuntimeException:无法创建类MovieViewModel的实例&存储库尚未初始化 - java.lang.RuntimeException: Cannot create an instance of class MovieViewModel& repository has not been initialized java.lang.RuntimeException:无法创建类 com.example.homeactivity.activities.editprofile.EditProfileViewModel 的实例 - java.lang.RuntimeException: Cannot create an instance of class com.example.homeactivity.activities.editprofile.EditProfileViewModel 无法使用刀柄创建视图模型 class 的实例 - Cannot create an instance of viewmodel class with hilt
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM