android - 如何将pdf保存在范围存储中?
问题描述
在引入范围存储之前,我使用下载管理器在我的应用程序中下载 pdf 并从中获取 pdf getExternalStorageDirectory
,但由于范围存储,我不能再使用getExternalStorageDirectory
它,因为它已被弃用。我决定离开下载管理器,它在公共目录中下载文件,而是使用改造来下载 pdf 文件。我知道我可以requiredLegacyStorage
在 Android Manifest 中使用该标签,但它不适用于 Android 11,所以我没有使用它。
这是我的代码
fun readAndDownloadFile(context: Context) {
readQuraanInterface?.downloadFile()
Coroutines.io {
file = File(context.filesDir,"$DESTINATION_DIRECTORY/$FILE_NAME$FILE_EXTENSION")
if (file?.exists() == true) {
renderPDF()
showPdf(mPageIndex, Direction.None)
} else {
Log.i("new","new0")
val response = readQuraanRepository.downloadPdf()
if (response.isSuccessful) {
Log.i("new","new00 ${file!!.path} ${response.body()?.byteStream().toString()}")
response.body()?.byteStream()?.let {
file!!.copyInputStreamToFile(
it
)
}
Log.i("new","new1")
// renderPDF()
// showPdf(mPageIndex, Direction.None)
} else {
Log.i("new","new2")
Coroutines.main {
response.errorBody()?.string()
?.let { readQuraanInterface?.downloadFailed(it) }
}
}
}
}
}
private fun File.copyInputStreamToFile(inputStream: InputStream) {
this.outputStream().use { fileOut ->
Log.i("new","new30")
inputStream.copyTo(fileOut)
}
}
虽然下载了 pdf id,但该文件从未使用我编写的 InputStream 辅助函数存储。我需要将该 pdf 添加到我的应用程序的内部存储中,并使用 PDFRenderer 渲染它。
解决方案
您可以使用以下代码使用范围存储下载和保存 PDF。这里我使用的是下载目录。不要忘记提供所需的权限。
@RequiresApi(Build.VERSION_CODES.Q)
fun downloadPdfWithMediaStore() {
CoroutineScope(Dispatchers.IO).launch {
try {
val url =
URL("https://www.w3.org/WAI/ER/tests/xhtml/testfiles/resources/pdf/dummy.pdf")
val connection: HttpURLConnection = url.openConnection() as HttpURLConnection
connection.requestMethod = "GET"
connection.doOutput = true
connection.connect()
val pdfInputStream: InputStream = connection.inputStream
val values = ContentValues().apply {
put(MediaStore.Downloads.DISPLAY_NAME, "test")
put(MediaStore.Downloads.MIME_TYPE, "application/pdf")
put(MediaStore.Downloads.IS_PENDING, 1)
}
val resolver = context.contentResolver
val collection =
MediaStore.Downloads.getContentUri(MediaStore.VOLUME_EXTERNAL_PRIMARY)
val itemUri = resolver.insert(collection, values)
if (itemUri != null) {
resolver.openFileDescriptor(itemUri, "w").use { parcelFileDescriptor ->
ParcelFileDescriptor.AutoCloseOutputStream(parcelFileDescriptor)
.write(pdfInputStream.readBytes())
}
values.clear()
values.put(MediaStore.Downloads.IS_PENDING, 0)
resolver.update(itemUri, values, null, null)
}
} catch (e: Exception) {
e.printStackTrace()
}
}
}
推荐阅读
- c - 添加第二个循环
- python - 列表索引未在 for 循环中更新(python)
- c# - 根据时区在一天中的特定时间安排hangfire作业
- r - 在闪亮的应用程序中更改标签内的字体
- c# - 是否可以在低于 6 的 EF 版本中拦截来自 EF 的数据库查询?
- angular - 将 environment.ts 传递给 Angular 库模块
- r - R中一张图表上的多条线
- c# - 使用 AutoMapper 将 ef 模型映射到 dto,DateTime 数据类型引发异常
- vue.js - 如何在 v-for 循环中调用模态组件?
- mysql - mysql在状态A,B和状态C中选择没有卡的用户