Jetpack Compose – LazyColumn 不重组

如何解决Jetpack Compose – LazyColumn 不重组

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

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

主活动

class MainActivity : 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) }
            }
        }
    }
}

视图模型

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,)

仓库

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","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
    }

}

Flow 幼崽正在生成更新的值,如您在我的 logcat 中所见

Logcat

我已将打印语句放在我的可组合项上,并且在流程发出新值后它们不会被重新组合。

编辑。

Lookslike Compose 比较对象的引用,由于这些没有改变,即使流发出新值也不会发生重组(可能是 Compose 上的错误?)

更改了 toggle 功能以重新创建列表元素的实例,如下所示,现在可以正常工作了。

注意:我已经将 Puppy.adopted 变成了 val 而不是 var


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
}

解决方法

Flow 幼崽正在生成更新的值,如您在我的 logcat 中所见

不完全是。

Flow 发出相同 List 对象的相同 Puppy。我相信 Compose 会发现 List 与之前的 List 对象相同,并假设没有任何变化。

我建议的更改:

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

  • 去掉 changeFlow 并让 getPuppies() 返回一个稳定的 MutableStateFlow<List<Puppy>>(或者让它成为公共财产)

  • toggleAdoption() 中,创建一个新的 Puppy 对象列表并使用它来更新 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
    }
,

这对我有用。

import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.setValue
import androidx.lifecycle.ViewModel

class MyViewModel : ViewModel() {
    var selectables: List<Selectable> by mutableStateOf(List(100) { Selectable(name = "$it") })
        private set

    fun onTapped(tappedItem: Selectable) {
        val index = selectables.indexOf(tappedItem)
        selectables = selectables.toMutableList().also {
            it[index] = tappedItem.copy(selected = !tappedItem.selected)
        }
    }
}

data class Selectable(
    val name: String,var selected: Boolean = false,)

关键部分是:

  1. 重新分配列表而不是就地修改它(例如,将 selectables 设为 MutableList 并执行 selectables[index] = tappedItem.copy(selected = !tappedItem.selected) 不起作用)
  2. 重新分配所选项目而不是就地修改它,例如以下是行不通的
selectables = selectables.toMutableList().also {
    it[index].selected = !tappedItem.selected
}

请注意,您没有必须使您的数据类不可变,但是,使其不可变将强制您必须制作元素的副本才能更新它。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


使用本地python环境可以成功执行 import pandas as pd import matplotlib.pyplot as plt # 设置字体 plt.rcParams[&#39;font.sans-serif&#39;] = [&#39;SimHei&#39;] # 能正确显示负号 p
错误1:Request method ‘DELETE‘ not supported 错误还原:controller层有一个接口,访问该接口时报错:Request method ‘DELETE‘ not supported 错误原因:没有接收到前端传入的参数,修改为如下 参考 错误2:cannot r
错误1:启动docker镜像时报错:Error response from daemon: driver failed programming external connectivity on endpoint quirky_allen 解决方法:重启docker -&gt; systemctl r
错误1:private field ‘xxx‘ is never assigned 按Altʾnter快捷键,选择第2项 参考:https://blog.csdn.net/shi_hong_fei_hei/article/details/88814070 错误2:启动时报错,不能找到主启动类 #
报错如下,通过源不能下载,最后警告pip需升级版本 Requirement already satisfied: pip in c:\users\ychen\appdata\local\programs\python\python310\lib\site-packages (22.0.4) Coll
错误1:maven打包报错 错误还原:使用maven打包项目时报错如下 [ERROR] Failed to execute goal org.apache.maven.plugins:maven-resources-plugin:3.2.0:resources (default-resources)
错误1:服务调用时报错 服务消费者模块assess通过openFeign调用服务提供者模块hires 如下为服务提供者模块hires的控制层接口 @RestController @RequestMapping(&quot;/hires&quot;) public class FeignControl
错误1:运行项目后报如下错误 解决方案 报错2:Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.8.1:compile (default-compile) on project sb 解决方案:在pom.
参考 错误原因 过滤器或拦截器在生效时,redisTemplate还没有注入 解决方案:在注入容器时就生效 @Component //项目运行时就注入Spring容器 public class RedisBean { @Resource private RedisTemplate&lt;String
使用vite构建项目报错 C:\Users\ychen\work&gt;npm init @vitejs/app @vitejs/create-app is deprecated, use npm init vite instead C:\Users\ychen\AppData\Local\npm-
参考1 参考2 解决方案 # 点击安装源 协议选择 http:// 路径填写 mirrors.aliyun.com/centos/8.3.2011/BaseOS/x86_64/os URL类型 软件库URL 其他路径 # 版本 7 mirrors.aliyun.com/centos/7/os/x86
报错1 [root@slave1 data_mocker]# kafka-console-consumer.sh --bootstrap-server slave1:9092 --topic topic_db [2023-12-19 18:31:12,770] WARN [Consumer clie
错误1 # 重写数据 hive (edu)&gt; insert overwrite table dwd_trade_cart_add_inc &gt; select data.id, &gt; data.user_id, &gt; data.course_id, &gt; date_format(
错误1 hive (edu)&gt; insert into huanhuan values(1,&#39;haoge&#39;); Query ID = root_20240110071417_fe1517ad-3607-41f4-bdcf-d00b98ac443e Total jobs = 1
报错1:执行到如下就不执行了,没有显示Successfully registered new MBean. [root@slave1 bin]# /usr/local/software/flume-1.9.0/bin/flume-ng agent -n a1 -c /usr/local/softwa
虚拟及没有启动任何服务器查看jps会显示jps,如果没有显示任何东西 [root@slave2 ~]# jps 9647 Jps 解决方案 # 进入/tmp查看 [root@slave1 dfs]# cd /tmp [root@slave1 tmp]# ll 总用量 48 drwxr-xr-x. 2
报错1 hive&gt; show databases; OK Failed with exception java.io.IOException:java.lang.RuntimeException: Error in configuring object Time taken: 0.474 se
报错1 [root@localhost ~]# vim -bash: vim: 未找到命令 安装vim yum -y install vim* # 查看是否安装成功 [root@hadoop01 hadoop]# rpm -qa |grep vim vim-X11-7.4.629-8.el7_9.x
修改hadoop配置 vi /usr/local/software/hadoop-2.9.2/etc/hadoop/yarn-site.xml # 添加如下 &lt;configuration&gt; &lt;property&gt; &lt;name&gt;yarn.nodemanager.res