我正在开发一个应用程序,使用户能够使用手机的内置摄像头拍摄照片,然后使用 Coli 的 AsyncImage 对象在应用程序中显示拍摄的照片。初始捕获按预期工作,但随后尝试捕获其他照片会导致显示的图像与第一张图像保持不变。无法更新新拍摄的图片。
我尝试将 getUriForFile 函数放置在按钮内,以便每次单击按钮时都会刷新 URI。然而,问题升级到第二次捕获后显示的图像变空的地步。我怀疑问题可能源于我分配 URI 值的方式,但尽管花了一整天的时间来解决它,但我一直无法解决它。
这是我正在使用的代码:
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
MyTheme {
// A surface container using the 'background' color from the theme
Surface(
modifier = Modifier.fillMaxSize(),
color = MaterialTheme.colorScheme.background
) {
MyApp()
}
}
}
}
}
@OptIn(ExperimentalMaterial3Api::class)
@Composable
private fun MyApp() {
val context = LocalContext.current
val uri = context.createImageFile()
var imageUri by remember {
mutableStateOf<Uri>(Uri.EMPTY)
}
// Take photo
val cameraLauncher = rememberLauncherForActivityResult(ActivityResultContracts.TakePicture()) {
imageUri = uri
}
// Camera Permission
val cameraPermissionLauncher = rememberLauncherForActivityResult(
ActivityResultContracts.RequestPermission()
) {
if (it) {
Toast.makeText(context, "Permission Granted", Toast.LENGTH_SHORT).show()
cameraLauncher.launch(uri)
} else {
Toast.makeText(context, "Permission Denied", Toast.LENGTH_SHORT).show()
}
}
Scaffold (
topBar = {
CenterAlignedTopAppBar(
title = {
Text(
text = stringResource(R.string.title),
fontWeight = FontWeight.Bold,
fontSize = 30.sp
)
},
colors = TopAppBarDefaults.largeTopAppBarColors(
containerColor = colorResource(R.color.theme)
)
)
}
) {
innerPadding ->
Box(
modifier = Modifier
.fillMaxSize()
.padding(innerPadding)
) {
// Create AsyncImage object if image exists
if (imageUri.path?.isNotEmpty() == true) {
AsyncImage(
model = imageUri,
modifier = Modifier.fillMaxWidth(),
contentDescription = stringResource(R.string.image_content_description)
)
}
Column(
verticalArrangement = Arrangement.Center,
horizontalAlignment = Alignment.CenterHorizontally,
modifier = Modifier
.align(Alignment.BottomCenter)
.padding(bottom = dimensionResource(R.dimen.padding_vertical))
) {
Text(
text = stringResource(R.string.upload),
style = MaterialTheme.typography.titleLarge
)
// Take photo
Button(
onClick = {
val permissionCheckResult =
ContextCompat.checkSelfPermission(context, Manifest.permission.CAMERA)
if (permissionCheckResult == PackageManager.PERMISSION_GRANTED) {
cameraLauncher.launch(uri)
} else {
// Request a permission
cameraPermissionLauncher.launch(Manifest.permission.CAMERA)
}
},
shape = RoundedCornerShape(dimensionResource(R.dimen.button_radius)),
colors = ButtonDefaults.buttonColors(containerColor = colorResource(R.color.theme)),
modifier = Modifier
.width(dimensionResource(R.dimen.button_width))
.height(dimensionResource(R.dimen.button_height))
.padding(top = dimensionResource(R.dimen.button_padding))
) {
Image(
painter = painterResource(R.drawable.photo_camera),
contentDescription = null,
modifier = Modifier.weight(0.5f)
)
Text(
text = stringResource(R.string.take_photo),
style = MaterialTheme.typography.titleLarge,
color = Color.Black,
fontWeight = FontWeight.Bold,
modifier = Modifier.weight(1.5f)
)
}
}
}
}
}
private fun Context.createImageFile(): Uri {
val directory = File(filesDir, "images")
if (!directory.exists()) {
directory.mkdirs()
}
val timeStamp = SimpleDateFormat("yyyyMMdd_HHmmss", Locale.getDefault()).format(Date())
val file = File.createTempFile(
"image_${timeStamp}_",
".png",
directory
)
return FileProvider.getUriForFile(
Objects.requireNonNull(this),
packageName + ".FileProvider",
file
)
}
问题可能与您如何处理可组合函数中的
imageUri
状态有关。当拍摄新照片时,状态没有正确更新,导致图像不刷新。
尝试使用 rememberSaveable
而不是 remember
来在配置更改时保留状态。
用
imageUri
而不是 null
初始化 Uri.EMPTY
也是一个很好的做法,因为最初没有捕获图像。
更换
var imageUri by remember {
mutableStateOf<Uri>(Uri.EMPTY)
}
与
var imageUri by rememberSaveable {
mutableStateOf<Uri?>(null)
}
并确保在使用前对
imageUri
添加 null 检查。
注意:代码未经测试。