无法在 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
//}
}
当我在片段中使用位于 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
//}
}