Kotlin Coroutines 不直接上传 XML,而是协程化驱动网络请求;需先构建 XML,再用 Retrofit(suspend 函数)或 OkHttp(withContext(Dispatchers.IO))发送,配合 lifecycleScope 或 viewModelScope 管理生命周期,注意 Content-Type、UTF-8 编码及大文件流式上传。

Android XML 异步上传本身不是 Kotlin Coroutines 的典型使用场景——Coroutines 不直接处理 XML 文件上传,而是用来安全、简洁地驱动网络请求(如上传 XML 字符串或 ByteArray)。关键在于:你得先把 XML 构建好,再用 OkHttp、Retrofit 或 HttpClient 发出去,而 Coroutines 负责让这个过程不卡主线程、可取消、结构清晰。
如何用 CoroutineScope.launch 启动一次 XML 上传
这是最直接的启动方式,适合简单上传逻辑(比如点击按钮后发一个 XML 请求)。注意必须绑定生命周期,避免内存泄漏或崩溃。
- 不要在
Activity或Fragment的顶层直接用GlobalScope.launch—— 它不随组件销毁自动取消,容易导致NullPointerException或后台继续执行 - 推荐用
lifecycleScope(Activity/Fragment)或viewModelScope(ViewModel),它们会在组件销毁时自动取消协程 - 上传前建议检查网络状态,否则
IOException会直接抛到协程作用域,需用try/catch捕获
lifecycleScope.launch {
try {
val xmlContent = "Alice "
val response = uploadXmlToServer(xmlContent)
Log.d("Upload", "Success: ${response.code()}")
} catch (e: Exception) {
Log.e("Upload", "Failed", e)
}
}
uploadXmlToServer 应该返回 Deferred 或 suspend 函数
真正发起网络请求的函数必须是挂起函数(suspend),否则无法在协程中自然等待。 Retrofit + suspend 函数是最常见组合;若用 OkHttp,需包装成 withContext(Dispatchers.IO)。
- Retrofit 接口定义要声明
suspend,不能写Call - OkHttp 的
execute()是阻塞调用,必须放在withContext(Dispatchers.IO)中,否则会卡主线程 - 别在
suspend函数里手动切线程(如runBlocking),这会破坏协程调度语义
@POST("api/upload")
suspend fun postXml(@Body xml: RequestBody): Response
上传 XML 时 Content-Type 和编码容易出错
服务端通常要求明确的 Content-Type: application/xml 或 text/xml,且需指定字符编码(如 UTF-8)。Kotlin 字符串默认是 UTF-16,转 RequestBody 时若没指定 charset,OkHttp 可能用 ISO-8859-1,导致中文乱码或解析失败。
- 用
RequestBody.create()时务必传入MediaType.get("application/xml; charset=utf-8") - 若 XML 有声明如
,服务端仍可能忽略它,以 HTTP header 为准 - 测试时可用 Charles 或 Proxyman 抓包,确认请求头中的
Content-Type和实际 body 字节是否匹配
val xmlBody = RequestBody.create(
MediaType.get("application/xml; charset=utf-8"),
xmlContent
)
大 XML 文件上传需考虑流式处理与进度回调
如果 XML 是动态生成的大文件(几 MB 以上),一次性读入内存(File.readText())会触发 OOM。此时应改用流式上传,并通过协程通道(Channel)或回调暴露进度。
- 避免用
File.readBytes()加载整个文件;改用OkHttp的RequestBody子类实现writeTo()流式写入 - 进度监听不能直接在协程中用
delay()模拟,而应在流写入过程中通过channel.send()向 UI 发送进度 -
Dispatchers.IO已优化文件 I/O,但不要在其中做字符串解析或 XML 校验等 CPU 密集操作——这类任务应切到Dispatchers.Default
复杂点在于:XML 本身不带传输进度,进度只能靠已写入字节数 / 总字节数估算;而总字节数又依赖于是否提前知道文件大小(如 File.length())或需先序列化再测量——这两者都可能违背“流式”初衷。实际项目中,更稳妥的做法是把 XML 生成和上传拆成两个阶段,上传阶段只负责稳定流控。










