android 如何使用以字符串形式存储在Room中的URI加载图像

cclgggtu  于 2023-01-07  发布在  Android
关注(0)|答案(1)|浏览(279)

我正在制作一个加载商店库存的练习应用程序,在屏幕内按下一个浮动按钮,生成一个对话框,要求用户从其图库中选择几个数据中的一个图像,稍后按下对话框中的保存按钮时,图像和其余数据将保存在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()
            )
        }
    )
r7xajy2e

r7xajy2e1#

这是因为当应用程序进程被终止时,URI将被撤销。
对于存储访问框架URI,您可以使用takePersistableUriPermission获得长期权限。
但据我所知,它可能不适用于ActivityResultContracts.PickVisualMedia()
在您的情况下,您可以在第一次获得图像后制作自己的副本,并将其保存在应用程序特定的存储中,并将该URI保存在您的数据库中。这将更加灵活。即使原始文件被删除/您仍然可以访问复制的图像。

相关问题