You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

首次使用Hilt的字典App崩溃,无法创建ViewModel实例

问题:使用Hilt依赖注入时,无法创建WordInfoViewModel实例导致App崩溃

崩溃日志

E/AndroidRuntime: FATAL EXCEPTION: main
    Process: ir.arinateam.dictionary, PID: 23787
    java.lang.RuntimeException: Cannot create an instance of class ir.arinateam.dictionary.feature_dictionary.presentation.WordInfoViewModel
        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.SavedStateViewModelFactory.create(SavedStateViewModelFactory.kt:175)
        at androidx.lifecycle.SavedStateViewModelFactory.create(SavedStateViewModelFactory.kt:138)

相关代码

WordInfoModule类

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

    @Provides
    @Singleton
    fun provideGetWordInfoUseCase(repository: WordInfoRepository): GetWordInfo {
        return GetWordInfo(repository)
    }

    @Provides
    @Singleton
    fun provideWordInfoDatabase(app: Application): WordInfoDatabase {
        return Room.databaseBuilder(
            app.applicationContext, WordInfoDatabase::class.java, "word_db"
        ).addTypeConverter(Converters(GsonParser(Gson())))
            .build()
    }

    @Provides
    @Singleton
    fun provideWordInfoRepository(
        db: WordInfoDatabase,
        api: DictionaryApi
    ): WordInfoRepository {
        return WordInfoRepositoryImpl(api, db.dao)
    }

    @Provides
    @Singleton
    fun provideDictionaryApi(): DictionaryApi {
        return Retrofit.Builder()
            .baseUrl(DictionaryApi.BASE_URL)
            .addConverterFactory(GsonConverterFactory.create())
            .build()
            .create(DictionaryApi::class.java)
    }
}

MainActivity代码

@AndroidEntryPoint
class MainActivity : AppCompatActivity() {

private lateinit var bindingActivity: ActivityMainBinding

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    bindingActivity = DataBindingUtil.setContentView(this, R.layout.activity_main)

    val viewModel: WordInfoViewModel by viewModels {
        SavedStateViewModelFactory(application, this)
    }
    
    lifecycleScope.launch {

        viewModel.eventFlow.collectLatest { event ->

            when (event) {

                is WordInfoViewModel.UIEvent.ShowSnackbar -> {
                    Snackbar.make(bindingActivity.root, event.message, Snackbar.LENGTH_SHORT)
                        .show()
                }

            }

        }

    }
}
}

WordInfoViewModel代码

@HiltViewModel
class WordInfoViewModel @Inject constructor(
private val getWordInfo: GetWordInfo
) : ViewModel() {

private val _searchQuery = mutableStateOf<String>("")
val searchQuery: State<String> = _searchQuery

private val _state = mutableStateOf<WordInfoState>(WordInfoState())
val state: State<WordInfoState> = _state

private val _eventFlow = MutableSharedFlow<UIEvent>()
val eventFlow = _eventFlow.asSharedFlow()

private var searchJob: Job? = null

fun onSearch(query: String) {

    _searchQuery.value = query
    searchJob?.cancel()
    searchJob = viewModelScope.launch {
        delay(500L)
        getWordInfo(query)
            .onEach { result ->
                when (result) {
                    is Resource.Success -> {
                        _state.value = state.value.copy(
                            wordInfoItems = result.data ?: emptyList(),
                            isLoading = false
                        )
                    }
                    is Resource.Error -> {
                        _state.value = state.value.copy(
                            wordInfoItems = result.data ?: emptyList(),
                            isLoading = false
                        )
                        _eventFlow.emit(UIEvent.ShowSnackbar(result.message ?: "Unknown Error"))
                    }
                    is Resource.Loading -> {
                        _state.value = state.value.copy(
                            wordInfoItems = result.data ?: emptyList(),
                            isLoading = true
                        )
                    }
                }
            }.launchIn(this)
    }

}

sealed class UIEvent {
    data class ShowSnackbar(val message: String) : UIEvent()
}

}

问题原因

你在MainActivity中手动指定SavedStateViewModelFactory创建ViewModel,绕过了Hilt的依赖注入机制。WordInfoViewModel用@HiltViewModel注解标记,且构造函数通过@Inject声明需要注入GetWordInfo实例,只有Hilt提供的ViewModelFactory才能正确解析并注入这些依赖。手动传入的SavedStateViewModelFactory无法获取Hilt管理的依赖实例,导致ViewModel创建失败引发崩溃。

另外需确认自定义Application类是否添加@HiltAndroidApp注解,这是Hilt初始化的必要条件,缺失也会导致依赖注入失败。

解决方案

  1. 修改MainActivity的ViewModel初始化代码:
    移除手动指定的工厂类,直接使用默认的viewModels()委托,Hilt会自动提供适配的Factory:

    val viewModel: WordInfoViewModel by viewModels()
    
  2. 确保Application类添加@HiltAndroidApp注解:
    若未创建自定义Application类,新建并添加注解:

    @HiltAndroidApp
    class DictionaryApplication : Application()
    

    同时在AndroidManifest.xml中指定该Application:

    <application
        android:name=".DictionaryApplication"
        ...>
        ...
    </application>
    

完成以上修改后,Hilt就能正确注入GetWordInfo实例,ViewModel可正常创建,App不会再崩溃。

内容的提问来源于stack exchange,提问作者Pooya Jannati Poor

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.17 05:46:06