使用 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,但无论如何这是一个测试。
我有一个来电应用程序,允许用户从他们的手机上为联系人选择照片,为铃声选择音频文件。 当我拿起照片时,可以使用界面上的 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,但无论如何这是一个测试。