Jetpack Compose – 有重新组合的问题

huangapple go评论62阅读模式
英文:

Jetpack Compose - have a problem with recomposition

问题

在Compose中,当我点击Donut按钮时,变量"donut"会递增,并且重新组合成功 - 按钮"Donut"上的数据立即更改。
但是在用户按钮上,当我点击时,用户列表中的数据会更改(通过logcat查看),但不会发生重新组合。但是如果在此之后我按下Donut按钮,那么用户数据会立即在屏幕上更改为更改后的数据。

主要问题可能出在以下地方:

  1. StateFlow的使用: 您在ViewModel中使用了StateFlow来管理数据状态。当用户按钮点击时,您在addAgeForAll函数中更新了userList的内容,但是这个更新可能没有被Compose框架检测到,因此没有触发重新组合。您可以尝试将userList的MutableStateFlow更新与StateFlow更新分开,以确保Compose能够正确检测到状态的更改。

  2. collectAsState()的使用: 在MainScreen中,您使用collectAsState()来获取usersClass的值。这意味着MainScreen将只在usersClass的值发生实际更改时进行重新组合。如果userList的内容更改,但userList本身的引用未更改,那么Compose可能不会触发重新组合。确保在userList更新时,usersClass的值也发生更改。

  3. 按钮点击时的状态更新: 在用户按钮的onClick处理程序中,您调用了mainViewModel.addAgeForAll(),该函数在内部更新了userList。但是,按钮点击后,class1的值可能没有直接更改,因此Compose可能不会触发重新组合。您可以尝试在按钮点击处理程序中手动更新class1的值,以确保重新组合发生。

这些是可能导致重新组合不起作用的一些常见问题。请尝试按照上述建议进行调整,以查看是否可以解决问题。如果问题仍然存在,请提供更多的代码和上下文,以便更具体地帮助您解决问题。

英文:

I am using a ViewModel to store data. The ViewModel has a StateFlow class that list of Users. There is also a donut:Int field.

In Compose, when I click on the Donut-button, the variable "donut" is incremented and the recomposition is successful - the data on the button "Donut" changes immediately.
On the Users buttons, when I click, the data in the User list changes (looked through logcat), but the recomposition does not occur. But if after that I press the Donut-button, then the user data instantly changes on the screen to the changed ones.Jetpack Compose – 有重新组合的问题

My MainViewModel:

class MainViewModel() : ViewModel() {

    private var _usersClass = MutableStateFlow(UsersClass())
    val usersClass: StateFlow<UsersClass> = _usersClass.asStateFlow()

    fun addDonut(int: Int) {
        _usersClass.update {
            it.copy(
                donuts = int
            )
        }
    }

    fun addAgeForAll(){
        val newList = _usersClass.value.userList
        newList.value.forEach(){a->a.addAge()}
        _usersClass.update{
            it.copy(
                userList = newList
            )
        }
    }
}

My UsersClass:

data class UsersClass(
    var donuts: Int = 0,

    private var _userList: MutableStateFlow<MutableList<User>> = MutableStateFlow(initData.items.toMutableList()),
    var userList: StateFlow<List<User>> = _userList.asStateFlow()
)

data class User(
    var username: String = "John Doe",
    var age: Int = 18
) {
    fun addAge() {
        age++
    }
}

object initData {
    var items = arrayListOf(
        User(username = "Elvis", age = 18),
        User(username = "Sunny", age = 19),
        User(username = "Mary", age = 18)
    )
}

MainActivity:

class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        val mainViewModel = ViewModelProvider(this)[MainViewModel::class.java]

        setContent {
            MainScreen(
                mainViewModel = mainViewModel,
                onClickButtonAddDonut = {
                    mainViewModel.addDonut(mainViewModel.usersClass.value.donuts + 1)
                }
            )
        }
    }
}

@Composable
fun MainScreen(
    mainViewModel: MainViewModel,
    onClickButtonAddDonut: () -> Unit,
) {
    val class1 = mainViewModel.usersClass.collectAsState()
    Column {
        LazyColumn {
            itemsIndexed(class1.value.userList.value) { _, item ->
                Button(
                    onClick = { mainViewModel.addAgeForAll() }
                ) {
                    Text(text = item.toString())
                }

            }
        }

        Button(
            modifier = Modifier,
            onClick = { onClickButtonAddDonut() },
            content = {
                Text(text = "donuts= ${class1.value.donuts}")
            })

    }
}

Why is recomposition not happening? What am I doing wrong? I can't figure it out for a week Jetpack Compose – 有重新组合的问题
Thx

答案1

得分: 4

问题出在这里,

fun addAge() {
    age++
}

这不会通知Compose有任何更改,因为它直接修改了age的值。

一般来说,通过状态流传递的数据应该是不可变的。要做到这一点,您可以将User更改为,

data class User(
    val username: String = "John Doe",
    val age: Int = 18
)

以及将UserClass更改为,

data class UsersClass(
    val donuts: Int = 0,
    val userList: List<User> = emptyList()
)

请注意使用val而不是var

在这些更改之后,模型上的方法可以是,

fun addAgeForAll(){
    val newList = _usersClass.value.userList.map {
        it.copy(age = it.age + 1)
    }
    _usersClass.update{
        it.copy(
            userList = newList
        )
    }
}

我建议您保持模型简单就像这样直到您知道需要额外的流来防止跳帧

这是翻译好的部分,不包含代码。

英文:

The issue is here,

fun addAge() {
    age++
}

This doesn't notify Compose that anything has changed as it is mutating the value of age directly.

In general, the data sent through a state flow should be immutable. To do this you can change User to be,

data class User(
    val username: String = &quot;John Doe&quot;,
    val age: Int = 18
)

and UserClass to be,

data class UsersClass(
    val donuts: Int = 0,
    val userList: List&lt;User&gt; = emptyList()
)

Note the use of val instead of var.

After these changes, method on the model could be,

fun addAgeForAll(){
    val newList = _usersClass.value.userList.map {
      it.copy(age = it.age + 1)
    }
    _usersClass.update{
        it.copy(
            userList = newList
        )
    }
}

I recommend you keep the model simple, like this, until you know that an additional flow is required to keep from skipping frames.

huangapple
  • 本文由 发表于 2023年6月22日 15:42:16
  • 转载请务必保留本文链接:https://go.coder-hub.com/76529606.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定