我有一个来电应用程序,允许用户从手机中提取联系人照片和铃声音频文件。 当我拿起照片时,它可以使用界面上的 URI 正确显示。在主页和联系页面上。 我将其保存在房间数据库中...
如果我关闭应用程序并重新打开它,它会从数据库获取相同的 URI。但没有显示图像。不在主页或联系页面上。 我尝试手动插入 URI 代码,但它也没有显示任何内容...还将图像加载器从
GlideImage
(另一个实现)更改为 rememberImagePainter
(另一个实现),但同样的问题...
我从数据库和图像选择器获得的 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()
,我还在学习。但我创建了一个转换器类(最长的解决方案)来使用 Uri 将其转换为位图...但我必须首先使其可绘制。我不知道如何直接从 Uri 中获取位图。
我首先更新了数据类
@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 包中创建一个转换器类,将 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,但无论如何这是一个测试。
我一直在使用 Compose,并且对此有一个解决方案,所以让我为您提供一些背景信息。
首先,我有一个带有 CRUD 事务的笔记应用程序,我使用了 room 和匕首柄。 因此,在我的可组合 AddNoteScreeen.kt 中,我添加或更新注释,但这是重要的部分
val mediaPickerLauncher = rememberLauncherForActivityResult(
contract = ActivityResultContracts.PickVisualMedia(),
onResult = { uri ->
if (uri != null) {
val flag = Intent.FLAG_GRANT_READ_URI_PERMISSION
context.contentResolver.takePersistableUriPermission(uri, flag)
noteViewModel.onImageChanged(uri)
}
}
)
我在上面声明了这个可组合组件,这是第一个可组合组件。这段代码对 Android 说你要创建一个启动器并等待结果,合同部分说你要使用一个标准活动,即 PickVisualMedia(),并且在该活动上,你只能选择一个元素。我鼓励您查看此处的文档:照片选择器
然后,我检查我的结果,如果它不为空,我将其分配给我的 ViewModel 中的状态。但在我声明一个标志之前,该标志允许您在后台上传大文件,您可能需要此访问权限持续较长时间,并且它必须与您选择的 URI 相关联。
最后,您可以使用下一个代码启动它
Button(onClick = {
mediaPickerLauncher.launch(
PickVisualMediaRequest(ActivityResultContracts.PickVisualMedia.ImageOnly)
)
}) {
Text(text = "Select Image")
}
PickVisualMediaRequest 创建启动该 Activity 的请求,在此部分中,您可以声明需要显示哪种资源,例如视频、图像或 GIF。
在这个过程中,我使用 Room 保存图像,显然,这个响应集中在 UI 以及如何保存元素上。
这里是 GitHub 存储库