如何解决使用PdfBox提取PDF文本时出现的ExceptionInInitialize及空指针异常
问题根源
- 异步调用逻辑错误:
registerForActivityResult的launch方法是异步触发系统文件选择器,调用launch后立刻判断fileUri是否非空时,用户还未选择文件、回调还未执行,fileUri仍为null,后续提取逻辑直接触发空指针。 - PDFTextStripper类初始化失败:你使用的是Android端适配的PdfBox分支(
com.tom_roush.pdfbox),该库初始化PDFTextStripper时需要读取内置的字体配置资源,如果构建配置开启了混淆、资源压缩,或者未正确引入依赖的fontbox组件,就会导致读取资源的InputStream为null,关闭时抛出你日志中显示的<clinit>阶段空指针。 - 代码空安全处理不到位:document加载失败时为null、inputStream打开失败时为null的场景都没有做拦截处理,会触发后续逻辑空指针。
解决方案
1. 修复异步调用逻辑
将extractTextPdfFile的调用放到registerForActivityResult的回调中,选到文件后再执行提取逻辑,修改后代码:
private var fileUri: Uri? = null private val getContent = registerForActivityResult(ActivityResultContracts.GetContent()) { uri: Uri? -> // Handle the returned Uri if (uri != null) { fileUri = uri // 选到文件后再调用提取逻辑 extractTextPdfFile() } else { Toast.makeText( this, "Cannot fetch document from the file manager", Toast.LENGTH_SHORT ).show() } } override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) findViewById<Button>(R.id.Import).setOnClickListener { // 仅触发文件选择器,不要在此处判断fileUri getContent.launch("application/pdf") } }
2. 修复PDFTextStripper初始化错误
依次做以下配置:
- 确保引入完整依赖,在Module级
build.gradle的dependencies块中添加:
implementation 'com.tom_roush:pdfbox-android:1.8.10.0' implementation 'com.tom_roush:fontbox-android:1.8.10.0'
- 在
proguard-rules.pro中添加混淆规则,避免PdfBox相关类和资源被混淆压缩:
-keep class com.tom_roush.** { *; } -dontwarn com.tom_roush.**
- 如果开启了资源压缩,在
res/xml/keep.xml中添加规则保留PdfBox需要的资源:
<?xml version="1.0" encoding="utf-8"?> <resources xmlns:tools="http://schemas.android.com/tools" tools:keep="@raw/*" tools:shrinkMode="strict"/>
3. 优化提取代码的空安全处理
修改extractTextPdfFile方法,提前拦截空指针场景:
private fun extractTextPdfFile() { var document: PDDocument? = null var parsedText: String = "解析失败,请检查文件是否有效" // 提前判断fileUri非空 val uri = fileUri ?: return try { val inputStream: InputStream? = this.contentResolver.openInputStream(uri) inputStream?:return document = PDDocument.load(inputStream) val pdfStripper = PDFTextStripper() pdfStripper.startPage = 0 pdfStripper.endPage = 1 parsedText="Parsed text: " + pdfStripper.getText(document) } catch (e: Exception) { e.printStackTrace() } finally { try { document?.close() } catch (e: IOException) { e.printStackTrace() } } findViewById<TextView>(R.id.file_path).text=parsedText }
内容的提问来源于stack exchange,提问作者Sarthak Kumar
相关产品推荐
相关产品推荐

