社交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
相关产品推荐
相关产品推荐

