我正在制作一个加载商店库存的练习应用程序,在屏幕内按下一个浮动按钮,生成一个对话框,要求用户从其图库中选择几个数据中的一个图像,稍后按下对话框中的保存按钮时,图像和其余数据将保存在ViewModel和ROOM中,然后在主屏幕上生成一个项目,在使用Log.d打印这些数据的同时显示这些数据
当保存后生成项目时,它会正确显示,但是如果我重新启动应用程序,图像会消失。当生成图像和重新启动应用程序时,Log.d打印在两种情况下都显示相同的URI。
我的主要目标是在ROOM中保存一个图像、它的地址或URI,然后加载带有图像的项。我的研究使我相信将URI保存为字符串是正确的,但我不知道保存图像的正确实践,如果需要,我愿意采用其他方法来实现解决方案。
首先,在创建一个项目的对话框中,我从图库中选择一个图像,如下所示,并将其保存在ViewModel中,然后保存在ROOM中:
val singlePhotoPickerLauncher = rememberLauncherForActivityResult(
contract = ActivityResultContracts.PickVisualMedia(),
onResult = { uri ->
selectedImageUri = uri
Log.d("URI RESULT", "$uri")
viewModel.onDialogChanged(
uri.toString()
)
}
)
当我按下“保存”按钮时,我将其保存在ROOM中:
DialogButton(
ButtonDefaults.buttonColors(
backgroundColor = verdeBillete,
contentColor = Color.White
), "Guardar", modifier = Modifier, onClick = {
viewModel.viewModelScope.launch {
viewModel.onAddSelected(
inventoryItem(
0,
uri,
)
)
}
onDismiss()
})
//add to ViewModel
fun onAddSelected(addItem: inventoryItem) {
viewModelScope.launch {
addItem(addItem)
getInventory()
}
}
//ROOM Table
@Entity(tableName = "inventory")
data class inventoryItem(
@PrimaryKey(autoGenerate = true)
@ColumnInfo(name = "r_id")
var id: Int = 0,
@ColumnInfo(name = "r_uri")
val uri: String,
)
然后,我现在尝试像这样加载图像:
Log.d("Loading items", item.uri)
AsyncImage(
model = Uri.parse(item.uri),
contentDescription = null,
modifier = Modifier.fillMaxWidth(),
contentScale = ContentScale.Crop
)
从图库中选择图像后,图像是可见的,但重新启动应用程序后,图像消失。在这两种情况下,Log.d中打印的URI是相同的。
此外,我还有权:
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.READ_MEDIA_IMAGES" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"
tools:ignore="ScopedStorage" />
更新:在阅读了CommonsWare和Gowtham K K的答案(谢谢你们!)并尝试实现它们之后,我无法自己编写代码,所以我将帖子的内容(问题和两个答案)输入到chatgpt中并要求解决方案,它为我提供了以下解决方案。
若要使用takePersistableUriPermission,必须执行以下操作:
首先,您需要拥有读取或写入要永久保存的URI的权限。您可以在AndroidManifest.xml文件中添加以下代码行:
或
然后,您需要获取要永久保存的URI。例如,如果要保存从库中选择的图像的URI,可以使用ActivityResultContracts.PickVisualMedia方法,如下所示:
val singlePhotoPickerLauncher =
rememberLauncherForActivityResult( contract =
ActivityResultContracts.PickVisualMedia(), onResult = { uri ->
selectedImageUri = uri } )
获得URI后,可以使用takePersistableUriPermission将其永久保存。takePersistableUriPermission方法应在ContentResolver上使用,并带有两个参数:URI和访问模式(读或写)。例如:
contentResolver.takePersistableUriPermission(uri,
Intent.FLAG_GRANT_READ_URI_PERMISSION) or
contentResolver.takePersistableUriPermission(uri,
Intent.FLAG_GRANT_WRITE_URI_PERMISSION)
最后,您可以将URI作为文本字符串保存在ROOM数据库中,并在必要时将其加载到应用程序中。例如:
val inventoryItem = inventoryItem(0, uri.toString())
viewModel.onAddSelected(inventoryItem)
把所有东西放在一起:
var selectedImageUri by remember {
mutableStateOf<Uri?>(null)
}
val singlePhotoPickerLauncher = rememberLauncherForActivityResult(
contract = ActivityResultContracts.PickVisualMedia(),
onResult = { uri ->
selectedImageUri = uri
Log.d("URI RESULT", "$uri")
val flags = Intent.FLAG_GRANT_READ_URI_PERMISSION//or Intent.FLAG_GRANT_WRITE_URI_PERMISSION
val resolver = mContext.contentResolver
resolver.takePersistableUriPermission(uri!!, flags)
viewModel.onDialogChanged( //**save to database function**
uri.toString()
)
}
)
1条答案
按热度按时间r7xajy2e1#
这是因为当应用程序进程被终止时,URI将被撤销。
对于存储访问框架URI,您可以使用
takePersistableUriPermission
获得长期权限。但据我所知,它可能不适用于
ActivityResultContracts.PickVisualMedia()
。在您的情况下,您可以在第一次获得图像后制作自己的副本,并将其保存在应用程序特定的存储中,并将该URI保存在您的数据库中。这将更加灵活。即使原始文件被删除/您仍然可以访问复制的图像。