Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Unable to create updated UI with new image in JetPack Compose

I'm trying to create simple Dice Roller JetPack Compose App. I create an Image compose and button compose. Whenever I click on the button, log statement shows button is clicked but I'm unable to update the dice image according to that data. I'll attach my code for future references. What am I doing wrong?

package com.example.mydiceroller

import android.os.Bundle
import android.util.Log
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.foundation.Image
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.material3.Button
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.painterResource
import androidx.lifecycle.ViewModelProvider

class MainActivity : ComponentActivity() {

    lateinit var mainViewModel: MainViewModel
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {

            mainViewModel = ViewModelProvider(this).get(MainViewModel::class.java)
            Column(
                modifier = Modifier
                    .fillMaxSize(),
                horizontalAlignment = Alignment.CenterHorizontally,
                verticalArrangement = Arrangement.Center
            ) {
                DiceImage(count = mainViewModel.count)
                Button(onClick = {
                    mainViewModel.rollDice()
                }
                )
                {
                    Text(text = "Let's Roll")
                }

            }
        }
    }

}

@Composable
fun DiceImage(count: Int) {


    Log.d("countValue", "${count}")

    var countId=when (count) {
        1 -> R.drawable.dice_1
        2 -> R.drawable.dice_2
        3 -> R.drawable.dice_3
        4 -> R.drawable.dice_4
        5 -> R.drawable.dice_5
        else -> R.drawable.dice_6
    }
    Image(
        painter = painterResource(id = countId), contentDescription = ""
    )
}

MainViewModel.kt

package com.example.mydiceroller

import android.util.Log
import androidx.lifecycle.ViewModel
import java.util.Random

class MainViewModel : ViewModel() {
    var count: Int = 1

    fun rollDice(): Int {
        count = (Random().nextInt(6) + 1)
        Log.d("ViewModel", "ButtonClicked")
        return count
    }
}

I also tried mutableStateOf but failed

like image 489
Aamir Khan Avatar asked Nov 20 '25 12:11

Aamir Khan


1 Answers

The problem is that your Compose UI cannot detect that count changed in the view model.

You need to store count in a State object. In a composable you would use something like this (by unwraps the State so it is an Int and can be more easily used):

var count: Int by remember { mutableStateOf(1) }

Whenever this variable is updated a recomposition is triggered and the UI is updated accodingly. Since you use a view model to store count you need to employ a Flow:

class MainViewModel : ViewModel() {
    private val _count = MutableStateFlow(1)
    val count = _count.asStateFlow()

    fun rollDice() {
        Log.d("ViewModel", "ButtonClicked")
        _count.value = (1..6).random()
    }
}

Whenever rollDice is called the count flow changes. You can convert this flow in your composables into a Compose State object with collectAsStateWithLifecycle (You need the gradle dependency androidx.lifecycle:lifecycle-runtime-compose):

setContent {
    val mainViewModel: MainViewModel = viewModel()
    val count: Int by mainViewModel.count.collectAsStateWithLifecycle()

    Column(
        modifier = Modifier
            .fillMaxSize(),
        horizontalAlignment = Alignment.CenterHorizontally,
        verticalArrangement = Arrangement.Center,
    ) {
        DiceImage(count = count)

        Button(onClick = {
            mainViewModel.rollDice()
        }) {
            Text(text = "Let's Roll")
        }
    }
}
like image 100
Leviathan Avatar answered Nov 22 '25 04:11

Leviathan



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!