升级依赖后ViewModel存储拍照Uri无法在Composable中展示图片问题
故障根因与修复方案
核心问题:ViewModel实例化逻辑错误
在SamplePage中直接通过构造函数创建InputViewModel实例,Composable每次重组都会生成全新的ViewModel对象,拍照动作触发界面重组后,原有存储了图片URI的ViewModel实例会被销毁,新实例的image字段自然为空值。
修复方式:改用Jetpack Compose提供的viewModel()扩展函数获取ViewModel实例,保证实例与宿主Activity/Fragment生命周期绑定,不会随界面重建销毁。
修改SamplePage中的ViewModel声明代码:
// 需提前导入依赖:import androidx.lifecycle.viewmodel.compose.viewModel val inputViewModel: InputViewModel = viewModel()
次要问题:PhotoButton逻辑缺陷
未校验拍照结果
ActivityResultContracts.TakePicture()返回值为Boolean类型,代表拍照是否成功,原有代码无论用户拍照成功还是取消,都会返回URI,会导致无效URI被存入ViewModel。
未持久化文件与URI实例
原有代码中File和URI没有用remember修饰,每次Composable重组都会重新生成实例,可能导致拍照时使用的URI和回调返回的URI不一致。
未授予相机URI写入权限
系统相机默认没有权限写入当前App的FileProvider路径,会导致拍照实际失败,生成空文件。
修复后的PhotoButton完整代码:
@Composable fun PhotoButton(onValChange: ((String) -> Unit)?){ val context = LocalContext.current // 用remember持久化文件和URI,避免重组时重新生成 val uri by remember { val storageDir: File? = context.getExternalFilesDir(Environment.DIRECTORY_PICTURES) val file = File(storageDir, "picFromCamera") mutableStateOf( FileProvider.getUriForFile( context, "${context.packageName}.provider", file ) ) } val launcher = rememberLauncherForActivityResult(ActivityResultContracts.TakePicture()) { isSuccess -> // 仅拍照成功时才返回URI if (isSuccess && onValChange != null) { onValChange(uri.toString()) } } FAB() { // 给相机授予URI写入权限 launcher.launch(uri, ActivityOptions.makeBasic().apply { Intent.FLAG_GRANT_WRITE_URI_PERMISSION }.toBundle()) } }
版本适配:Coil加载组件兼容
如果升级了Coil到2.x版本,原有rememberImagePainter已被废弃,建议替换为新的API避免加载异常:
val painter = rememberAsyncImagePainter(model = image)
内容的提问来源于stack exchange,提问作者Stefano Sansone
相关产品推荐
相关产品推荐

