androidkotlinandroid-jetpack-composemutablestateof

How to properly use mutability in Jetpack Compose to update Text when a value in a companion object is changed? (Kotlin)


EXPLANATION:

I have a budget screen

the Home.kt class basics are here:

@Composable
fun Home(navController: NavController) {
    var currentBalance = Budget.currentBalance

    Column(
        /* ... */
    ) {
        /* ... */
    }
}

the Text is determined here (deep within the Column shown above):

Text(
    text = if (currentBalance>= 0) // this ternary operator adds the "$" and/or "-" cleanly
        "\$${"%.${2}f".format(currentBalance)}" // eg. 2.56 -> $2.56
    else "-\$${"%.${2}f".format(-currentBalance)}", // eg. -7.94 -> -$7.94
    textAlign = TextAlign.Center,
    color = MaterialTheme.colorScheme.onPrimary,
    style = MaterialTheme.typography.displayLarge
)

my Budget.kt class basics are here:

class Budget {
    companion object {
        var currentBalance: Double = 0.0
            get() = field
            private set(value) {
                field = value
            }

        /* ... */

        private fun AddBalance(funds: Double) {
            Companion.currentBalance += funds
            Save()
        } // Adds money to Balance

        private fun RemoveBalance(funds: Double) {
            Companion.currentBalance -= funds
            Save()
        } // Removes money from Balance

        /* ... */
    }
}

AddBalance() and RemoveBalance() are called from another method that handles all transactions based on a type, I have confirmed via logs that Budget.currentBalance is being changed properly, and if you reopen the app (the balance is saved in a text file) or recompose it via live updates, the Text updates as expected;

the Text just won't recompose instantaneously.

ATTEMPTED SOLUTIONS:

firstly, I tried to change Home().currentBalance to a mutableDoubleState as that's how other values do it

@Composable
fun Home(navController: NavController) {
    var currentBalance: MutableDoubleState = remember {
        mutableDoubleStateOf(Budget.currentBalance)
    }

    Column(
        /* ... */
    )
}

but that didn't work and I've concluded from this thread that I need to change Home().currentBalance.value somehow from Budget.Companion but I'm not sure how to go about that, the implementation example was confusing. no Exceptions have occurred, my app does not crash; it just does not recompose when I want it to.

please help :]

~ kee


Solution

  • Compose track changes of the state. You hasn't defined any state inside your companion object. Change your current balance field to a mutable state object.

    var currentBalance = 
        mutableDoubleStateOf(0.0)
    

    and also you need to change your add and remove method.

     fun AddBalance(funds: Double) {
            Companion.currentBalance.value += funds
            Save()
        }
    

    then you can use the currentBalance object in the composable like this

     var currentBalance = Budget.currentBalance.value
    

    if You find lazy to use .value everytime for currentBalance then

       var currentBalance by mutableStateOf(0.0)
      private set
    

    then your add Method would be

     fun addBalance(funds : Double){
      currentBalance += funds
    }
    

    and you can use your current Balance in the composable

      var currentBalance = Budget.currentBalance