Jetpack Compose中用Picasso加载联系人头像遇FileNotFoundException
解决Jetpack Compose中Picasso加载联系人头像URI抛出FileNotFoundException的问题
问题原因
- 权限缺失:读取联系人头像需要
READ_CONTACTS权限,未申请或未授予时会无法访问content URI。 - Target对象被GC回收:匿名内部类实现的
Target仅被Picasso以弱引用持有,Compose重组或GC可能在图片加载完成前回收该对象,触发加载失败。 - 空状态未处理:代码中直接使用
image!!强制非空,加载失败时会引发空指针异常。
解决方案
1. 确认权限配置
在AndroidManifest.xml中添加权限声明:
<uses-permission android:name="android.permission.READ_CONTACTS" />
针对Android 6.0(API 23)及以上版本,需通过ActivityResultContracts.RequestPermission在运行时动态申请权限。
2. 保持Target对象的强引用
用remember存储Target对象,避免被GC回收:
var image by remember { mutableStateOf<ImageBitmap?>(null) } val uri = viewModel.getAvatarUri().get(neme)?.get() var drawable by remember { mutableStateOf<Drawable?>(null) } // 用remember持有Target对象,维持强引用 val target = remember(uri) { object : Target { override fun onPrepareLoad(placeHolderDrawable: Drawable?) { drawable = placeHolderDrawable } override fun onBitmapFailed(e: Exception?, errorDrawable: Drawable?) { e?.printStackTrace() drawable = errorDrawable image = null // 加载失败时清空image,避免空指针 } override fun onBitmapLoaded(bitmap: Bitmap?, from: Picasso.LoadedFrom?) { image = bitmap?.asImageBitmap() } } } DisposableEffect(uri, target) { val picasso = Picasso.get() uri?.let { picasso .load(it) .placeholder(R.drawable.person) .error(R.drawable.person) // 添加错误占位图 .into(target) } onDispose { image = null drawable = null picasso.cancelRequest(target) } } // 处理空状态,避免强制非空 Image( bitmap = image ?: ImageBitmap.imageResource(id = R.drawable.person), contentDescription = "Avatar", modifier = Modifier .size(48.dp) .background(Color.Gray, CircleShape) )
3. 额外注意事项
- 验证
viewModel.getAvatarUri()返回的URI有效性,可通过打印uri值确认是否为正确的联系人头像路径。 - 若问题仍存在,尝试更新Picasso到最新版本,旧版本可能存在Compose兼容性问题。
内容的提问来源于stack exchange,提问作者Slava
相关产品推荐
相关产品推荐

