我正在制作一个练习应用程序来加载商店的库存,在屏幕内我按下一个浮动按钮,该按钮会生成一个对话框,询问用户从库中选择的几个数据中的图像,稍后当按下对话框中的保存按钮时,图像和其余数据将保存在ViewModel和ROOM中,然后在主屏幕上生成一个项目,在用Log.d 打印这些数据的同时显示这些数据
保存后生成项目时,它会正确显示,但是,如果我重新启动应用程序,图像就会消失。在生成图像和重新启动应用程序时,Log.d打印在这两种情况下都显示相同的URI。
我的主要目标是将图像、其地址或URI保存在ROOM中,然后用该图像加载项目。我的研究使我相信将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的两个答案并尝试实现它们之后,我无法自己编写代码,所以我将帖子的内容(问题和两个答案)输入到chatgpt中,并要求提供解决方案,这为我提供了以下对我有效的解决方案。
要使用takePersistableUriPermission,您必须执行以下操作:
首先,您需要具有读取或写入您想要持久保存。您可以添加以下内容AndroidManifest.xml文件中的代码行:
或
然后,您需要获得要持久保存的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)
最后,您可以将ROOM数据库中的URI保存为文本字符串并在必要时将其加载到应用程序中。例如:
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()
)
}
)
这是因为当应用程序进程被终止时,URI会被吊销。
对于存储访问框架URI,您可以使用takePersistableUriPermission
获得长期权限。
但据我所知,它可能不适用于ActivityResultContracts.PickVisualMedia()
。
在您的情况下,您可以在第一次获得图像后制作自己的图像副本,并将其保存在应用程序特定的存储中,然后将该URI保存在数据库中。这将更加灵活。即使原始文件被删除,您仍然可以访问复制的图像。