java - 如何在 SDK Q 及更高版本的下载文件夹中使用 FileProvider 和创建的 PFD
问题描述
最近我更新了一个面向 SDK 30 的应用程序,并调整了使用 Mediastore 创建和存储 PDF 的方式。对于创建和存储,我使用这段代码:
@RequiresApi(api = Build.VERSION_CODES.Q)
@NonNull
private Uri savePDFFile(@NonNull final Context context, @NonNull byte[] in,
@NonNull final String mimeType,
@NonNull final String displayName, @Nullable final String subFolder) throws IOException {
String relativeLocation = Environment.DIRECTORY_DOCUMENTS;
if (!TextUtils.isEmpty(subFolder)) {
relativeLocation += File.separator + subFolder;
}
final ContentValues contentValues = new ContentValues();
contentValues.put(MediaStore.MediaColumns.DISPLAY_NAME, displayName);
contentValues.put(MediaStore.MediaColumns.MIME_TYPE, mimeType);
contentValues.put(MediaStore.MediaColumns.RELATIVE_PATH, Environment.DIRECTORY_DOWNLOADS);
final ContentResolver resolver = context.getContentResolver();
OutputStream stream = null;
Uri uri = null;
try {
final Uri contentUri = MediaStore.Files.getContentUri("external");
uri = resolver.insert(MediaStore.Downloads.EXTERNAL_CONTENT_URI, contentValues);
ParcelFileDescriptor pfd;
try {
assert uri != null;
pfd = context.getContentResolver().openFileDescriptor(uri, "w");
assert pfd != null;
FileOutputStream out = new FileOutputStream(pfd.getFileDescriptor());
out.write(in);
out.close();
pfd.close();
} catch (Exception e) {
e.printStackTrace();
}
contentValues.clear();
contentValues.put(MediaStore.Video.Media.IS_PENDING, 0);
context.getContentResolver().update(uri, contentValues, null, null);
stream = resolver.openOutputStream(uri);
if (stream == null) {
throw new IOException("Failed to get output stream.");
}
return uri;
} catch (IOException e) {
// Don't leave an orphan entry in the MediaStore
resolver.delete(uri, null, null);
throw e;
} finally {
if (stream != null) {
stream.close();
renderPDF(this.fileName, this.fileType);
}
}
}
PDf 存储在 /storage/emulated/0/Download 中,一旦保存,我想按意图渲染它
File path = Environment.getExternalStoragePublicDirectory(
Environment.DIRECTORY_DOWNLOADS);
File file = new File(path.toString() + "/" + fileName + "." + filetype);
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setFlags(Intent.FLAG_ACTIVITY_NO_HISTORY);
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
intent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
intent.setDataAndType(FileProvider.getUriForFile(this, getPackageName() + ".provider",file), "application/pdf");
我的 provider_paths.xml 设置如下:
<?xml version="1.0" encoding="utf-8"?>
<paths>
<external-path
name="external"
path="Download/" />
<external-files-path
name="external_files"
path="Download/" />
<files-path
name="files"
path="Download/" />
</paths>
此时,当您下载 pdf 时会显示您要选择的 pdf 阅读器,当您选择一个时会显示一条消息错误,提示路径太长?!?(已丢弃)或者 Google Drive Pdf 阅读器是否显示一毫秒空白屏幕并再次返回应用程序。
如何正确检索 pdf 文件并使用 FileProvider 启动意图?我认为此时问题出在 FileProvider 中,但我不知道如何...
intent.setDataAndType(FileProvider.getUriForFile(this, getPackageName() + ".provider",file), "application/pdf");
解决方案
推荐阅读
- flutter - 我不能在 ScrollView 中使用 GridView,我只能使用展开后的 GridView。如何在页面中添加真正的 ScrollView?
- mysql - 如何在laravel中访问具有两个外键的表的数据
- python - 将熊猫数据框从一个jupyter笔记本复制到另一个的最佳方法是什么
- sql-server - ASP.NET 应用程序使用唯一的活动目录凭据连接到远程 SQL Server
- android - 完全透明的状态栏在某些设备上不起作用
- c# - QnA Api 返回响应代码 200 OK,无论 KB 中是否存在匹配项
- c# - 我可以创建 C# 独立应用程序而不是在 Windows 中安装而不运行吗?
- java - 哪些版本的 Atlassian 插件 SDK 支持哪些版本的 confluence?
- sql - 如何按家庭计算孩子的数量并将其放在oracle中的父行中
- python - 如何在 django 中保存一个模型的 3 种形式?