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参数:
这样既省去手动管理Uri的代码,又能利用Coil的本地缓存机制,彻底解决重复加载问题。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)) )
3. 提升Uri缓存层级
如果坚持手动获取Uri,可将缓存逻辑移到ViewModel中,用Map<Project, Uri>存储已获取的Uri,避免LazyColumn回收组件时丢失缓存;也可以用rememberSaveable替代remember,让状态在组件重建时保留:
var uriOfProjectIconFromFirebase by rememberSaveable { mutableStateOf<Uri?>(null) }
内容的提问来源于stack exchange,提问作者Sujal Kumar
相关产品推荐
相关产品推荐

