Kotlin Android应用点击分享按钮崩溃:TransactionTooLargeException
问题根源分析
你遇到的TransactionTooLargeException是因为Binder事务传递的数据量超过了Android系统限制(单次Binder事务的大小上限通常在1MB左右)。核心错误出在代码逻辑的两个关键点:
Intent.EXTRA_STREAM参数的用途被误用——它要求传递的是文件的Uri,而不是Base64字符串。- 你的
imageViewToPdf返回Base64格式的PDF内容,Base64编码会让数据体积膨胀约30%,再加上扫描文档生成的PDF本身体积不小(日志显示已达5.5MB),直接通过Intent传递超大字符串必然触发事务大小限制。
排查步骤
- 确认
imageViewToPdf的输出:检查该函数确实返回了Base64字符串而非文件路径/Uri,这是触发崩溃的直接原因。 - 验证数据体积:将生成的Base64字符串转为字节数组,计算其长度,会发现远超过1MB的Binder事务上限。
解决思路与代码调整
1. 修改PDF生成逻辑,输出文件而非Base64字符串
让imageViewToPdf生成PDF文件并保存到应用的外部私有存储目录,返回File对象而非字符串:
fun imageViewToPdf(imageView: ImageView): File? { // 从ImageView获取Bitmap val bitmap = (imageView.drawable as BitmapDrawable).bitmap ?: return null // 创建存储PDF的目录与文件 val docsDir = context.getExternalFilesDir(Environment.DIRECTORY_DOCUMENTS) ?: return null val pdfFile = File(docsDir, "scanned_doc_${System.currentTimeMillis()}.pdf") // 示例:使用AndroidPdfLibrary将Bitmap写入PDF PdfDocument().apply { val pageInfo = PdfDocument.PageInfo.Builder(bitmap.width, bitmap.height, 1).create() val page = startPage(pageInfo) val canvas = page.canvas canvas.drawBitmap(bitmap, 0f, 0f, null) finishPage(page) writeTo(FileOutputStream(pdfFile)) close() } return pdfFile.takeIf { it.exists() && it.length() > 0 } }
2. 使用FileProvider生成可分享的Uri
Android 7.0及以上禁止直接暴露文件Uri,必须通过FileProvider生成安全Uri:
- 在
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 xmlns:android="http://schemas.android.com/apk/res/android"> <external-files-path name="documents" path="Documents" /> </paths>
3. 修正分享逻辑,传递正确的Uri并授予权限
shareBtn.setOnClickListener { val pdfFile = imageViewToPdf(croppedImageView) ?: return@setOnClickListener // 生成安全Uri val pdfUri = FileProvider.getUriForFile(this, "${packageName}.fileprovider", pdfFile) val shareIntent = Intent(Intent.ACTION_SEND).apply { putExtra(Intent.EXTRA_STREAM, pdfUri) type = "application/pdf" // 授予接收应用临时读取权限 addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION) } startActivity(Intent.createChooser(shareIntent, "分享扫描文档")) }
4. 额外优化建议
- 转PDF前压缩Bitmap:扫描的图片分辨率通常很高,可通过
Bitmap.compress()压缩后再写入PDF,进一步减小文件体积。 - 清理旧文件:每次生成新PDF时,删除目录下的旧文件,避免占用过多存储。
内容的提问来源于stack exchange,提问作者jelkaa
相关产品推荐
相关产品推荐

