修复firebase崩溃错误,1.0.3(3)

This commit is contained in:
ocean 2025-11-26 11:33:17 +08:00
parent 30c04ee7d9
commit 70850c8a2c
7 changed files with 114 additions and 71 deletions

View File

@ -16,6 +16,7 @@ import com.all.pdfreader.pdf.reader.ui.dialog.PdfPasswordProtectionDialogFragmen
import com.all.pdfreader.pdf.reader.util.AppUtils.setOnSingleClickListener
import com.all.pdfreader.pdf.reader.util.FileUtils.isPdfEncrypted
import com.all.pdfreader.pdf.reader.util.PdfUtils
import com.all.pdfreader.pdf.reader.util.ToastUtils
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
@ -55,8 +56,8 @@ class PdfToImageActivity : BaseActivity() {
statusBarDarkFont(true)
navigationBarColor(R.color.bg_color)
}
filePath = intent.getStringExtra(EXTRA_PDF_PATH)
?: throw IllegalArgumentException("PDF file hash is required")
filePath = intent.getStringExtra(EXTRA_PDF_PATH) ?: ""
source = getSerializableOrDefault(EXTRA_SOURCE, PdfPickerSource.NONE)
if (filePath.isEmpty()) {
showToast(getString(R.string.file_not))
@ -153,8 +154,18 @@ class PdfToImageActivity : BaseActivity() {
PdfUtils.splitPdfToPageItemsFlow(
context = this@PdfToImageActivity,
inputFile = file,
password = password
password = password,
onError = { e ->
runOnUiThread {
ToastUtils.show(
this@PdfToImageActivity,
getString(R.string.file_not_pdf_or_corrupted)
)
finish()
}
}
).collect { pageItem ->
logDebug("splitPdfToPageItemsFlow pageItem->$pageItem")
if (pdfPageList.size <= pageItem.pageIndex) {
pdfPageList.add(pageItem)

View File

@ -49,12 +49,12 @@ class PdfViewActivity : BaseActivity(), OnLoadCompleteListener, OnPageChangeList
get() = binding.rootBottomLayout
companion object {
const val FRAG_TAG = "PdfViewActivity"
private const val EXTRA_PDF_HASH = "extra_pdf_hash"
private const val EXTRA_PDF_FILE_PATH = "extra_pdf_file_path"
// 创建启动Intent的便捷方法
fun createIntent(context: Context, filePath: String): Intent {
return Intent(context, PdfViewActivity::class.java).apply {
putExtra(EXTRA_PDF_HASH, filePath)
putExtra(EXTRA_PDF_FILE_PATH, filePath)
}
}
}
@ -81,9 +81,12 @@ class PdfViewActivity : BaseActivity(), OnLoadCompleteListener, OnPageChangeList
navigationBarColor(R.color.white)
}
setupDoubleBackExit()
val filePath = intent.getStringExtra(EXTRA_PDF_FILE_PATH) ?: ""
if (filePath.isEmpty()) {
showToast(getString(R.string.file_not))
finish()
}
initObserve()
val filePath = intent.getStringExtra(EXTRA_PDF_HASH)
?: throw IllegalArgumentException("PDF file hash is required")
// 加载PDF数据
viewModel.getPDFDocument(filePath)
//加载书签数据

View File

@ -23,6 +23,7 @@ import com.all.pdfreader.pdf.reader.util.AppUtils.setOnSingleClickListener
import com.all.pdfreader.pdf.reader.util.FileUtils.isPdfEncrypted
import com.all.pdfreader.pdf.reader.util.FileUtils.toUnderscoreDateTime
import com.all.pdfreader.pdf.reader.util.PdfUtils
import com.all.pdfreader.pdf.reader.util.ToastUtils
import com.gyf.immersionbar.ImmersionBar
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
@ -35,7 +36,7 @@ class SplitPdfActivity : BaseActivity() {
get() = binding.rootBottomLayout
private var currentViewState: ViewState = ViewState.SPLIT_LIST
var currentPassword : String? = null//拆分只会选择一个文件。直接进行密码传递
var currentPassword: String? = null//拆分只会选择一个文件。直接进行密码传递
private enum class ViewState {
SPLIT_LIST, // 拆分页列表
@ -69,8 +70,7 @@ class SplitPdfActivity : BaseActivity() {
statusBarDarkFont(true)
navigationBarColor(R.color.bg_color)
}
filePath = intent.getStringExtra(EXTRA_PDF_PATH)
?: throw IllegalArgumentException("PDF file hash is required")
filePath = intent.getStringExtra(EXTRA_PDF_PATH) ?: ""
if (filePath.isEmpty()) {
showToast(getString(R.string.file_not))
finish()
@ -174,7 +174,7 @@ class SplitPdfActivity : BaseActivity() {
}
private fun initSplitDataWithPassword(file: File, password: String? = null) {
if(!password.isNullOrEmpty()){
if (!password.isNullOrEmpty()) {
currentPassword = password
}
lifecycleScope.launch {
@ -188,7 +188,16 @@ class SplitPdfActivity : BaseActivity() {
PdfUtils.splitPdfToPageItemsFlow(
context = this@SplitPdfActivity,
inputFile = file,
password = password
password = password,
onError = { e ->
runOnUiThread {
ToastUtils.show(
this@SplitPdfActivity,
getString(R.string.file_not_pdf_or_corrupted)
)
finish()
}
}
).collect { pageItem ->
logDebug("splitPdfToPageItemsFlow pageItem->$pageItem")
if (splitList.size <= pageItem.pageIndex) {

View File

@ -518,24 +518,10 @@ object FileUtils {
}
fun getFileFromUri(context: Context, uri: Uri): File? {
// 先尝试通过 DATA 字段获取
val projection = arrayOf(MediaStore.Files.FileColumns.DATA)
context.contentResolver.query(uri, projection, null, null, null)?.use { cursor ->
if (cursor.moveToFirst()) {
val path =
cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Files.FileColumns.DATA))
if (!path.isNullOrEmpty()) {
val file = File(path)
if (file.exists()) {
return file
}
}
}
}
// Android 10+ 或 DATA 字段为空时,使用 ContentResolver 流访问
return try {
val tempFile = File(context.cacheDir, "temp_pdf_${System.currentTimeMillis()}.pdf")
val fileName = getFileName(context, uri) ?: "temp_${System.currentTimeMillis()}"
val tempFile = File(context.cacheDir, fileName)
context.contentResolver.openInputStream(uri)?.use { input ->
tempFile.outputStream().use { output ->
input.copyTo(output)
@ -543,11 +529,28 @@ object FileUtils {
}
tempFile
} catch (e: Exception) {
// Log.e("ocean", "无法获取文件: ${e.message}", e)
e.printStackTrace()
null
}
}
private fun getFileName(context: Context, uri: Uri): String? {
return try {
val cursor = context.contentResolver.query(uri,
arrayOf(MediaStore.Files.FileColumns.DISPLAY_NAME),
null, null, null)
cursor?.use {
if (it.moveToFirst()) {
return it.getString(0)
}
}
null
} catch (e: Exception) {
null
}
}
fun duplicateFile(originalFile: File): File? {
if (!originalFile.exists()) return null

View File

@ -86,7 +86,8 @@ class PDFSearchManager(private val pdfView: PDFView) {
onLoaded?.invoke(cachedDoc!!)
} catch (e: Exception) {
onError?.invoke(e)
throw e
cachedDoc = null
cachedPath = null
}
} else {
// 已缓存文档,仍可调用回调

View File

@ -52,53 +52,68 @@ object PdfUtils {
dpi: Float = 72f,
chunkSize: Int = 5,
thumbWidth: Int = 200,
password: String? = null
password: String? = null,
onError: ((Exception) -> Unit)? = null
): Flow<PdfPageItem> = flow {
val pdfiumCore = PdfiumCore(context)
ParcelFileDescriptor.open(inputFile, ParcelFileDescriptor.MODE_READ_ONLY).use { fd ->
val pdfDocument = if (password.isNullOrEmpty()) {
pdfiumCore.newDocument(fd)
} else {
pdfiumCore.newDocument(fd, password)
}
val pageCount = pdfiumCore.getPageCount(pdfDocument)
val pages = List(pageCount) {
PdfPageItem(pageIndex = it, previewFilePath = null, isSelected = false)
}
// 先 emit 页对象,让 UI 知道总页数
pages.forEach { emit(it) }
val cacheDir = File(context.cacheDir, child).apply { mkdirs() }
for (i in 0 until pageCount) {
pdfiumCore.openPage(pdfDocument, i)
val width = (pdfiumCore.getPageWidthPoint(pdfDocument, i) * dpi / 72).toInt()
val height = (pdfiumCore.getPageHeightPoint(pdfDocument, i) * dpi / 72).toInt()
val scale = thumbWidth.toFloat() / width
val targetHeight = (height * scale).toInt()
val bitmap = createBitmap(thumbWidth, targetHeight, Bitmap.Config.RGB_565)
pdfiumCore.renderPageBitmap(pdfDocument, bitmap, i, 0, 0, thumbWidth, targetHeight)
// 保存为压缩 JPEG
val outFile = File(cacheDir, inputFile.name + "_page_$i.jpg")
FileOutputStream(outFile).use { fos ->
bitmap.compress(Bitmap.CompressFormat.JPEG, 70, fos)
try {
ParcelFileDescriptor.open(inputFile, ParcelFileDescriptor.MODE_READ_ONLY).use { fd ->
val pdfDocument = try {
if (password.isNullOrEmpty()) {
pdfiumCore.newDocument(fd)
} else {
pdfiumCore.newDocument(fd, password)
}
} catch (e: Exception) {
onError?.invoke(e)
return@flow // 直接退出 flow不崩溃
}
bitmap.recycle()
pages[i].previewFilePath = outFile.absolutePath
emit(pages[i])
val pageCount = pdfiumCore.getPageCount(pdfDocument)
val pages = List(pageCount) {
PdfPageItem(pageIndex = it, previewFilePath = null, isSelected = false)
}
if ((i + 1) % chunkSize == 0) delay(50) // 分批渲染,保证 UI 流畅
// 先 emit 页对象,让 UI 知道总页数
pages.forEach { emit(it) }
val cacheDir = File(context.cacheDir, child).apply { mkdirs() }
for (i in 0 until pageCount) {
try {
pdfiumCore.openPage(pdfDocument, i)
val width = (pdfiumCore.getPageWidthPoint(pdfDocument, i) * dpi / 72).toInt()
val height = (pdfiumCore.getPageHeightPoint(pdfDocument, i) * dpi / 72).toInt()
val scale = thumbWidth.toFloat() / width
val targetHeight = (height * scale).toInt()
val bitmap = createBitmap(thumbWidth, targetHeight, Bitmap.Config.RGB_565)
pdfiumCore.renderPageBitmap(pdfDocument, bitmap, i, 0, 0, thumbWidth, targetHeight)
val outFile = File(cacheDir, inputFile.name + "_page_$i.jpg")
FileOutputStream(outFile).use { fos ->
bitmap.compress(Bitmap.CompressFormat.JPEG, 70, fos)
}
bitmap.recycle()
pages[i].previewFilePath = outFile.absolutePath
emit(pages[i])
if ((i + 1) % chunkSize == 0) delay(50)
} catch (e: Exception) {
// 单页渲染失败也不崩溃,只提示
onError?.invoke(e)
}
}
pdfiumCore.closeDocument(pdfDocument)
}
pdfiumCore.closeDocument(pdfDocument)
} catch (e: Exception) {
// 打开文件失败或 PFDium 异常
onError?.invoke(e)
}
}.flowOn(Dispatchers.IO)

View File

@ -193,4 +193,5 @@
<string name="save_to_album">Save to Album</string>
<string name="one_image_converted">1 image converted</string>
<string name="number_image_converted">%1$d imagesF converted</string>
<string name="file_not_pdf_or_corrupted">File not in PDF format or corrupted</string>
</resources>