You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Android Jetpack Compose中Picker URI权限异常问题求助

问题:重启应用后调用cleanupCheck触发SecurityException,无法访问相册Picker URI

我用Jetpack Compose开发了一款Android应用,通过Retrofit获取国家信息并存入MongoDB。用户进入国家详情页时可从相册选择图片关联至对应国家,首次安装应用时保存图片功能正常,但重启应用后会崩溃。

我通过URI将图片上传至Firebase,若上传中断会将会话信息保存至DAO,后续通过cleanupCheck方法重试上传/删除操作。但调用该方法时会触发如下致命异常:

FATAL EXCEPTION: DefaultDispatcher-worker-1
Process: com.omersungur.theworldwander, PID: 13346
java.lang.SecurityException: Calling uid ( 10410 ) does not have permission to access picker uri: content://media/picker/0/com.android.providers.media.photopicker/media/1000005801
at android.os.Parcel.createExceptionOrNull(Parcel.java:3069)
at android.os.Parcel.createException(Parcel.java:3053)
at android.os.Parcel.readException(Parcel.java:3036)
at android.database.DatabaseUtils.readExceptionFromParcel(DatabaseUtils.java:190)
at android.database.DatabaseUtils.readExceptionWithFileNotFoundExceptionFromParcel(DatabaseUtils.java:153)
at android.content.ContentProviderProxy.openTypedAssetFile(ContentProviderNative.java:814)
at android.content.ContentResolver.openTypedAssetFileDescriptor(ContentResolver.java:2043)
at android.content.ContentResolver.openAssetFileDescriptor(ContentResolver.java:1858)
at android.content.ContentResolver.openFileDescriptor(ContentResolver.java:1689)
at android.content.ContentResolver.openFileDescriptor(ContentResolver.java:1635)
at com.google.firebase.storage.UploadTask.(UploadTask.java:140)
at com.google.firebase.storage.StorageReference.putFile(StorageReference.java:284)
at com.omersungur.theworldwander.core.ExtFunctionKt.retryUploadingImageToFirebase(ExtFunction.kt:61)
at com.omersungur.theworldwander.presentation.MainActivityKt$cleanupCheck$1.invokeSuspend(MainActivity.kt:108)
at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:108)
at kotlinx.coroutines.internal.LimitedDispatcher$Worker.run(LimitedDispatcher.kt:115)
at kotlinx.coroutines.scheduling.TaskImpl.run(Tasks.kt:103)
at kotlinx.coroutines.scheduling.CoroutineScheduler.runSafely(CoroutineScheduler.kt:584)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.executeTask(CoroutineScheduler.kt:793)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.runWorker(CoroutineScheduler.kt:697)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.run(CoroutineScheduler.kt:684)
Suppressed: kotlinx.coroutines.internal.DiagnosticCoroutineContextException: [StandaloneCoroutine{Cancelling}@b372588, Dispatchers.IO]

相关代码

相册选择器代码(Gallery Uploader Composable)

val context = LocalContext.current
val multiplePhotoPicker = rememberLauncherForActivityResult(
    contract = ActivityResultContracts.PickMultipleVisualMedia(maxItems = 8),
) { images ->
    images.forEach {
        onImageSelect(it)
        val name = context.packageName
        context.grantUriPermission(name, it, Intent.FLAG_GRANT_READ_URI_PERMISSION)
    }
}

MainActivity中的cleanupCheck方法

private fun cleanupCheck(
    scope: CoroutineScope,
    imageToUploadDao: ImageToUploadDao,
    imageToDeleteDao: ImageToDeleteDao
) {
    scope.launch(Dispatchers.IO) {
        val result = imageToUploadDao.getAllImages()
        result.forEach { imageToUpload ->
            retryUploadingImageToFirebase(
                imageToUpload = imageToUpload,
                onSuccess = {
                    scope.launch(Dispatchers.IO) {
                        imageToUploadDao.cleanupImage(imageToUpload.id)
                    }
                }
            )
        }
        val result2 = imageToDeleteDao.getAllImages()
        result2.forEach { imageToDelete ->
            retryDeletingImageFromFirebase(
                imageToDelete = imageToDelete,
                onSuccess = {
                    scope.launch(Dispatchers.IO) {
                        imageToDeleteDao.cleanupImage(imageId = imageToDelete.id)
                    }
                }
            )
        }
    }
}

扩展函数

fun retryUploadingImageToFirebase(
    imageToUpload: ImageToUpload,
    onSuccess: () -> Unit
) {
    val storage = FirebaseStorage.getInstance().reference
    storage.child(imageToUpload.remoteImagePath).putFile(
        imageToUpload.imageUrl.toUri(),
        storageMetadata { },
        imageToUpload.sessionUri.toUri()
    ).addOnSuccessListener { onSuccess() }
}

fun retryDeletingImageFromFirebase(
    imageToDelete: ImageToDelete,
    onSuccess: () -> Unit
) {
    val storage = FirebaseStorage.getInstance().reference
    storage.child(imageToDelete.remoteImagePath).delete()
        .addOnSuccessListener { onSuccess() }
}

移除cleanupCheck调用后则无异常,项目地址:https://github.com/omersungur/TheWorldWander


内容的提问来源于stack exchange,提问作者omersungur

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.03 05:23:17