You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.14 20:25:56