You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

LazyColumn中AsyncImage(Coil)缓存失效问题求助

问题:LazyColumn中ProjectCard滚动后重复加载Firebase图片,无缓存

我开发了ProjectCard这个Composable组件,通过AsyncImage从Firebase Storage获取项目图标。在搜索页面的LazyColumn展示项目时,滚动后移出屏幕的ProjectCard重新显示时会重复加载图片,且加载速度很慢,明显没用到缓存。我试过用LaunchedEffect,但问题仍未解决。


相关代码

ProjectCard.kt

@Composable
fun ProjectCard(
    project: Project
) {
    val context = LocalContext.current
    var uriOfProjectIconFromFirebase by remember {
        mutableStateOf<Uri?>(null)
    }

    LaunchedEffect(Unit) {
        if (project.storedInFirebase) {
            Log.i(TAG, "Trying to get uri of Project Icon...")
            Firebase.storage.reference.child(
                "projectIcons/${project.belongsTo}/${project.name}.jpg"
            ).downloadUrl.addOnSuccessListener { uri ->
                uriOfProjectIconFromFirebase = uri
            }
        }
    }

    Card(
        modifier = Modifier
            .fillMaxWidth()
    ) {
        Box(
            modifier = Modifier.background(
                Brush.verticalGradient(
                    listOf(
                        project.tintColor,
                        Color.White
                    )
                )
            )
        )
        {
            Column(
                modifier = Modifier.padding(15.dp)
            ) {
                Row(verticalAlignment = Alignment.CenterVertically) {
                    AsyncImage(
                        model =
                        if (project.storedInFirebase) {
                            uriOfProjectIconFromFirebase
                        } else if (project.iconPath != null) {
                            BitmapFactory.decodeFile(project.iconPath)
                        } else {
                            project.iconId
                        },
                        contentDescription = "Project Icon",
                        contentScale = ContentScale.Crop,
                        modifier = Modifier
                            .height(50.dp)
                            .width(50.dp)
                            .clip(RoundedCornerShape(12.dp))
                    )

                    Spacer(modifier = Modifier.width(15.dp))

                    Text(
                        text = project.name,
                        fontSize = 18.sp,
                        fontFamily = FontFamily.SansSerif,
                        fontWeight = FontWeight.SemiBold,
                        color = Color.Black
                    )
                    Spacer(modifier = Modifier.width(10.dp))

                    Image(
                        painter = painterResource(id = R.drawable.link_icon),
                        contentDescription = "",
                        modifier = Modifier.clickable {
                            val browserIntent = Intent(Intent.ACTION_VIEW, Uri.parse(project.link))
                            context.startActivity(browserIntent)
                        }
                    )
                }

                HorizontalDivider(
                    Modifier.padding(vertical = 5.dp),
                    color = Color.DarkGray
                )

                Text(
                    text = project.description,
                    color = Color.DarkGray
                )
            }
        }

    }
}

LazyColumn代码

LazyColumn(verticalArrangement = Arrangement.spacedBy(5.dp)) {
    items(projectWrapperOfPersonSearched.projectsList.size)
    {
        ProjectCard(project = projectWrapperOfPersonSearched.projectsList[it])
    }
}

解决方案

1. 修正LaunchedEffect的依赖键

当前LaunchedEffect(Unit)会在组件每次进入组合时执行(包括LazyColumn回收复用组件时),导致同一项目重复请求downloadUrl。把依赖键改为project,同一个项目只会请求一次:

LaunchedEffect(project) { // 绑定project,同一项目仅执行一次
    if (project.storedInFirebase) {
        Log.i(TAG, "Trying to get uri of Project Icon...")
        Firebase.storage.reference.child(
            "projectIcons/${project.belongsTo}/${project.name}.jpg"
        ).downloadUrl.addOnSuccessListener { uri ->
            uriOfProjectIconFromFirebase = uri
        }
    }
}

2. 让Coil直接加载Firebase Storage引用(推荐)

AsyncImage基于Coil实现,Coil官方支持直接加载Firebase Storage资源,自动处理下载和缓存,无需手动请求downloadUrl:

  • 先添加Coil-Firebase依赖:
    implementation "io.coil-kt:coil-firebase:2.5.0"
    
  • 修改AsyncImage的model参数:
    AsyncImage(
        model =
        if (project.storedInFirebase) {
            // 直接传入Storage引用,Coil自动处理缓存
            Firebase.storage.reference.child(
                "projectIcons/${project.belongsTo}/${project.name}.jpg"
            )
        } else if (project.iconPath != null) {
            BitmapFactory.decodeFile(project.iconPath)
        } else {
            project.iconId
        },
        contentDescription = "Project Icon",
        contentScale = ContentScale.Crop,
        modifier = Modifier
            .height(50.dp)
            .width(50.dp)
            .clip(RoundedCornerShape(12.dp))
    )
    
    这样既省去手动管理Uri的代码,又能利用Coil的本地缓存机制,彻底解决重复加载问题。

3. 提升Uri缓存层级

如果坚持手动获取Uri,可将缓存逻辑移到ViewModel中,用Map<Project, Uri>存储已获取的Uri,避免LazyColumn回收组件时丢失缓存;也可以用rememberSaveable替代remember,让状态在组件重建时保留:

var uriOfProjectIconFromFirebase by rememberSaveable {
    mutableStateOf<Uri?>(null)
}

内容的提问来源于stack exchange,提问作者Sujal Kumar

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.19 09:02:34