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

三星Galaxy Watch4录音文件上传AWS S3失败的代码修改咨询

解决AWS S3上传时的JobCancellationException问题

核心原因分析

kotlinx.coroutines.JobCancellationException 本质是上传过程中协程被提前终止,常见触发场景:

  • 协程作用域与生命周期绑定过紧(比如用viewModelScope但页面销毁,或手表应用后台被系统回收)
  • 文件读取/网络请求未做超时处理
  • 录音完成后未正确关闭文件流,导致上传时文件无法读取
  • AWS SDK调用未在IO调度器执行,阻塞主线程引发协程取消

针对性修改方案

1. 选择独立的协程作用域

避免使用与UI生命周期强绑定的作用域,改用不受页面销毁影响的独立作用域:

private val uploadScope = CoroutineScope(Dispatchers.IO + SupervisorJob())

2. 确保录音文件可正常读取

录音结束后必须关闭相关流,上传前校验文件有效性:

// 录音完成后的收尾操作
private fun finishRecording() {
    recorder?.stop()
    recorder?.release()
    outputStream?.flush()
    outputStream?.close() // 必须关闭输出流,否则文件可能处于锁定状态
}

// 上传前校验文件
private fun isValidRecordingFile(file: File): Boolean {
    return file.exists() && file.canRead() && file.length() > 0
}

3. 修改uploadFile函数,增加超时与异常处理

给上传任务添加超时限制,捕获取消异常并补充必要的错误处理:

fun uploadToS3(file: File, bucketName: String, s3Key: String) {
    uploadScope.launch {
        try {
            withTimeout(30000) { // 30秒超时限制
                if (!isValidRecordingFile(file)) {
                    throw IllegalArgumentException("录音文件无效或不可读")
                }

                // 初始化S3客户端(建议用Cognito身份池,避免硬编码密钥)
                val s3Client = AmazonS3ClientBuilder.standard()
                    .withRegion(Regions.AP_SOUTHEAST_1) // 替换为你的存储桶区域
                    .build()

                val putRequest = PutObjectRequest(bucketName, s3Key, file)
                    .withCannedAcl(CannedAccessControlList.Private)

                // 执行上传
                s3Client.putObject(putRequest)
                // 上传成功后的逻辑:比如通知用户、删除本地文件
            }
        } catch (e: TimeoutCancellationException) {
            Log.e("S3Upload", "上传超时", e)
        } catch (e: JobCancellationException) {
            Log.e("S3Upload", "上传任务被取消", e)
            // 可选:添加重试逻辑
        } catch (e: Exception) {
            Log.e("S3Upload", "上传失败", e)
        }
    }
}

4. 适配手表后台运行限制

Galaxy Watch4的Wear OS对后台任务有严格限制,需启动前台服务确保上传不被系统终止:

private fun startUploadForeground() {
    val notification = NotificationCompat.Builder(this, "UPLOAD_CHANNEL")
        .setContentTitle("正在上传录音")
        .setSmallIcon(R.drawable.ic_upload)
        .build()
    
    startForeground(1, notification)
}

在uploadToS3函数开头调用此方法,上传完成后调用stopForeground(true)关闭前台服务。

5. 依赖库版本兼容检查

确保AWS SDK与协程版本匹配,建议使用稳定版:

// AWS S3 SDK
implementation 'com.amazonaws:aws-android-sdk-s3:2.74.0'
// Kotlin协程
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.3'

关键注意事项

  • 避免硬编码AWS密钥,建议使用Cognito身份池进行身份验证
  • 录音文件存储路径选择getExternalFilesDir(Environment.DIRECTORY_MUSIC),确保应用有权限访问
  • 测试时保持手表网络稳定,避免上传过程中断网

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.02 04:10:36