android - Fragment 类、MVVM、Viewmodel 中未解析的引用(vars)

标签 android kotlin android-viewmodel

我正在学习关于使用 Kotlin 开发 Android 应用程序的 UDACITY 免费类(class),实际上我在类(class)的 Viewmodel/MVVM 部分,即实现 Viewmodel 类以更好地分离关注点。所以无论如何,我现在被阻止了。我正在进行的练习是关于创建 Viewmodel 类并将变量和函数从 Fragment 类转移到这个新创建的类。我一步一步地按照教程,检查提供的 git diff 上的正确答案,我仍然发现自己被 Unresolved reference 错误所阻止。

在更改代码之前,我必须更新我的 Gradle 模块文件以使用 ViewModel

//ViewModel
implementation 'androidx.lifecycle:lifecycle-extensions:2.2.0'

然后我必须在我的 Fragment 类中声明我的 Viewmodel 对象
gameViewModel = ViewModelProviders.of(this).get(GameViewModel::class.java)

ViewModelProviders 被弃用,旧类(class),我不得不在搜索后更改为
gameViewModel = ViewModelProvider(this).get(GameViewModel::class.java)

这似乎是正确的做法,但我仍然在变量 word (gameViewModel. word ) 和 score (gameViewModel. score ) 上留下了一些 Unresolved 引用 fragment 类,无法编译。我不知道我是否正确声明了 Viewmodel 对象,或者我是否遗漏了其他东西......

我没有这个问题, Unresolved reference ,我的 ViewModel 类函数,即 gameViewModel.onCorrect() 和 gameViewModel.onSkip()。它们似乎在 Fragment 类中被正确声明和调用,这让我想到了关于我的变量、单词和分数的问题......

我的 fragment 课
package com.example.android.guesstheword.screens.game

import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.databinding.DataBindingUtil
import androidx.fragment.app.Fragment
import androidx.lifecycle.ViewModelProvider
import androidx.navigation.fragment.NavHostFragment.findNavController
import com.example.android.guesstheword.R
import com.example.android.guesstheword.databinding.GameFragmentBinding
import timber.log.Timber

class GameFragment : Fragment() {

private lateinit var binding: GameFragmentBinding

private lateinit var gameViewModel: GameViewModel



override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
                          savedInstanceState: Bundle?): View? {

    // Inflate view and obtain an instance of the binding class
    binding = DataBindingUtil.inflate(
            inflater,
            R.layout.game_fragment,
            container,
            false
    )

    Timber.i("onCreateView  GameFragment called")
    gameViewModel = ViewModelProvider(this).get(GameViewModel::class.java)
    Timber.i("ViewModelProvider is called")

    binding.correctButton.setOnClickListener {
        gameViewModel.onCorrect()
        updateScoreText()
        updateWordText()
    }
    binding.skipButton.setOnClickListener {
        gameViewModel.onSkip()
        updateScoreText()
        updateWordText()
    }
    updateScoreText()
    updateWordText()
    return binding.root

}

/**
 * Called when the game is finished
 */
fun gameFinished() {
    val action = GameFragmentDirections.actionGameToScore(gameViewModel.score)
    findNavController(this).navigate(action)
}

/** Methods for updating the UI **/

private fun updateWordText() {
    binding.wordText.text = gameViewModel.word
}

private fun updateScoreText() {
    binding.scoreText.text = gameViewModel.score.toString()
}

override fun onDestroyView() {
    super.onDestroyView()
    Timber.i("onDestroyView GameFragment called")
}
}

我的 ViewModel 类
package com.example.android.guesstheword.screens.game

import androidx.lifecycle.ViewModel
import timber.log.Timber

var word = ""
var score = 0

private lateinit var wordList: MutableList<String>

class GameViewModel: ViewModel() {
init {
    Timber.i("GameViewModel is created")
    resetList()
    nextWord()
}

override fun onCleared() {
    super.onCleared()
    Timber.i("GameViewModel is cleared")
}
/**
 * Resets the list of words and randomizes the order
 */


fun resetList() {
    wordList = mutableListOf(
            "queen",
            "hospital",
            "basketball",
            "cat",
            "change",
            "snail",
            "soup",
            "calendar",
            "sad",
            "desk",
            "guitar",
            "home",
            "railway",
            "zebra",
            "jelly",
            "car",
            "crow",
            "trade",
            "bag",
            "roll",
            "bubble"
    )
    wordList.shuffle()
}
/**
 * Moves to the next word in the list
 */
private fun nextWord() {
    //Select and remove a word from the list
    if (wordList.isEmpty()) {
        //gameFinished()
    } else {
        word = wordList.removeAt(0)
    }
}
/** Methods for buttons presses **/

fun onSkip() {
    score--
    nextWord()
}

fun onCorrect() {
    score++
    nextWord()
}
}

我哪里搞砸了?

最佳答案

您尝试访问的变量不在同一范围内:

var word = ""
var score = 0

private lateinit var wordList: MutableList<String>

class GameViewModel: ViewModel() {
...

您的变量是在 ViewModel 之外声明的,请将它们添加到类 GameViewModel 中使它们成为实例变量:
class GameViewModel: ViewModel() {
var word = ""
var score = 0
...
}

关于android - Fragment 类、MVVM、Viewmodel 中未解析的引用(vars),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61627986/

相关文章:

android - 使用导航图范围 : NavController is not available before onCreate() 注入(inject) View 模型

android - 结合 android ViewModel 和数据绑定(bind)的最佳实践

android - 在 Xamarin 中正确绑定(bind) native 库

java - Kotlin for android 和 static final 内部类

android - 带有自定义适配器 (BaseAdapter) 的 MultiAutoCompleteTextView

Android Studio中的日期和时间(科林语言)

java - 如何在 Kotlin 中将日期时间字符串转换为 UTC 格式

android - 发布或设置 MutableLiveData - 未调用观察者 onChanged

Android xml id命名

java - Android 应用程序和 AsyncTask 未按预期运行