Android Java中读取Byte数据展示PDF及传递Byte至PDF的方法
Android 处理API返回的PDF字节数据实现方案
一、依赖说明
- 系统原生方案:使用
PdfRenderer,支持Android 5.0(API 21+),无需额外依赖。 - 第三方增强方案:如需要批注、搜索等功能,可使用
AndroidPdfViewer库。
二、读取API返回的PDF字节数据
Retrofit 实现
定义API接口:
interface PdfApiService { @GET("your/pdf/endpoint") suspend fun fetchPdf(): ResponseBody }
获取字节数组:
// 在ViewModel/Repository中调用 val pdfBytes = pdfApiService.fetchPdf().bytes()
OkHttp 实现
val client = OkHttpClient() val request = Request.Builder().url("your-pdf-url").build() val response = client.newCall(request).execute() val pdfBytes = response.body?.bytes()
三、展示PDF
方案1:系统原生PdfRenderer
1. 将字节写入临时文件
fun writePdfToTempCache(context: Context, pdfBytes: ByteArray): File { val tempFile = File(context.cacheDir, "temp_${System.currentTimeMillis()}.pdf") FileOutputStream(tempFile).use { it.write(pdfBytes) } return tempFile }
2. 实现页面渲染适配器
用ViewPager2展示多页PDF:
class PdfPageAdapter(private val renderer: PdfRenderer) : RecyclerView.Adapter<PdfPageAdapter.ViewHolder>() { inner class ViewHolder(val imageView: ImageView) : RecyclerView.ViewHolder(imageView) override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder { val imageView = ImageView(parent.context).apply { layoutParams = ViewGroup.LayoutParams( ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT ) scaleType = ImageView.ScaleType.FIT_CENTER } return ViewHolder(imageView) } override fun onBindViewHolder(holder: ViewHolder, position: Int) { renderer.openPage(position).use { page -> val bitmap = Bitmap.createBitmap(page.width, page.height, Bitmap.Config.ARGB_8888) page.render(bitmap, null, null, PdfRenderer.Page.RENDER_MODE_FOR_DISPLAY) holder.imageView.setImageBitmap(bitmap) } } override fun getItemCount(): Int = renderer.pageCount }
3. 在Activity中初始化
class PdfDisplayActivity : AppCompatActivity() { private var pdfRenderer: PdfRenderer? = null override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_pdf_display) val pdfBytes = intent.getByteArrayExtra("PDF_BYTES") ?: return val tempFile = writePdfToTempCache(this, pdfBytes) val parcelFd = ParcelFileDescriptor.open(tempFile, ParcelFileDescriptor.MODE_READ_ONLY) pdfRenderer = PdfRenderer(parcelFd) findViewById<ViewPager2>(R.id.view_pager).adapter = PdfPageAdapter(pdfRenderer!!) } override fun onDestroy() { super.onDestroy() pdfRenderer?.close() } }
对应布局activity_pdf_display.xml:
<?xml version="1.0" encoding="utf-8"?> <androidx.viewpager2.widget.ViewPager2 xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/view_pager" android:layout_width="match_parent" android:layout_height="match_parent" />
方案2:第三方AndroidPdfViewer
添加依赖(build.gradle):
implementation 'com.github.barteksc:android-pdf-viewer:3.2.0-beta.1'
直接加载字节数组:
// 在Activity/Fragment中 findViewById<PDFView>(R.id.pdf_view).apply { fromBytes(pdfBytes) .defaultPage(0) .enableSwipe(true) .swipeHorizontal(false) .load() }
对应布局:
<com.github.barteksc.pdfviewer.PDFView android:id="@+id/pdf_view" android:layout_width="match_parent" android:layout_height="match_parent" />
四、传递PDF字节数据
1. 组件间传递
小体积字节数组(<1MB):用Intent
val intent = Intent(this, PdfDisplayActivity::class.java) intent.putExtra("PDF_BYTES", pdfBytes) startActivity(intent)
大体积字节数组:用全局单例
避免TransactionTooLargeException:
// 定义全局数据 holder object PdfDataHolder { var pdfBytes: ByteArray? = null } // 发送方 PdfDataHolder.pdfBytes = pdfBytes startActivity(Intent(this, PdfDisplayActivity::class.java)) // 接收方 val pdfBytes = PdfDataHolder.pdfBytes ?: return PdfDataHolder.pdfBytes = null // 使用后清空,防止内存泄漏
2. 传递给其他操作
保存到本地存储
fun savePdfToDocuments(context: Context, pdfBytes: ByteArray, fileName: String): Boolean { val docsDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOCUMENTS) val pdfFile = File(docsDir, "$fileName.pdf") return try { FileOutputStream(pdfFile).use { it.write(pdfBytes) } // 通知系统更新媒体库 MediaScannerConnection.scanFile(context, arrayOf(pdfFile.path), arrayOf("application/pdf"), null) true } catch (e: Exception) { e.printStackTrace() false } }
注意:Android 10+需适配Scoped Storage,Android 13+需申请READ_MEDIA_IMAGES/READ_MEDIA_DOCUMENTS权限。
分享PDF
fun sharePdf(context: Context, pdfBytes: ByteArray) { val tempFile = writePdfToTempCache(context, pdfBytes) val uri = FileProvider.getUriForFile(context, "${context.packageName}.fileprovider", tempFile) val shareIntent = Intent(Intent.ACTION_SEND).apply { type = "application/pdf" putExtra(Intent.EXTRA_STREAM, uri) addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION) } context.startActivity(Intent.createChooser(shareIntent, "分享PDF")) }
需在AndroidManifest.xml配置FileProvider:
<provider android:name="androidx.core.content.FileProvider" android:authorities="${applicationId}.fileprovider" android:exported="false" android:grantUriPermissions="true"> <meta-data android:name="android.support.FILE_PROVIDER_PATHS" android:resource="@xml/file_paths" /> </provider>
res/xml/file_paths.xml:
<?xml version="1.0" encoding="utf-8"?> <paths> <cache-path name="pdf_cache" path="." /> </paths>
内容的提问来源于stack exchange,提问作者molige srinivas
相关产品推荐
相关产品推荐

