Android向Apollo-GraphQL传图报错:ENOENT文件不存在
解决Apollo-GraphQL上传图片时的ENOENT文件找不到错误
这个错误的核心原因很明确:你传入的路径是Android Content URI(/document/1804-2E16:DCIM/definicion-de-persona-min.jpg),而非真实的文件系统路径,直接用File(imagen.path!!)去访问肯定找不到对应的文件——因为这个URI并不是文件系统里的真实路径,File类自然无法识别它,所以抛出了ENOENT (No such file or directory)错误。
问题分析
从Android 10(API 29)开始,系统就限制了直接访问外部存储的文件路径,推荐使用Content URI来访问媒体文件。你拿到的这种/document/...格式的路径,是系统提供的内容访问标识符,本质上是指向媒体库中文件的“索引”,不是磁盘上的真实文件路径,直接用File类读取自然会失败。
解决方案:通过ContentResolver获取输入流上传
Apollo的FileUpload支持通过InputStream构建,我们可以利用Android的ContentResolver从Content URI中获取文件的输入流,再传入FileUpload,这样就能绕过直接访问文件路径的问题。
修改你的代码如下:
lifecycleScope.launch { val response = try { // 获取ContentResolver实例 val contentResolver = requireContext().contentResolver // 解析Content URI并打开输入流,用use块自动关闭流避免资源泄漏 contentResolver.openInputStream(Uri.parse(imagen.path!!))?.use { inputStream -> apolloClient(requireContext()).mutate( SubirImagenMutation( imagenData = FileUpload("image/jpg", inputStream) ) ).toDeferred().await() } ?: run { // 处理输入流获取失败的情况 Toasts().visualizarToast(requireContext(), getString(R.string.str_err_imagen_no_encontrada)) return@launch } } catch (e: ApolloException) { Toasts().visualizarToast(requireContext(), getString(R.string.str_err_generico)) return@launch } catch (e: FileNotFoundException) { // 捕获文件找不到的异常,给出更明确的提示 Toasts().visualizarToast(requireContext(), getString(R.string.str_err_imagen_no_encontrada)) return@launch } findNavController().navigate(R.id.serviciosFragment) }
额外注意事项
- 权限适配:如果你的应用目标SDK是Android 13(API 33)及以上,需要将
READ_EXTERNAL_STORAGE权限替换为READ_MEDIA_IMAGES,同时确保在运行时请求了对应的权限。 - URI有效性:要保证
imagen.path是从系统Intent(比如相册选择)返回的合法Content URI,避免传入无效的路径字符串。 - 流的管理:使用
use块可以自动关闭输入流,避免出现资源泄漏问题。
内容的提问来源于stack exchange,提问作者AlejandroOO
相关产品推荐
相关产品推荐

