Kotlin中Nearby Share传输图片异常:解码失败/显示不全求助
问题背景
在Kotlin中使用Nearby Share实现设备间字符串与图片传输,字符串传输正常,但图片接收后显示持续异常已超一个月,报错信息为:Failed to create image decoder with message 'input was incomplete'。现象不稳定:有时能正常显示,有时显示失败,有时仅显示一半。
原图片接收代码:
val uri = filePayloads[0].asFile()!!.asUri()!! val file = getExternalFilesDir(Environment.DIRECTORY_PICTURES).toString() + "/${endpointIdUserId.get(endpointId)}-profile-picture-" + System.currentTimeMillis().toString() + ".jpeg" File(file) val inp: InputStream? = contentResolver.openInputStream(uri) copyStream(inp!!, FileOutputStream(file)) contentResolver.delete(uri, null, null) val user = users.find { it.id == endpointIdUserId.get(endpointId) } user!!.pfp = file addPayload(endpointId) filePayloads.remove(filePayloads[0])
Fragment中读取Room数据库显示图片的代码:
if(currentItem.pfp != null) { holder.pfpImageView.setImageURI(Uri.parse(currentItem.pfp)) }
问题分析与解决方案
核心原因
报错及显示异常的本质是图片文件写入不完整,根源在于流操作未正确处理资源关闭、数据未完全写入就执行后续操作,或未确认Nearby Share文件已完全接收。
具体修复步骤
1. 修复流复制逻辑,确保资源正确关闭与数据完整写入
原代码未正确关闭流,可能导致部分数据滞留内存未写入磁盘。改用Kotlin标准库的copyTo方法,结合use块自动管理流资源:
val uri = filePayloads[0].asFile()!!.asUri()!! // 用File构造函数直接创建目标文件对象,避免字符串拼接错误 val targetFile = File( getExternalFilesDir(Environment.DIRECTORY_PICTURES), "${endpointIdUserId.get(endpointId)}-profile-picture-${System.currentTimeMillis()}.jpeg" ) // 安全获取输入流并完成复制,自动关闭流 contentResolver.openInputStream(uri)?.use { inputStream -> FileOutputStream(targetFile).use { outputStream -> inputStream.copyTo(outputStream) // 强制刷新输出流,确保所有数据写入磁盘 outputStream.flush() } } ?: run { // 处理输入流获取失败的异常情况 return@yourFunction } // 确认文件写入完成后,再删除Nearby Share的源文件 contentResolver.delete(uri, null, null) val user = users.find { it.id == endpointIdUserId.get(endpointId) } // 存储文件绝对路径,避免后续读取路径错误 user?.pfp = targetFile.absolutePath addPayload(endpointId) // 用removeAt更安全,避免因列表元素变化导致的索引错误 filePayloads.removeAt(0)
2. 校验文件完整性,避免处理损坏文件
复制完成后添加文件大小校验,过滤异常文件:
// 可根据实际图片大小调整阈值,比如最小100字节 if (targetFile.length() < 100) { // 文件异常,执行丢弃或重新请求逻辑 targetFile.delete() return@yourFunction }
3. 优化图片显示逻辑,增加异常兜底
原代码直接用setImageURI读取文件,无法处理文件未完成写入或损坏的情况。改用Coil/Glide等图片加载库,自动处理异常:
以Coil为例(需先添加依赖):
if (currentItem.pfp != null) { val imageFile = File(currentItem.pfp) if (imageFile.exists() && imageFile.length() > 0) { holder.pfpImageView.load(imageFile) { error(R.drawable.default_profile) // 加载失败显示默认图 placeholder(R.drawable.loading_placeholder) // 加载中显示占位图 } } else { holder.pfpImageView.setImageResource(R.drawable.default_profile) } }
4. 确保Nearby Share文件完全接收后再处理
在PayloadCallback中监听传输状态,仅当传输成功时才处理文件:
override fun onPayloadTransferUpdate(endpointId: String, update: PayloadTransferUpdate) { if (update.status == PayloadTransferUpdate.Status.SUCCESS) { // 在此处触发文件复制逻辑,确保文件已完全接收 processReceivedImage(endpointId, update.payloadId) } }
内容的提问来源于stack exchange,提问作者Bruno Piazza
相关产品推荐
相关产品推荐

