0
votes

I'm facing sporadical issues with jetpack compose's mutable states. In a viewModel I'have a variable of type data class.

var headerState by mutableStateOf(ModelTemplateHeaderUiModel())
    private set

When I update the variable in the viewModel with

headerState = headerState.copy(
            client = RepoManager.getClientById(clientID) ?: Client(),
            reportNumber = (RepoManager.getLastReportNumberByClient(clientID))?.plus(1)
                ?.toString()
                ?: ""
        )

the states of client and reportNumber are updated but seem that the UI is not receiving the new state signal to update the Ui and the recomposition do not happens.

The state is used in this section :

 Header(
            viewModel.headerState,
            onContractNumberChange = { viewModel.updateContractNumber(it) },
            onReportNumberChange = { viewModel.updateReportNumber(it) },
            onDateChange = { viewModel.updateDate(it) },
        )

Header is defined as :

@Composable
fun Header(
    headerState: ModelTemplateHeaderUiModel = ModelTemplateHeaderUiModel(),
    onContractNumberChange: (String) -> Unit,
    onReportNumberChange: (String) -> Unit,
    onDateChange: (LocalDate) -> Unit,
)

ModelTemplateHeaderUiModel is defined as :

@Parcelize
data class ModelTemplateHeaderUiModel(
    var descriptionHeader: String = "",
    var client: Client = Client(),
    var contractNumber: String = "",
    var reportNumber: String = "",
    var date: Long = Clock.System.now().epochSeconds
) : Parcelable

the strangest thing is that the variables whose update is not heard are only 3 :

contractNumber

OutlinedTextField(
                    modifier = Modifier.fillMaxWidth(),
                    value = headerState.contractNumber,
                    onValueChange = { onContractNumberChange(it) },
                    singleLine = true,
                    placeholder = { Text(text = "Contratto n°", color = Color.Gray) },
                    keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Number),
                label = { Text(text = "Contratto n°") }
            )

reportNumber

OutlinedTextField(
                    modifier = Modifier.fillMaxWidth(),
                    value = headerState.reportNumber, onValueChange = { onReportNumberChange(it) },
                    singleLine = true,
                    placeholder = { Text(text = "Rapporto di lavoro n°", color = Color.Gray) },
                    keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Number),
                    label = { Text(text = "Rapporto di lavoro n°") }
                )

and client

Column(
                verticalArrangement = Arrangement.spacedBy(10.dp),
                modifier = Modifier.weight(1f)
            ) {
                Text(text = "Cliente", style = MaterialTheme.typography.titleLarge)
                Text(text = headerState.client.name, style = MaterialTheme.typography.titleMedium)
                Text(text = headerState.client.address)
                Row(
                    horizontalArrangement = Arrangement.spacedBy(10.dp),
                ) {
                    Text(text = headerState.client.cap)
                    Text(text = headerState.client.city)
                    Text(text = headerState.client.province)
                }
            }

DescriptionHeader and date are updated correctly in the viewModel by :

fun loadModelById(modelID: String) {
        viewModelScope.launch {
            modelState.value = RepoManager.getCompleteModelById(modelID) ?: Model()
            //update components
            components.clear()
            components.addAll(modelState.value.components)
            //update header state
            headerState = headerState.copy(descriptionHeader = modelState.value.headerDescription)
        }
    }

fun updateDate(value: LocalDate) {
        headerState =
            headerState.copy(date = value.atStartOfDayIn(TimeZone.currentSystemDefault()).epochSeconds)
    }

So there is no difference in the method to update the state of the object.

I did some checks through the debugger and actually the data from firebase arrives, the variable is loaded correctly, the status is updated but the new data is not displayed. I don't understand how the same method of updating data works only for some variables and not for others. I want to clarify that there are no strange logics that manipulate the data that is not displayed. All data comes straight to the UI without manipulation.

I'm using

implementation 'androidx.core:core-ktx:1.8.0'
    implementation "androidx.compose.ui:ui:1.3.0-alpha01"
    implementation 'androidx.compose.compiler:compiler:1.2.0'
    implementation 'androidx.compose.material3:material3:1.0.0-alpha14'
    implementation "androidx.compose.ui:ui-tooling-preview:1.3.0-alpha01"
    implementation 'androidx.lifecycle:lifecycle-runtime-ktx:2.5.0'
    implementation 'androidx.activity:activity-compose:1.5.0'
    implementation 'androidx.navigation:navigation-runtime-ktx:2.5.0'
    testImplementation 'junit:junit:4.13.2'
    androidTestImplementation 'androidx.test.ext:junit:1.1.3'
    androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'
    androidTestImplementation "androidx.compose.ui:ui-test-junit4:1.3.0-alpha01"
    debugImplementation "androidx.compose.ui:ui-tooling:1.3.0-alpha01"
    debugImplementation "androidx.compose.ui:ui-test-manifest:1.3.0-alpha01"

minSdk 26
targetSdk 32

 jvmTarget = '1.8'

compose_version = '1.2.0'

plugins {
    id 'com.android.application' version '7.2.1' apply false
    id 'com.android.library' version '7.2.1' apply false
    id 'org.jetbrains.kotlin.android' version '1.7.0' apply false
}

Anyone have any suggestions? Thank you