使用 Uri 显示图像 -> 从图像选择器工作但从数据库房间不...(Jetpack Compose)

displaying image using Uri -> from image picker works but from db room don't... (Jetpack Compose)

我有一个来电应用程序,允许用户从他们的手机上为联系人选择照片,为铃声选择音频文件。 当我拿起照片时,可以使用界面上的 URI 正确显示它。在主页和联系页面上。 我将其保存在房间数据库中...

如果我关闭应用程序并重新打开它,它会从数据库获取相同的 URI。但没有显示图像。既不在主页上也不在联系页面上。 我尝试手动插入 URI 代码,但它也没有显示任何内容……还将图像加载器从 rememberImagePainter(另一个实现)更改为 GlideImage,但同样的问题…… 我从数据库和图像选择器中得到的 URI 看起来像这样 val uri2:Uri = "content://com.android.providers.media.documents/document/image%3A34".toUri()

提取图片Uri的代码是这样的

class GetContentActivityResult(
 private val launcher: ManagedActivityResultLauncher<String, Uri>,
       val uri: Uri?
          ) {
          fun launch(mimeType: String) {
           launcher.launch(mimeType)
        }
      }

@Composable
fun rememberGetContentActivityResult(): GetContentActivityResult {

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

 val launcher = rememberLauncherForActivityResult(ActivityResultContracts.GetContent(), onResult = {

      uri = it
     })

 return remember(launcher, uri) { GetContentActivityResult(launcher, uri) }
}

我在联系页面中显示图像是这样的

val getContent = rememberGetContentActivityResult() <-- to access the class of pickup files

if (roomViewModel.photoUri.value.isBlank()){ <-- if no image from db display the picked image using image picker 
    getContent.uri?.let {
              Image(
                modifier = Modifier
                             .align(Alignment.TopCenter)
                             .fillMaxSize(1f),
                         contentDescription = "UserImage",
                         contentScale = ContentScale.Crop,
                painter = rememberImagePainter(data = it))
                      }
         }else{

             Image(
               modifier = Modifier
                            .align(Alignment.TopCenter)
                            .fillMaxSize(1f),
                         contentDescription = "UserImage",
                         contentScale = ContentScale.Crop,
                         painter = rememberImagePainter(data = roomViewModel.photoUri.value))
            }
    }

           TextButton(
                      onClick = { getContent.launch("image/*") }, <-- launching the class to get the image URI by defining the Mime as image/*
                      modifier = Modifier.layoutId("changePhoto")
            ) {
     Text(
         text = "Change Photo",
        color = Color.Black)}

在主页里面。没有图像选择器,我只是显示我在数据库中的数据,我以这种方式显示图像

@OptIn(ExperimentalCoilApi::class)
@Composable
fun ProfilePicture(uri : Uri, imageSize: Dp) {
 Card(
     shape = CircleShape,
     border = BorderStroke(
     width = 2.dp,
     color = Color.Red ),
     modifier = Modifier.padding(16.dp),
     elevation = 4.dp) {

 val uri2:Uri = "content://com.android.providers.media.documents/document/image%3A34".toUri() //<-- i tried to load the image this way also it didn't work.

 val painter = rememberImagePainter(
                data = uri,
                builder = {
                placeholder(R.drawable.yara) <-- the placeholder image blinks quickly when app is loaded and then disappear...
     }
  )
    Image(
       painter = painter,
       contentDescription = "User Image",
       modifier = Modifier.size(imageSize) )
 }
}

Uri 选择器或图片显示有问题吗?

房间数据库中的其他内容已正确显示(字符串)

我尝试在模拟器和真实设备上使用代码,这两种情况都是一样的...

我刚刚注意到的一件事...如果我使用图像选择器并选择以前选择的图像(它的 uri 在数据库中),图像会自动显示在应用程序的其他位置,而无需执行任何其他操作。 ..只是选择图像并显示它甚至不保存它...

嗯,我不知道该怎么做 takePersistableUriPermission(),我还在学习中。但是我创建了一个转换器 class(最长的解决方案)来使用 Uri 将其转换为位图...但我必须先使其可绘制。我不知道如何直接从 Uri 做位图。

我第一时间更新了数据class

@Entity
data class Contact(
    @PrimaryKey()
    val id: UUID = UUID.randomUUID(),
    val name: String,
    val land_line : String,
    val mobile: String,
    val contact_photo: Bitmap
)

为数据库中的位图添加了一个TypeConverter

    @TypeConverter
    fun fromBitmap(bitmap: Bitmap): ByteArray {
        val outputStream = ByteArrayOutputStream()
        bitmap.compress(Bitmap.CompressFormat.PNG, 100, outputStream)
        return outputStream.toByteArray()
    }

    @TypeConverter
    fun toBitmap(byteArray: ByteArray): Bitmap {
        return BitmapFactory.decodeByteArray(byteArray, 0, byteArray.size)
    }

将值类型一直更改为 UI,并在 Util 包中创建了一个转换器 class 以将 Uri 转换为可绘制对象然后是位图(我知道它看起来很愚蠢 - 任何更好的解决方案被接受)。

suspend fun convertToBitmap(uri: Uri, context: Context, widthPixels: Int, heightPixels: Int): Bitmap? {
    val mutableBitmap = Bitmap.createBitmap(widthPixels, heightPixels, Bitmap.Config.ARGB_8888)
    val canvas = Canvas(mutableBitmap)
    val drawable = getDrawable(uri, context)
    drawable?.setBounds(0, 0, widthPixels, heightPixels)
    drawable?.draw(canvas)
    return mutableBitmap
}


@OptIn(ExperimentalCoilApi::class)
suspend fun getDrawable(uri: Uri, context: Context): Drawable? {
    val imageLoader = ImageLoader.Builder(context)
        .availableMemoryPercentage(0.25)
        .allowHardware(false)
        .crossfade(true)
        .build()

    val request= ImageRequest.Builder(context)
        .data(uri)
        .build()
    return imageLoader.execute(request).drawable
}

它现在正在运行并且正在完美加载。我知道我的宽度和高度是 50 50 px,但无论如何这是一个测试。