0

I want to add the random generated integer into my MutableList in Player class when I use the random integer generator method located in Player class in my fragment then I want to pass this MutableList to Fragment with using Livedata(I'm not sure if i'm doing right with using livedata).Then show the MutableList in TextView.But MutableList returns the default value not after adding. So what am i doing wrong ? What should i do ? Thank you

MY 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")

    }

}

MY FRAGMENT

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")
            }

        })
    }
}

MY VIEWMODEL

class DenemeViewModel : ViewModel() {

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

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


}

MY LOG

PHOTO OF THE LOGS

Tenfour04
  • 83,111
  • 11
  • 94
  • 154
korsdetek
  • 3
  • 2
  • Does this answer your question? [Notify Observer when item is added to List of LiveData](https://stackoverflow.com/questions/47941537/notify-observer-when-item-is-added-to-list-of-livedata) – Henry Twist Mar 31 '22 at 19:42
  • I saw this same code smell in your classmate's code: `Superman("",2).numberss`. Was that code already in your starting project? It doesn't make sense to create something to pull numbers out of it and then immediately throw the source away (unless it's a factory class). – Tenfour04 Mar 31 '22 at 19:43
  • @HenryTwist Thank you I'll check it tommorow to see if it works – korsdetek Mar 31 '22 at 21:44
  • @Tenfour04 What's the alternative can you tell me ? Because I couldn't find a better way to get that MutableList from class and use it in ViewModel – korsdetek Mar 31 '22 at 21:45
  • Well it doesn’t make sense that you would want to do that in the first place. Why is a list that is part of what a “Superman” is useful outside Superman, especially if he’s already dead (object destroyed)? – Tenfour04 Mar 31 '22 at 22:12
  • @Tenfour04 Superman class inherits Player class thats all so I could reach that random generated list from Superman too. I don't destroy Superman it's for test. Superman has a random generated health value between 1-50 and my attack method in Player class generates random damage value between 1-10 .I'm just trying to get those random generated damage values from Player class and show them in fragment's textview. And I'm asking you again HOW CAN I DO THIS ? stop saying It doesn't make sense etc If i could do the right thing I wouldn't ask this question here so help me please – korsdetek Apr 01 '22 at 09:05
  • I’m trying to understand what you’re actually trying to accomplish because this is an XY problem. Usually I can kind of tell by looking at code even if it has mistakes, but in this case I’m not sure which is why I was asking for more explanation. I think the issue is that you aren’t quite grasping yet the concept of class instances. If you want the random numbers from a Superman you created earlier, you have to get them from that instance, not some new instance you just created by calling the constructor again. – Tenfour04 Apr 01 '22 at 12:43
  • Evidently you have a Superman that is part of some game state. Then it needs to be referenced by a property somewhere (not just in a local variable inside a function) so you can continually access the same instance wherever you need it. But it's kind of impossible to tell you exactly how to do that, where to put it, etc., since this I don't know the requirements of your project or all the details. – Tenfour04 Apr 01 '22 at 12:45
  • "But it's kind of impossible to tell you exactly how to do that, where to put it, etc., since this I don't know the requirements of your project or all the details." @Tenfour04 This isn't a project.I watched a profesor from youtube he was talking about inheritance in java so I used his codes in Kotlin I've changed some codes because they werent working in Kotlin here the video www.youtube.com/watch?v=6vtIdeYND3g&list=PLhPyEFL5u-i3tikmnS9QAFi7YuLWR7q8P&index=16 – korsdetek Apr 01 '22 at 13:50
  • @Tenfour04 I have a class and that class has method that creates random numbers and to do that I call this method in fragment in while loop.Everytime it works in loop it creates a number.SO All I need is those numbers to show them in textview that's all but I couldn't manage to do it in 5 days so sad – korsdetek Apr 01 '22 at 13:53

1 Answers1

1

Your Superman is evidently part of some ongoing game, not something that should be created and then destroyed inside the action function. So you need to store it in a property. This kind of state is usually stored in a ViewModel on Android so it can outlive the Fragment.

Currently, you are creating a Superman in your action function, but anything created in a function is automatically sent do the garbage collector (destroyed) if you don't store the reference in a property outside the function.

Every time you call the Superman constructor, such as in your line damageList.value = Superman("",2).numberss, you are creating a new instance of a Superman that has no relation to the one you were working with in the action() function.

Also, I recommend that you do not use LiveData until you fully grasp the basics of OOP: what object references are, how to pass them around and store them, and when they get sent to the garbage collector.

So, I would change your ViewModel to this. Notice we create a property and initialize it with a new Superman. Now this Superman instance will exist for as long as the ViewModel does, instead of only inside some function.

class DenemeViewModel : ViewModel() {

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

}

Then in your frgament, you can get this same Superman instance anywhere you need to use it, whether it be to deal some damage to it or get the current value of its numberss to put in an EditText.

Also, I noticed in your action function that you have a while loop that repeatedly deals damage until Superman is dead. (It also incorrectly observes live data over and over in the loop, but we'll ignore that.) The problem with this is that the while loop is processed to completion immediately, so you won't ever see any of the intermediate text. You will only immediately see the final text. You probably want to put some delays inside the loop to sort of animate the series of events that are happening. You can only delay easily inside a coroutine, so you'll need to wrap the while loop in a coroutine launch block. In a fragment when working with views, you should do this with viewLifecycleOwner.lifecycleScope.launch.

Finally, if you set playerIsDead to true on the first iteration of the loop, you might as well remove the whole loop. I'm guessing you want to wrap an if-condition around that line of code. But since your code above doesn't modify player health yet, there's no sensible way to determine when a player should be dead, so I've commented out the while loop

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
    //}
}
Tenfour04
  • 83,111
  • 11
  • 94
  • 154
  • It's working perfectly with animation.I understand oop so much better right now because you've explained,fixed and show better way about many things I was wondering about.About that loop, there was a method determines the player health in Player class and also It was determining the dead or alive situation and there was a opponent player object in attack method and I was using it like opponent.determineHealth(damage). And then in while loop there were this codes superMan.attack(batMan) batMan.attack(superMan). So Thank you for mentoring and the time you spent to write this profesor Tenfour – korsdetek Apr 01 '22 at 19:12