簡體   English   中英

如何使用作為字符串存儲在 Room 中的 URI 加載圖像

[英]How to load an image using a URI stored in Room as a String

我正在制作一個練習應用程序來加載商店的庫存,在屏幕內我按下一個浮動按鈕,該按鈕生成一個對話框,要求用戶從他們的圖庫中選擇多個數據中的圖像,稍后在按下保存按鈕時對話框、圖像和數據的 rest 保存在 ViewModel 和 ROOM 中,然后在主屏幕上生成一個項目,在使用 Log.d 打印的同時顯示這些數據

保存后生成項目時,它會正確顯示,但是,如果我重新啟動應用程序,圖像就會消失。 在生成圖像和重新啟動應用程序時,Log.d 打印在這兩種情況下都顯示相同的 URI。

我的主要目標是在 ROOM 中保存圖像、它的地址或 URI,然后用圖像加載項目。 我的研究使我相信將 URI 保存為字符串是正確的,但我不知道保存圖像的正確做法,並且我願意在必要時使用其他方法來找到解決方案。

首先,在創建項目的對話框中,我 select 像這樣從畫廊中獲取圖像並將其保存在 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 KK(謝謝你們)的兩個答案並嘗試實現它們之后,我無法自己編寫代碼,所以我將帖子的內容(問題和兩個答案)輸入到 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()
            )
        }
    )

這是因為當應用程序進程被終止時,URI 將被撤銷。

對於存儲訪問框架 URI,您可以使用takePersistableUriPermission獲得長期許可。

但據我所知,它可能不適用於ActivityResultContracts.PickVisualMedia()

在您的情況下,您可以在第一次獲取圖像后制作自己的圖像副本,並將其保存在應用程序特定的存儲中,並將該 URI 保存在您的數據庫中。 這樣會更靈活。 即使原始文件被刪除/您仍然可以訪問您復制的圖像。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM