使用registerForActivityResult选PDF Android7下路径错误无法获取文件名
问题根因
ActivityResultContracts.GetContent()返回的是content://开头的内容Uri,不属于本地文件路径格式,调用uri.getPath()获取到的只是Uri的路径片段,不是文件的实际存储路径。Android 10上能正常显示属于特殊场景下的巧合,不是通用的正确用法。
你无需获取文件实际存储路径,也不需要申请额外存储权限:系统文件选择器返回的Uri自带临时读取权限,足够你读取文件内容、元数据(文件名、类型、大小等),你已有的上传逻辑能正常运行就是证明。
解决方案
1. 实现Uri元数据读取工具方法
import android.provider.OpenableColumns; import android.database.Cursor; import android.net.Uri; // 从Content Uri获取文件名 private String getFileNameFromUri(Uri uri) { String fileName = null; Cursor cursor = getContentResolver().query(uri, null, null, null, null); if (cursor != null && cursor.moveToFirst()) { int nameIndex = cursor.getColumnIndex(OpenableColumns.DISPLAY_NAME); fileName = cursor.getString(nameIndex); cursor.close(); } // 异常场景兜底 if (fileName == null) { fileName = "pdf_file_" + System.currentTimeMillis() + ".pdf"; } return fileName; } // 从Content Uri获取文件MIME类型 private String getFileTypeFromUri(Uri uri) { String mimeType = getContentResolver().getType(uri); // 因为启动选择器时指定了仅选PDF,异常场景直接兜底为PDF类型 if (mimeType == null) { mimeType = "application/pdf"; } return mimeType; }
2. 替换原有Uri处理逻辑
修改你原有registerForActivityResult的回调逻辑,直接读取文件名显示即可:
mGetContent = registerForActivityResult(new ActivityResultContracts.GetContent(), uri -> { if(uri!=null) { noticeUri = uri; // 读取文件名、类型 String pdfFileName = getFileNameFromUri(uri); String pdfFileType = getFileTypeFromUri(uri); // 显示文件名 textViewNoticeName.setText(pdfFileName); // 原有上传逻辑无需修改,直接用noticeUri读文件流即可 } else{ Toast.makeText(CROption.this, "未选择任何文件", Toast.LENGTH_SHORT).show(); } });
注意事项
- 不要尝试将Content Uri转换为本地文件路径:不同Android版本、不同厂商的文件管理器返回的Uri规则差异极大,适配成本极高,直接通过ContentResolver操作Uri即可满足所有需求
- 全程不需要申请存储权限:系统返回的Uri自带临时访问权限,权限范围仅限你选中的单个文件,符合权限最小化要求
- 如果需要获取文件大小,也可以直接从Uri中读取:在查询Cursor时取
OpenableColumns.SIZE字段即可
内容的提问来源于stack exchange,提问作者abusaeed2433
相关产品推荐
相关产品推荐

