我的LazyColumn没有重新组合,但值正在更新.

如果我向下滚动列表并向上滚动,我会看到UI的正确值

主要活动

class 主要活动 : AppCompatActivity() {


    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            MyTheme {
                MyApp()
            }
        }
    }
}

// Start building your app here!
@Composable
fun MyApp(vm: PuppyListViewModel =  viewModel()) {
    val puppers by vm.pups.collectAsState(emptyList())
    Surface(color = MaterialTheme.colors.background) {
        Column {
            Toolbar()
            LazyColumn {
                items(puppers) { pup ->  PuppyUI(pup, vm::seeDetails, vm::togglePuppyAdoption) }
            }
        }
    }
}

The ViewModel

class PuppyListViewModel : ViewModel() {

    val pups = PuppyRepo.getPuppies().onEach {
        println("FlowEmitted: $it")
    }

    fun togglePuppyAdoption(puppy: Puppy) = viewModelScope.launch {
        PuppyRepo.toggleAdoption(puppy.id)
    }

    fun seeDetails(puppy: Puppy) {
        println("seeDetails $puppy")
    }
}

该模型


internal var IDS = 0L

data class Puppy (
    val name: String,
    val tagline: String = "",
    val race: String,
    @DrawableRes val image: Int,
    var adopted: Boolean = false,
    val id: Long = ++IDS,
)

The repository

object PuppyRepo {
    private val changeFlow = MutableStateFlow(0)
    private val pups: List<Puppy>

    private val puppyImages = listOf(
        R.drawable._1,
        R.drawable._2,
        R.drawable._3,
        R.drawable._4,
        R.drawable._5,
        R.drawable._6,
        R.drawable._7,
        R.drawable._8,
        R.drawable._9,
        R.drawable._10,
        R.drawable._11,
        R.drawable._12,
        R.drawable._13,
        R.drawable._14,
        R.drawable._15,
        R.drawable._16,
        R.drawable._17,
        R.drawable._18,
        R.drawable._19,
    )


    private val puppyNames = listOf(
        "Gordie",
        "Alice",
        "Belle",
        "Olivia",
        "Bubba",
        "Pandora",
        "Bailey",
        "Nala",
        "Rosco",
        "Butch",
        "Matilda",
        "Molly",
        "Piper",
        "Kelsey",
        "Rufus",
        "Duke",
        "Ozzy"
    )

    private val puppyTags = listOf(
        "doggo",
        "doge",
        "special dogo",
        "wrinkler",
        "corgo",
        "shoob",
        "puggo",
        "pupper",
        "small dogo",
        "big ol dogo",
        "woofer",
        "floofer",
        "yapper",
        "pupper",
        "good-boye",
        "grizlord",
        "snip-snap dogo"
    )

    private val puppyBreeds = listOf(
        "Labrador Retriever",
        "German Shepard",
        "Golden Retriever",
        "French Bulldog",
        "Bulldog",
        "Beagle",
        "Poodle",
        "Rottweiler",
        "German Shorthaired Pointer",
        "Yorkshire Terrier",
        "Boxer"
    )

    init {
        pups = puppyImages.map { image ->
            val name = puppyNames.random()
            val tagline = puppyTags.random()
            val breed = puppyBreeds.random()
            Puppy(name, tagline, breed, image)
        }
    }

    @OptIn(ExperimentalCoroutinesApi::class)
    fun getPuppies() = changeFlow.flatMapLatest { flowOf(pups) }

    fun getPuppy(puppyId: Long) = flow {
        emit(pups.find { it.id == puppyId })
    }


    suspend fun toggleAdoption(puppyId: Long): Boolean {
        val found = getPuppy(puppyId).first()?.toggleAdoption()?.let { true } ?: false
        if (found) {
            // Trigger a new emission for those that are consuming a Flow from getPuppies
            changeFlow.value = changeFlow.value + 1
        }
        return found
    }


    private fun Puppy.toggleAdoption() {
        adopted = !adopted
    }

}

正如你在我的日志(log)中看到的,Flow只幼崽正在产生更新的值

Logcat

I've put print statements on my composables and they are not getting re-composed after the flow emits a new value.

Edit.

Lookslike Compose compares the references of the objects and since those didn't change, recomposition didn't happen even if flows were emitting new values (a bug on Compose perhaps?)

更改了toggle功能以重新创建列表元素的实例,如下所示,现在正在运行.

Note:我把Puppy.adopted改成了val


suspend fun toggleAdoption(puppyId: Long): Boolean {
    var found = false
    pups = pups.map {
        val isThePuppy = it.id == puppyId
        found = found || isThePuppy
        if(isThePuppy) it.copy(adopted = !it.adopted) else it.copy()
    }
    if (found) {
        // Trigger a new emission for those that are consuming a Flow from getPuppies
        changeFlow.value = changeFlow.value + 1
    }
    return found
}

推荐答案

正如你在我的日志(log)中看到的,Flow只幼崽正在产生更新的值

Not exactly.

Flowemits 的是Puppy个相同物体中的List个.我相信Compose会看到List和以前是同一个List对象,并假设没有变化.

我建议的改变:

  • 使Puppy成为不变的data类(即var个属性)

  • Get rid of changeFlow and have getPuppies() return a stable MutableStateFlow<List<Puppy>> (or make that just be a public property)

  • In toggleAdoption(), create a fresh list of Puppy objects and use that to update the MutableStateFlow<List<Puppy>>:

    suspend fun toggleAdoption(puppyId: Long) {
        val current = puppies.value // assumes that puppies is a MutableSharedFlow<List<Puppy>>

        val replacement = current.map { if (it.id == puppyId) it.copy(adopted = !it.adopted) else it }

        puppies.value = replacement
    }

Kotlin相关问答推荐

升级使用jOOQ Gradle插件生成代码失败

在Kotlin项目中使用Free Fair AspectJ插件(使用Gradle)

MyType.()在 Kotlin 中是什么意思?

有什么方法可以要求在 kotlin 中的类型参数上进行注释?

kotlin 父类具有依赖于抽象变量的变量

Kotlin:我可以将函数分配给 main 的伴随对象中的变量吗?

如何在 jOOQ 中两次加入同一张表?

Kotlin 使用委托进行隐式覆盖

关于 Kotlin 函数类型转换的问题

compareBy 如何使用布尔表达式在 kotlin 中工作

Saripaar formvalidation 在 kotlin 中第二次不起作用

Kotlin 枚举中的循环引用

如何将 Kotlin 日期中的字符串或时间戳格式化为指定的首选格式?

在 Kotlin 函数上使用 Mokito anyObject() 时,指定为非 null 的参数为 null

kotlin 委托有什么用?

如何在Kotlin中使方法param可变?

不推荐使用仅限生命周期的LifecycleEvent

Kotlin替换字符串中的多个单词

@StringRes、@DrawableRes、@LayoutRes等android注释使用kotlin参数进行判断

内联 Kotlin 方法没有覆盖报告