无法在 Kotlin 中更改 MutableList 的值 class

Can't change the value of MutableList in a Kotlin class

当我在片段中使用位于 Player class 中的随机整数生成器方法时,我想将随机生成的整数添加到 Player class 中的 MutableList 中,然后我想将此 MutableList 传递给使用 Livedata 的片段(我不确定我使用 livedata 是否正确)。然后在 TextView.But MutableList returns 中显示 MutableList 添加后的默认值。 那我做错了什么?我应该怎么办 ? 谢谢

我的CLASS

open class Player {

    //property
    private var playerName : String
    private var playerHealth : Int
    var playerIsDead : Boolean = false

    //constructor
    constructor(playerName:String,playerHealth:Int){
        this.playerName = playerName
        this.playerHealth = playerHealth
    }


    var numberss: MutableList<Int> = mutableListOf()

    fun attack(){
        //Create a random number between 1 and 10
        var damage = (1..10).random()

        //Subtract health points from the opponent

        Log.d("TAG-DAMAGE-WRITE","$damage")

        numberss.add(damage)
        Log.d("TAG-DAMAGE-ADD-TO-LIST","$numberss")

        Log.d("TAG-NUMBER-LIST-LATEST-VERSION","$numberss")

    }

}

我的片段

class ScreenFragment : Fragment() {

    var nickname : String? = null
    private lateinit var viewModel : DenemeViewModel

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

    }

    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        // Inflate the layout for this fragment
        return inflater.inflate(R.layout.fragment_screen, container, false)
    }

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)

        viewModel = ViewModelProvider(this).get(DenemeViewModel::class.java)


        arguments?.let {
            nickname = ScreenFragmentArgs.fromBundle(it).nickName
        }
        sFtextView.text = "Player : $nickname"
        action()

    }

    private fun action(){
        val health1 = (1..50).random()
        val health2 = (1..50).random()

        val superMan = Superman("Dusman",health1,)

        while(superMan.playerIsDead == false){
            //attack each other
            superMan.attack()
            sFtextsonuc.text = "Superman oldu"
            viewModel.setData()
            observeLiveData()

           superMan.playerIsDead = true
        }
    }

    fun observeLiveData(){
        viewModel.damageList.observe(viewLifecycleOwner, Observer { dmgList ->

            dmgList?.let {

                sFtextsonuc.text = it.toString()
                Log.d("TAG-THE-LIST-WE'VE-SENT-TO-FRAGMENT","$it")
            }

        })
    }
}

我的视图模型

class DenemeViewModel : ViewModel() {

    val damageList:MutableLiveData<MutableList<Int>> = MutableLiveData()

    fun setData(){
        damageList.value = Superman("",2).numberss
        Log.d("TAG-VIEWMODEL","${damageList.value}")
    }


}

我的日志

PHOTO OF THE LOGS

你的超人显然是一些正在进行的游戏的一部分,而不是应该在 action 函数中创建然后销毁的东西。所以你需要把它存储在一个属性中。这种状态通常存储在 Android 上的 ViewModel 中,因此它可以比 Fragment 更有效。

目前,您正在 action 函数中创建一个超人,但如果您不将引用存储在 属性 在函数外。

每次您调用超人构造函数时,例如在您的行 damageList.value = Superman("",2).numberss 中,您都在创建超人的一个 新实例,它与超人没有关系您在 action() 函数中使用。

此外,我建议您在完全掌握 OOP 的基础知识之前不要使用 LiveData:什么是对象引用,如何传递和存储它们,以及它们何时被发送到垃圾收集器。

因此,我会将您的 ViewModel 更改为此。请注意,我们创建了一个 属性 并用一个新的超人对其进行了初始化。现在,只要 ViewModel 存在,这个超人实例就会存在,而不是只存在于某个函数中。

class DenemeViewModel : ViewModel() {

    val superman = Superman("Dusman", (1..50).random())

}

然后在你的frgament中,你可以在任何你需要使用它的地方得到这个相同的Superman实例,无论是对它造成一些伤害还是得到它的当前值numberss放入一个 EditText。

此外,我注意到您的 action 函数中有一个 while 循环,它会反复造成伤害,直到超人死去。 (它在循环中一遍又一遍地错误地观察实时数据,但我们将忽略它。)这样做的问题是 while 循环被立即处理完成,因此您永远不会看到任何中间文本。您只会立即看到最终文本。您可能希望在循环内放置一些延迟,以对正在发生的一系列事件进行动画处理。您只能在协程内轻松延迟,因此您需要将 while 循环包装在协程启动块中。在使用视图的片段中,您应该使用 viewLifecycleOwner.lifecycleScope.launch.

最后,如果您在循环的第一次迭代中将 playerIsDead 设置为 true,您还不如删除整个循环。我猜您想在该行代码周围包装一个 if-condition 。但是由于您上面的代码还没有修改玩家的健康状况,因此没有明智的方法来确定玩家何时应该死亡,所以我注释掉了 while 循环

private fun action() = viewLifecycleOwner.lifecycleScope.launch {
    val superMan = viewModel.superman

    //while(superMan.playerIsDead == false){
        //attack each other
        superMan.attack()
        sFtextsonuc.text = "Superman oldu"
        delay(300) // give user a chance to read the text before changing it
        sFtextsonuc.text = superMan.numberss.joinToString()
        delay(300) // give user a chance to read the text before changing it

        // TODO superMan.playerIsDead = true
    //}
}