Android点击标题崩溃:无法创建SongViewModel实例求助
Dagger Hilt + ExoPlayer 应用崩溃问题:无法创建SongViewModel实例
点击标题时应用崩溃,Logcat报错Cannot create an instance of class SongViewModel,原因是该类没有无参构造函数。
报错触发位置:
SongFragment代码
@AndroidEntryPoint class SongFragments : Fragment(R.layout.fragment_song) { @Inject lateinit var glide: RequestManager private lateinit var mainViewModel: MainViewModel private val songViewModel: SongViewModel by viewModels() private var curplayingSong: sound? = null private var playbackState: PlaybackStateCompat? = null private var shouldUpdateSeekbar = true override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) mainViewModel = ViewModelProvider(requireActivity()).get(MainViewModel::class.java) subscribeToObservers() ivPlayPauseDetail.setOnClickListener { curplayingSong?.let { mainViewModel.playOrToggleSound(it, true) } } seekBar.setOnSeekBarChangeListener(object : SeekBar.OnSeekBarChangeListener { override fun onProgressChanged(seekBar: SeekBar?, progress: Int, fromUser: Boolean) { if (fromUser) { setCurPlayerTimeToTextView(progress.toLong()) } } override fun onStartTrackingTouch(seekBar: SeekBar?) { shouldUpdateSeekbar = false } override fun onStopTrackingTouch(seekBar: SeekBar?) { seekBar?.let { mainViewModel.seekTo(it.progress.toLong()) shouldUpdateSeekbar = true } } }) ivSkipPrevious.setOnClickListener { mainViewModel.skipToPreviousSound() } ivSkip.setOnClickListener{ mainViewModel.skipToNextSound() } } private fun updateTitleAndSongImage(sound: sound) { val title = "${sound.title} - ${sound.subtitle}" tvSongName.text = title glide.load(sound.imageUrl).into(ivSongImage) } private fun subscribeToObservers() { mainViewModel.mediaItems.observe(viewLifecycleOwner){ it?.let { result -> when(result.status){ Status.SUCCESS -> { result.data?.let { sounds -> if (curplayingSong == null && sounds.isNotEmpty()) { curplayingSong = sounds[0] updateTitleAndSongImage(sounds[0]) } } } else -> Unit } } } mainViewModel.curPlayingSound.observe(viewLifecycleOwner) { if(it == null) return@observe curplayingSong = it.toSong() updateTitleAndSongImage(curplayingSong!!) } mainViewModel.playbackState.observe(viewLifecycleOwner) { playbackState = it ivPlayPauseDetail.setImageResource( if (playbackState?.isPlaying == true) R.drawable.ic_pause else R.drawable.ic_play ) seekBar.progress = it?.position?.toInt() ?: 0 } songViewModel.curPlayerPosition.observe(viewLifecycleOwner) { if (shouldUpdateSeekbar) { seekBar.progress = it.toInt() setCurPlayerTimeToTextView(it) } } songViewModel.curSongDuration.observe(viewLifecycleOwner) { seekBar.max = it.toInt() val dateFormat = SimpleDateFormat("mm:ss", Locale.getDefault()) tvSongDuration.text = dateFormat.format(it) } } private fun setCurPlayerTimeToTextView(ms: Long) { val dateFormat = SimpleDateFormat("mm:ss", Locale.getDefault()) tvCurTime.text = dateFormat.format(ms) } }
SongViewModel代码
class SongViewModel @ViewModelInject constructor( musicServiceConnection: MusicServiceConnection ) : ViewModel() { private val playbackState = musicServiceConnection.playBackState private val _curSongDuration = MutableLiveData<Long>() val curSongDuration: LiveData<Long> = _curSongDuration private val _curPlayerPosition = MutableLiveData<Long>() val curPlayerPosition: LiveData<Long> = _curPlayerPosition init { updateCurrentplayerPostion() } @SuppressLint("NullSafeMutableLiveData") private fun updateCurrentplayerPostion() { viewModelScope.launch { while(true) { val pos = playbackState.value?.currentPlaybackPosition if(curPlayerPosition.value != pos){ _curPlayerPosition.postValue(pos) _curSongDuration.postValue(MusicService.curSoundDuration) } delay(UPDATE_PLAYER_POSITION_INTERVAL) } } } }
Logcat错误信息
2022-08-12 19:11:39.122 10888-10983/com.fridayhouse.snoozz E/ion: ioctl c0044901 failed with code -1: Invalid argument 2022-08-12 19:11:39.318 10888-10888/com.fridayhouse.snoozz E/AndroidRuntime: FATAL EXCEPTION: main Process: com.fridayhouse.snoozz, PID: 10888 java.lang.RuntimeException: Cannot create an instance of class com.fridayhouse.snoozz.ui.viewmodels.SongViewModel 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:203) at dagger.hilt.android.internal.lifecycle.HiltViewModelFactory.create(HiltViewModelFactory.java:111) at androidx.lifecycle.ViewModelProvider$Factory.create(ViewModelProvider.kt:83) at androidx.lifecycle.ViewModelProvider.get(ViewModelProvider.kt:187) at androidx.lifecycle.ViewModelProvider.get(ViewModelProvider.kt:153) at androidx.lifecycle.ViewModelLazy.getValue(ViewModelLazy.kt:53) at androidx.lifecycle.ViewModelLazy.getValue(ViewModelLazy.kt:35) at com.fridayhouse.snoozz.ui.fragments.SongFragments.getSongViewModel(SongFragments.kt:33) at com.fridayhouse.snoozz.ui.fragments.SongFragments.subscribeToObservers(SongFragments.kt:121) at com.fridayhouse.snoozz.ui.fragments.SongFragments.onViewCreated(SongFragments.kt:45) at androidx.fragment.app.Fragment.performViewCreated(Fragment.java:3128) at androidx.fragment.app.FragmentStateManager.createView(FragmentStateManager.java:552) at androidx.fragment.app.FragmentStateManager.moveToExpectedState(FragmentStateManager.java:261) at androidx.fragment.app.FragmentManager.executeOpsTogether(FragmentManager.java:1890) at androidx.fragment.app.FragmentManager.removeRedundantOperationsAndExecute(FragmentManager.java:1814) at androidx.fragment.app.FragmentManager.execPendingActions(FragmentManager.java:1751) at androidx.fragment.app.FragmentManager$5.run(FragmentManager.java:538) at android.os.Handler.handleCallback(Handler.java:938) at android.os.Handler.dispatchMessage(Handler.java:99) at android.os.Looper.loopOnce(Looper.java:233) at android.os.Looper.loop(Looper.java:334) at android.app.ActivityThread.main(ActivityThread.java:8396) at java.lang.reflect.Method.invoke(Native Method) at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:582) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1068) Caused by: java.lang.InstantiationException: java.lang.Class<com.fridayhouse.snoozz.ui.viewmodels.SongViewModel> has no zero argument constructor at java.lang.Class.newInstance(Native Method) at androidx.lifecycle.ViewModelProvider$NewInstanceFactory.create(ViewModelProvider.kt:202) 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:203) at dagger.hilt.android.internal.lifecycle.HiltViewModelFactory.create(HiltViewModelFactory.java:111) at androidx.lifecycle.ViewModelProvider$Factory.create(ViewModelProvider.kt:83) at androidx.lifecycle.ViewModelProvider.get(ViewModelProvider.kt:187) at androidx.lifecycle.ViewModelProvider.get(ViewModelProvider.kt:153) at androidx.lifecycle.ViewModelLazy.getValue(ViewModelLazy.kt:53) at androidx.lifecycle.ViewModelLazy.getValue(ViewModelLazy.kt:35) at com.fridayhouse.snoozz.ui.fragments.SongFragments.getSongViewModel(SongFragments.kt:33) at com.fridayhouse.snoozz.ui.fragments.SongFragments.subscribeToObservers(SongFragments.kt:121) at com.fridayhouse.snoozz.ui.fragments.SongFragments.onViewCreated(SongFragments.kt:45) at androidx.fragment.app.Fragment.performViewCreated(Fragment.java:3128) at androidx.fragment.app.FragmentStateManager.createView(FragmentStateManager.java:552) at androidx.fragment.app.FragmentStateManager.moveToExpectedState(FragmentStateManager.java:261) at androidx.fragment.app.FragmentManager.executeOpsTogether(FragmentManager.java:1890) at androidx.fragment.app.FragmentManager.removeRedundantOperationsAndExecute(FragmentManager.java:1814) at androidx.fragment.app.FragmentManager.execPendingActions(FragmentManager.java:1751) at androidx.fragment.app.FragmentManager$5.run(FragmentManager.java:538) at android.os.Handler.handleCallback(Handler.java:938) at android.os.Handler.dispatchMessage(Handler.java:99) at android.os.Looper.loopOnce(Looper.java:233) at android.os.Looper.loop(Looper.java:334) at android.app.ActivityThread.main(ActivityThread.java:8396) at java.lang.reflect.Method.invoke(Native Method) at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:582) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1068)
问题原因及解决方案
核心问题
你用@ViewModelInject标记了SongViewModel的构造函数,但在Fragment中获取ViewModel时使用了默认的by viewModels(),这个方式不会调用Hilt的ViewModel工厂,而是尝试通过无参构造函数创建实例,导致崩溃。
修复步骤
- 更新ViewModel注解:
废弃的@ViewModelInject已被替换为@HiltViewModel,修改SongViewModel代码:
import dagger.hilt.android.lifecycle.HiltViewModel import javax.inject.Inject @HiltViewModel class SongViewModel @Inject constructor( musicServiceConnection: MusicServiceConnection ) : ViewModel() { // 原有代码不变 }
- 修改Fragment中获取ViewModel的方式:
将Fragment中的:
private val songViewModel: SongViewModel by viewModels()
替换为Hilt专属的扩展方法:
import androidx.hilt.navigation.fragment.hiltViewModel private val songViewModel: SongViewModel by hiltViewModel()
- 确认依赖配置:
确保Module级别的build.gradle中包含Hilt ViewModel相关依赖(版本需与Hilt核心依赖匹配):
implementation "androidx.hilt:hilt-lifecycle-viewmodel:1.0.0" kapt "androidx.hilt:hilt-compiler:1.0.0"
- 清理并重建项目:
执行Build -> Clean Project,再执行Build -> Rebuild Project,确保注解处理器生成正确的代码。
内容的提问来源于stack exchange,提问作者Sidharth
相关产品推荐
相关产品推荐

