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

使用Retrofit下载文件后无法正常打开的问题排查请求

Retrofit下载文件后无法正常打开:图片黑屏/文件格式错误排查

问题描述:使用Retrofit下载文件时,日志显示下载完成且大小匹配,但打开文件时图片显示黑屏,其他文件提示格式错误。

文件创建代码

val file = File(getExternalFilesDir(null), event.fileName)

ResponseBody写入磁盘代码

private fun writeResponseBodyToDisk(body: ResponseBody, file: File): Boolean {
    return try {
        // todo change the file location/name according to your needs
        val futureStudioIconFile: File = file
        var inputStream: InputStream? = null
        var outputStream: OutputStream? = null
        try {
            val fileReader = ByteArray(4096)
            val fileSize: Long = body.contentLength()
            var fileSizeDownloaded: Long = 0
            inputStream = body.byteStream()
            outputStream = FileOutputStream(futureStudioIconFile)
            while (true) {
                val read: Int = inputStream.read(fileReader)
                if (read == -1) {
                    break
                }
                outputStream.write(fileReader, 0, read)
                fileSizeDownloaded += read.toLong()
                Timber.d("%s%s", "file download: $fileSizeDownloaded of ", fileSize)
            }
            outputStream.flush()

            viewState.value = ViewState.ShowFile(file)
            true
        } catch (e: IOException) {
            false
        } finally {
            inputStream?.close()
            outputStream?.close()
        }
    } catch (e: IOException) {
        false
    }
}

文件查看代码

val fileUri = FileProvider.getUriForFile(
                this,
                "${BuildConfig.APPLICATION_ID}.fileprovider",
                state.file
            )
            startActivity(
                Intent.createChooser(
                    Intent().apply {
                        action = Intent.ACTION_VIEW
                        putExtra(Intent.EXTRA_STREAM, fileUri)
                        clipData = ClipData.newRawUri("", fileUri)
                        type = "*/*"
                        addFlags(
                            Intent.FLAG_GRANT_READ_URI_PERMISSION or Intent.FLAG_GRANT_WRITE_URI_PERMISSION
                        )
                    },
                    null
                )
            )

下载日志

file download: 4096 of 21688
file download: 8192 of 21688 
file download: 12288 of 21688
file download: 16384 of 21688
file download: 20480 of 21688
file download: 21688 of 21688

排查方向

  • 检查Retrofit接口配置:确保接口返回ResponseBody时,添加@Streaming注解,且该接口未被Gson等JSON转换器处理。如果未加@Streaming,大文件可能被缓存到内存导致写入数据损坏。
  • 验证文件完整性:将下载后的文件传到电脑,对比原文件的MD5/SHA哈希值。若不匹配,说明写入过程存在问题:
    • 写入前先调用file.delete()清空旧文件,避免残留数据干扰;
    • 改用Kotlin的use函数自动管理流,替代手动循环,减少出错概率:
      body.byteStream().use { inputStream ->
          FileOutputStream(file).use { outputStream ->
              inputStream.copyTo(outputStream, bufferSize = 4096)
          }
      }
      
  • 检查响应压缩处理:查看服务器响应头是否包含Content-Encoding: gzip,如果有,需给OkHttp添加Gzip解压拦截器,否则写入的是压缩后的二进制数据,导致格式错误。
  • 修正文件查看Intent:
    • 替换EXTRA_STREAM为data字段传递Uri;
    • 不要使用*/*,通过ContentResolver获取准确的MIME类型,让系统选择正确的应用打开文件:
      private fun getMimeType(file: File): String? {
          return contentResolver.getType(Uri.fromFile(file))
      }
      
  • 确认文件扩展名:检查event.fileName是否包含正确的扩展名(如.jpg、.pdf),无扩展名会导致系统无法识别文件类型。

内容的提问来源于stack exchange,提问作者Nikita Vasko

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.18 01:45:35