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

社交APP中用户返回后如何继续Retrofit媒体上传任务?

解决方案:确保媒体上传在页面退出后仍能完成

1. 使用前台服务(Foreground Service)执行上传任务

普通后台线程在Activity/Fragment销毁后,极易被Android系统回收(尤其是内存紧张时)。前台服务拥有更高的系统优先级,会在通知栏显示持续通知,确保上传任务不会被轻易终止。

实现步骤:

  • 创建继承自Service的上传服务类,在onStartCommand中启动上传逻辑
  • 启动服务时必须调用startForeground(),传入通知ID和合规通知(Android 8.0+强制要求,否则会抛出异常)
  • 通过Retrofit发起上传请求,回调中处理成功/失败逻辑,任务完成后停止服务

示例代码片段:

class UploadService : Service() {
    private val retrofit by lazy { Retrofit.Builder().baseUrl(BASE_URL).build() }
    private val apiService by lazy { retrofit.create(ApiService::class.java) }

    override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
        // 构建前台通知
        val notification = NotificationCompat.Builder(this, UPLOAD_CHANNEL_ID)
            .setContentTitle("正在上传媒体")
            .setContentText("请稍候...")
            .setSmallIcon(R.drawable.ic_upload)
            .build()
        
        startForeground(UPLOAD_NOTIFICATION_ID, notification)

        // 获取要上传的文件路径
        val filePath = intent?.getStringExtra("FILE_PATH") ?: return START_NOT_STICKY
        
        // 执行上传
        CoroutineScope(Dispatchers.IO).launch {
            try {
                val file = File(filePath)
                val requestBody = file.asRequestBody("multipart/form-data".toMediaTypeOrNull())
                val part = MultipartBody.Part.createFormData("media", file.name, requestBody)
                
                val response = apiService.uploadMedia(part)
                if (response.isSuccessful) {
                    updateNotification("上传完成")
                } else {
                    updateNotification("上传失败,请重试")
                }
            } catch (e: Exception) {
                updateNotification("上传出错:${e.message}")
            } finally {
                stopForeground(STOP_FOREGROUND_REMOVE)
                stopSelf()
            }
        }

        return START_REDELIVER_INTENT // 服务被杀死后,系统会重新传递Intent
    }

    private fun updateNotification(content: String) {
        val updatedNotification = NotificationCompat.Builder(this, UPLOAD_CHANNEL_ID)
            .setContentTitle("媒体上传")
            .setContentText(content)
            .setSmallIcon(R.drawable.ic_upload)
            .build()
        val notificationManager = getSystemService(NOTIFICATION_SERVICE) as NotificationManager
        notificationManager.notify(UPLOAD_NOTIFICATION_ID, updatedNotification)
    }

    override fun onBind(intent: Intent?): IBinder? = null

    companion object {
        const val UPLOAD_CHANNEL_ID = "upload_channel"
        const val UPLOAD_NOTIFICATION_ID = 1001
        const val BASE_URL = "https://your-server-url.com/"
    }
}

聊天页面启动服务:

val intent = Intent(this, UploadService::class.java).apply {
    putExtra("FILE_PATH", selectedMediaPath)
}
ContextCompat.startForegroundService(this, intent)

2. 使用WorkManager实现可靠的后台上传

如果需要更稳定的任务调度(比如设备重启后继续上传、网络恢复后自动重试),可以使用WorkManager。它会根据系统状态自动管理任务,确保任务最终执行。

实现步骤:

  • 创建继承自Worker的上传Worker类
  • 在doWork()方法中执行Retrofit上传逻辑
  • 在聊天页面通过OneTimeWorkRequest提交任务到WorkManager

示例代码片段:

class UploadWorker(context: Context, params: WorkerParameters) : Worker(context, params) {
    private val retrofit by lazy { Retrofit.Builder().baseUrl(BASE_URL).build() }
    private val apiService by lazy { retrofit.create(ApiService::class.java) }

    override fun doWork(): Result {
        val filePath = inputData.getString("FILE_PATH") ?: return Result.failure()
        
        return try {
            val file = File(filePath)
            val requestBody = file.asRequestBody("multipart/form-data".toMediaTypeOrNull())
            val part = MultipartBody.Part.createFormData("media", file.name, requestBody)
            
            val response = apiService.uploadMedia(part)
            if (response.isSuccessful) {
                Result.success()
            } else {
                Result.retry() // 失败后自动重试
            }
        } catch (e: Exception) {
            Result.retry()
        }
    }

    companion object {
        const val BASE_URL = "https://your-server-url.com/"
    }
}

提交任务:

val uploadRequest = OneTimeWorkRequestBuilder<UploadWorker>()
    .setInputData(workDataOf("FILE_PATH" to selectedMediaPath))
    .setConstraints(Constraints.Builder()
        .setRequiredNetworkType(NetworkType.CONNECTED) // 仅在有网络时执行
        .build())
    .build()

WorkManager.getInstance(this).enqueue(uploadRequest)

3. 额外注意事项

  • Android 12+对后台服务限制更严格,前台服务必须是用户主动触发的场景(比如主动点击上传按钮),否则会被系统阻止
  • 使用WorkManager时,可通过setBackoffCriteria()配置重试间隔,避免频繁重试消耗资源
  • 上传完成后,可通过LiveData、本地广播或EventBus更新聊天页面UI,同步上传状态

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.11 02:03:30