首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >无法创建类ViewModel的实例,无法找到原因

无法创建类ViewModel的实例,无法找到原因
EN

Stack Overflow用户
提问于 2022-08-12 14:07:30
回答 2查看 408关注 0票数 1

每当我点击标题时,应用程序Crashes就会显示我对Android来说是个新手,使用匕首柄,系外玩家,

这就是我碰到错误的地方:

松片

代码语言:javascript
运行
复制
@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

代码语言:javascript
运行
复制
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)
            }
        }
    }
}

逻辑猫:

代码语言:javascript
运行
复制
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) 
EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2022-08-16 08:08:35

@ViewModelInject已被废弃。您可以通过检查这里获取更多信息。

在较新的版本中,需要用@AndroidViewModel注释viewmodel类,用@Inject对构造函数进行注释。

代码语言:javascript
运行
复制
@AndroidViewModel
class SongViewModel @Inject constructor(
    musicServiceConnection: MusicServiceConnection
) : ViewModel() 

希望它能解决这个问题。

票数 0
EN

Stack Overflow用户

发布于 2022-08-12 14:48:27

既然您使用的是Hilt,就不应该使用by viewModels()。您应该在提供程序中设置您的MusicServiceConnection,而不是使用private val songViewModel: SongViewModel by viewModels(),而是使用@Inject private lateinit var songViewModel: SongViewModel

我对希尔特不太熟悉,所以我不能提供更多的指导。下面是对by viewModels()出了什么问题的解释,以及如果不是使用依赖注入框架的,您将如何解决这个问题。

在活动或片段中创建ViewModel时,可以提供负责创建ViewModel实例的工厂。如果不提供工厂,则使用默认工厂。

只有当您的ViewModel构造函数的参数为下列之一时,默认工厂才能创建ViewModel实例:

  • constructor()空构造函数(没有参数)
  • constructor(savedStateHandle: SavedStateHandle)
  • constructor(application: Application)
  • constructor(application: Application, savedStateHandle: SavedStateHandle)

我不认为这是很好的记录。我必须看一下Jetpack源代码才能了解它。

由于ViewModel需要一个MusicServiceConnection参数,所以不能使用默认工厂。您需要将显式ViewModelProvider.Factory作为参数提供给by viewModels()

这场训练有一个为ViewModel创建一个需要构造函数特殊参数的ViewModelProvider.Factory类的示例。在您的例子中,解决方案可能如下所示:

代码语言:javascript
运行
复制
class SongViewModelFactory(private val musicServiceConnection: MusicServiceConnection) : ViewModelProvider.Factory {
    override fun <T : ViewModel> create(modelClass: Class<T>): T {
        require(modelClass.isAssignableFrom(SongViewModel::class.java)) { "Unknown ViewModel class" }
        @Suppress("UNCHECKED_CAST")
        return SongViewModel(musicServiceConnection) as T
    }
}

我不知道您的MusicServiceConnection类是从哪里来的,但是让我们假设您可以简单地为您的活动实例化它一次,使用一个空的构造函数。然后你就会替换

代码语言:javascript
运行
复制
private val songViewModel: SongViewModel by viewModels()

使用

代码语言:javascript
运行
复制
private val songViewModel: SongViewModel by viewModels {
    SongViewModelFactory(MusicServiceConnection())
}

注意,您将一个lambda函数传递给viewModels,而不是直接传递工厂的一个实例。这是因为工厂只创建了一次,即使您的活动被多次重新创建(比如用户来回旋转屏幕)。这个lambda中的代码仅在应用程序导航到此屏幕时调用一次,即使该活动是为屏幕旋转或其他配置更改重新创建的。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/73335428

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档