• Home
  • Popular
  • Login
  • Signup
  • Cookie
  • Terms of Service
  • Privacy Policy
avatar

Posted by User Bot


26 Mar, 2025

Updated at 18 May, 2025

Why my compose not recompose after state change

My project is a app get data from a ble device and show this. Here is WorkoutSessionScreen:

@Composable
fun WorkoutSessionScreen(
    viewModel: MainViewModel = hiltViewModel(),
    onEndWorkout: () -> Unit = {}
) {
    val state by viewModel.state.collectAsState()
    val exercise by viewModel.exerciseState.collectAsState()

    Scaffold { innerPadding ->
        Column(
            modifier = Modifier
                .fillMaxSize()
                .padding(innerPadding)
        ) {
            // Stat Section (Hiển thị thông tin thống kê)
            WorkoutStatsSection(
                workoutStat = state.sessionStat,
                modifier = Modifier
                    .padding(16.dp)
            )

            Spacer(modifier = Modifier.height(16.dp))

            // Thông tin bài tập
            StatCard(
                title = "Bài tập",
                exercise = exercise,
                value = when (exercise.name) {
                    "Idle" -> "Đang chờ"
                    "Pushup" -> state.sessionStat.pushupReps.toString()
                    "Squat" -> state.sessionStat.squatReps.toString()
                    "Crunch" -> state.sessionStat.crunchReps.toString()
                    else -> "Không xác định"
                },
                modifier = Modifier
                    .fillMaxWidth()
                    .padding(16.dp)
            )


            Spacer(modifier = Modifier.height(32.dp))

            // Các nút điều khiển
            Row(
                modifier = Modifier.fillMaxWidth(),
                horizontalArrangement = Arrangement.SpaceEvenly
            ) {
                Button(
                    onClick = {
                    },
                    modifier = Modifier.width(120.dp)
                ) {
                    Text("Tạm dừng")
                }
                Button(
                    onClick = {
                        onEndWorkout()
                        viewModel.finishSession()
                    },
                    modifier = Modifier.width(120.dp)
                ) {
                    Text("Kết thúc")
                }
            }
        }
    }
}

Here is MainViewModel:

@HiltViewModel
class MainViewModel @Inject constructor(
    private val bleManager: BleManager,
    private val bleGatt: BleGatt
) : ViewModel() {
    private val _state = MutableStateFlow(UiState())
    val state: StateFlow = _state.asStateFlow()

    private val _exerciseState = MutableStateFlow(Exercise("Idle", R.drawable.idle))
    val exerciseState: StateFlow = _exerciseState.asStateFlow()


    init {
        viewModelScope.launch {
            bleGatt.exerciseState.collectLatest { newState ->
                Log.d("ViewModel", "Get state from BLE: ${newState}k" )
                when(newState) {
                    "1" -> {
                        _exerciseState.value = Exercise("Pushup", R.drawable.pushup)
                    }
                    "2" -> {
                        _exerciseState.value = Exercise("Squat", R.drawable.squat)
                    }
                    "3" -> {
                        _exerciseState.value = Exercise("Crunch", R.drawable.crunch)
                    }
                    else -> {
                        _exerciseState.value = Exercise("Idle", R.drawable.idle)
                    }
                }
                if (newState != "4") {
                    updateExerciseCount(newState)
                }
            }
        }
    }

    fun updateExerciseCount(state: String) {
        when (state) {
            "1" -> {
                countPushup()
                Log.d("ViewModel", "Count pushup")
                Log.d("ViewModel", "Current pushup: ${_state.value.sessionStat.pushupReps}")
            }
            "2" -> {
                countSquat()
                Log.d("ViewModel", "Count squat")
                Log.d("ViewModel", "Current squat: ${_state.value.sessionStat.squatReps}")
                Log.d("ViewModel", "Current state: ${this.state.value.sessionStat.squatReps}")
            }
            "3" -> {
                countCrunch()
                Log.d("ViewModel", "Count crunch")
                Log.d("ViewModel", "Current crunch: ${_state.value.sessionStat.crunchReps}")
                Log.d("ViewModel", "Current state: ${this.state.value.sessionStat.crunchReps}")
            }
            else -> {
                Log.d("ViewModel", "Don't get any state")
            }
        }
    }

 ///////

    fun countPushup() {
        _state.update { state ->
            val newPushupReps = state.sessionStat.pushupReps + 1
            val newCalories = calculateSessionCalories(newPushupReps, state.sessionStat.squatReps, state.sessionStat.crunchReps)

            state.copy(
                sessionStat = state.sessionStat.copy(
                    pushupReps = newPushupReps,
                    totalCalories = newCalories
                )
            )
        }
    }

    fun countSquat() {
        _state.update { state ->
            val newSquatReps = state.sessionStat.squatReps + 1
            val newCalories = calculateSessionCalories(state.sessionStat.pushupReps, newSquatReps, state.sessionStat.crunchReps)

            state.copy(
                sessionStat = state.sessionStat.copy(
                    squatReps = newSquatReps,
                    totalCalories = newCalories
                )
            )
        }
    }

    fun countCrunch() {
        _state.update { state ->
            val newCrunchReps = state.sessionStat.crunchReps + 1
            val newCalories = calculateSessionCalories(state.sessionStat.pushupReps, state.sessionStat.squatReps, newCrunchReps)

            state.copy(
                sessionStat = state.sessionStat.copy(
                    crunchReps = newCrunchReps,
                    totalCalories = newCalories
                )
            )
        }
    }

    ///// some other code
}

Here is some log from Logcat:

2025-03-26 10:51:28.203 26994-27033 BleGatt                 com.qtcoding.workouttracker          D  characteristic changed: android.bluetooth.BluetoothGattCharacteristic@aee9130
2025-03-26 10:51:28.204 26994-27033 BleGatt                 com.qtcoding.workouttracker          D  Exercise state change expected: 4
2025-03-26 10:51:28.207 26994-26994 ViewModel               com.qtcoding.workouttracker          D  Get state from BLE: 4k
2025-03-26 10:51:30.236 26994-27033 BleGatt                 com.qtcoding.workouttracker          D  characteristic changed: android.bluetooth.BluetoothGattCharacteristic@aee9130
2025-03-26 10:51:30.238 26994-27033 BleGatt                 com.qtcoding.workouttracker          D  Exercise state change expected: 2
2025-03-26 10:51:30.243 26994-26994 ViewModel               com.qtcoding.workouttracker          D  Get state from BLE: 2k
2025-03-26 10:51:30.244 26994-26994 ViewModel               com.qtcoding.workouttracker          D  Count squat
2025-03-26 10:51:30.244 26994-26994 ViewModel               com.qtcoding.workouttracker          D  Current squat: 1
2025-03-26 10:51:30.244 26994-26994 ViewModel               com.qtcoding.workouttracker          D  Current state: 1
2025-03-26 10:51:32.267 26994-27033 BleGatt                 com.qtcoding.workouttracker          D  characteristic changed: android.bluetooth.BluetoothGattCharacteristic@aee9130
2025-03-26 10:51:32.270 26994-27033 BleGatt                 com.qtcoding.workouttracker          D  Exercise state change expected: 1
2025-03-26 10:51:32.276 26994-26994 ViewModel               com.qtcoding.workouttracker          D  Get state from BLE: 1k
2025-03-26 10:51:32.277 26994-26994 ViewModel               com.qtcoding.workouttracker          D  Count pushup
2025-03-26 10:51:32.277 26994-26994 ViewModel               com.qtcoding.workouttracker          D  Current pushup: 1
2025-03-26 10:51:34.268 26994-27033 BleGatt                 com.qtcoding.workouttracker          D  characteristic changed: android.bluetooth.BluetoothGattCharacteristic@aee9130
2025-03-26 10:51:34.269 26994-27033 BleGatt                 com.qtcoding.workouttracker          D  Exercise state change expected: 2
2025-03-26 10:51:34.274 26994-26994 ViewModel               com.qtcoding.workouttracker          D  Get state from BLE: 2k
2025-03-26 10:51:34.275 26994-26994 ViewModel               com.qtcoding.workouttracker          D  Count squat
2025-03-26 10:51:34.275 26994-26994 ViewModel               com.qtcoding.workouttracker          D  Current squat: 2
2025-03-26 10:51:34.275 26994-26994 ViewModel               com.qtcoding.workouttracker          D  Current state: 2
2025-03-26 10:51:34.868 26994-27863 BluetoothAdapter        com.qtcoding.workouttracker          I  STATE_ON
2025-03-26 10:51:34.869 26994-27863 BluetoothLeScanner      com.qtcoding.workouttracker          D  could not find callback wrapper
2025-03-26 10:51:36.223 26994-27033 BleGatt                 com.qtcoding.workouttracker          D  characteristic changed: android.bluetooth.BluetoothGattCharacteristic@aee9130
2025-03-26 10:51:36.225 26994-27033 BleGatt                 com.qtcoding.workouttracker          D  Exercise state change expected: 3
2025-03-26 10:51:36.232 26994-26994 ViewModel               com.qtcoding.workouttracker          D  Get state from BLE: 3k
2025-03-26 10:51:36.233 26994-26994 ViewModel               com.qtcoding.workouttracker          D  Count crunch
2025-03-26 10:51:36.233 26994-26994 ViewModel               com.qtcoding.workouttracker          D  Current crunch: 1
2025-03-26 10:51:36.233 26994-26994 ViewModel               com.qtcoding.workouttracker          D  Current state: 1
2025-03-26 10:51:38.355 26994-27033 BleGatt                 com.qtcoding.workouttracker          D  characteristic changed: android.bluetooth.BluetoothGattCharacteristic@aee9130
2025-03-26 10:51:38.356 26994-27033 BleGatt                 com.qtcoding.workouttracker          D  Exercise state change expected: 2
2025-03-26 10:51:38.361 26994-26994 ViewModel               com.qtcoding.workouttracker          D  Get state from BLE: 2k
2025-03-26 10:51:38.362 26994-26994 ViewModel               com.qtcoding.workouttracker          D  Count squat
2025-03-26 10:51:38.362 26994-26994 ViewModel               com.qtcoding.workouttracker          D  Current squat: 3
2025-03-26 10:51:38.362 26994-26994 ViewModel               com.qtcoding.workouttracker          D  Current state: 3

Based on the log, i think the state and exerciseState is changing but i don't know why the UI not recompose

I want the screen will update UI based on the data from ble device