Android相机:拍摄初始照片后显示图像无法刷新

问题描述 投票:0回答:1

我正在开发一个应用程序,使用户能够使用手机的内置摄像头拍摄照片,然后使用 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
    )
}
android kotlin camera uri android-fileprovider
1个回答
0
投票

问题可能与您如何处理可组合函数中的

imageUri
状态有关。当拍摄新照片时,状态没有正确更新,导致图像不刷新。 尝试使用
rememberSaveable
而不是
remember
来在配置更改时保留状态。

imageUri
而不是
null
初始化
Uri.EMPTY
也是一个很好的做法,因为最初没有捕获图像。

更换

var imageUri by remember {
    mutableStateOf<Uri>(Uri.EMPTY)
}

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

并确保在使用前对

imageUri
添加 null 检查。

注意:代码未经测试。

© www.soinside.com 2019 - 2024. All rights reserved.