OkHttp SSE Coroutines 模块解读
简介
okhttp-sse-coroutines
是 OkHttp 库的一个扩展模块,它将 Server-Sent Events (SSE) 与 Kotlin 协程 (Coroutines) 进行了集成。这个模块提供了一种更现代、更简洁的方式来处理 SSE 事件流,利用 Kotlin 协程的 Flow 和 Channel API,替代传统的回调方式。
Server-Sent Events (SSE) 是一种基于 HTTP 的单向通信技术,允许服务器向客户端推送实时更新。与 WebSocket 不同,SSE 只支持服务器到客户端的单向通信,但它具有自动重连、事件类型标识等特性,适合于通知、实时更新等场景。
核心 API
Event 类
模块定义了一个 Event
密封类 (sealed class),表示从服务器接收到的 SSE 事件:
kotlin
sealed class Event {
data class Open(val response: Response) : Event()
data class Message(val id: String?, val type: String?, val data: String) : Event()
object Closed : Event()
data class Error(val throwable: Throwable, val response: Response? = null) : Event()
}
- Open: 表示 EventSource 连接已成功打开,包含服务器响应
- Message: 表示接收到服务器发送的消息,包含消息 ID、类型和数据
- Closed: 表示 EventSource 连接已正常关闭
- Error: 表示发生错误,包含异常信息和可能的响应
扩展函数
模块为 EventSources.Factory
提供了三个扩展函数:
1. events(request: Request): Flow
kotlin
fun EventSources.Factory.events(request: Request): Flow<Event>
返回包含所有类型事件的 Flow,包括连接打开、消息接收、连接关闭和错误事件。这是最完整的 API,提供了对 SSE 连接生命周期的全面控制。
2. messages(request: Request): ReceiveChannel<Event.Message>
kotlin
fun EventSources.Factory.messages(request: Request): ReceiveChannel<Event.Message>
返回只包含消息事件的 Channel,过滤掉其他类型的事件,专注于实际数据。这个 API 适合只关心消息内容而不关心连接状态的场景。
3. messageData(request: Request): Flow
kotlin
fun EventSources.Factory.messageData(request: Request): Flow<String>
返回只包含消息数据字符串的 Flow,是最简化的 API,直接获取消息内容。这个 API 适合只需要处理消息数据而不关心元数据的场景。
实现原理
okhttp-sse-coroutines
模块通过将传统的回调式 API 转换为协程式 API 来实现功能。它内部使用了 callbackFlow
和 channelFlow
等协程构建器,将 EventSourceListener
的回调转换为 Flow 或 Channel 的事件发射。
核心实现逻辑包括:
- 创建一个 Flow 或 Channel 来发射事件
- 使用标准的 OkHttp SSE API 创建 EventSource
- 实现 EventSourceListener 接口,将回调事件转发到 Flow 或 Channel
- 处理协程取消,确保在协程取消时关闭 EventSource
- 处理异常情况,确保错误被正确传播
使用示例
1. 接收所有类型的事件
kotlin
val client = OkHttpClient()
val factory = EventSources.createFactory(client)
val request = Request.Builder()
.url("https://example.com/sse-endpoint")
.build()
// 在协程作用域中收集事件
lifecycleScope.launch {
factory.events(request).collect { event ->
when (event) {
is Event.Open -> println("连接已打开: ${event.response.code}")
is Event.Message -> println("收到消息: ${event.data}, 类型: ${event.type}, ID: ${event.id}")
is Event.Closed -> println("连接已关闭")
is Event.Error -> println("发生错误: ${event.throwable.message}")
}
}
}
2. 只接收消息事件
kotlin
lifecycleScope.launch {
val channel = factory.messages(request)
try {
for (message in channel) {
println("收到消息: ${message.data}")
// 处理消息...
}
} finally {
println("Channel 已关闭")
}
}
3. 直接获取消息数据
kotlin
lifecycleScope.launch {
factory.messageData(request).collect { data ->
println("收到数据: $data")
// 处理数据...
}
}
4. 与 Flow 操作符结合使用
kotlin
lifecycleScope.launch {
factory.messageData(request)
.filter { it.contains("important") }
.map { parseJson(it) }
.catch { error -> handleError(error) }
.collect { processData(it) }
}
5. 在 ViewModel 中使用
kotlin
class SseViewModel : ViewModel() {
private val client = OkHttpClient()
private val factory = EventSources.createFactory(client)
private val _messages = MutableStateFlow<List<String>>(emptyList())
val messages: StateFlow<List<String>> = _messages
init {
val request = Request.Builder()
.url("https://example.com/sse-endpoint")
.build()
viewModelScope.launch {
factory.messageData(request)
.catch { error ->
// 处理错误
}
.collect { message ->
_messages.update { currentList -> currentList + message }
}
}
}
}
与标准 SSE 模块的对比
特性 | 标准 SSE 模块 | SSE Coroutines 模块 |
---|---|---|
编程模型 | 回调式 | 协程式 |
异步处理 | 回调函数 | Flow/Channel |
取消操作 | 显式调用 cancel() | 协程取消自动处理 |
错误处理 | 回调函数中处理 | try/catch 或 Flow.catch |
组合操作 | 困难 | 简单(使用 Flow 操作符) |
背压处理 | 无 | 支持(通过 Flow/Channel) |
代码简洁性 | 较冗长 | 简洁 |
标准 SSE 模块示例
kotlin
val client = OkHttpClient()
val request = Request.Builder()
.url("https://example.com/sse-endpoint")
.build()
val factory = EventSources.createFactory(client)
val listener = object : EventSourceListener() {
override fun onOpen(eventSource: EventSource, response: Response) {
println("连接已打开: ${response.code}")
}
override fun onEvent(
eventSource: EventSource,
id: String?,
type: String?,
data: String
) {
println("收到消息: $data, 类型: $type, ID: $id")
}
override fun onClosed(eventSource: EventSource) {
println("连接已关闭")
}
override fun onFailure(eventSource: EventSource, t: Throwable?, response: Response?) {
println("发生错误: ${t?.message}")
}
}
val eventSource = factory.newEventSource(request, listener)
// 稍后需要手动取消
eventSource.cancel()
适用场景
okhttp-sse-coroutines
模块特别适合以下场景:
1. 使用 Kotlin 协程的现代 Android 应用
- 与 ViewModel 和 LiveData/StateFlow 无缝集成
- 利用结构化并发简化生命周期管理
- 与其他协程代码保持一致的编程风格
2. 需要复杂事件处理的应用
- 利用 Flow 操作符进行过滤、转换和组合
- 实现复杂的事件处理逻辑
- 与其他数据源进行组合
3. 需要精细控制资源的场景
- 与协程的取消机制集成,确保资源及时释放
- 避免内存泄漏和网络连接泄漏
- 自动处理连接的生命周期
4. 响应式 UI 更新
- 直接将事件流映射到 UI 状态
- 与 StateFlow 和 SharedFlow 集成
- 实现响应式架构
最佳实践
1. 生命周期管理
确保在适当的协程作用域中启动 SSE 连接,以便在不再需要时自动取消:
kotlin
// 在 Activity/Fragment 中
lifecycleScope.launch {
// 将 SSE 连接限制在视图的生命周期内
lifecycle.repeatOnLifecycle(Lifecycle.State.STARTED) {
factory.events(request).collect { /* 处理事件 */ }
}
}
// 在 ViewModel 中
viewModelScope.launch {
factory.events(request).collect { /* 处理事件 */ }
}
2. 错误处理
使用 Flow 的错误处理机制来处理连接错误:
kotlin
factory.events(request)
.catch { error ->
// 处理错误
emit(Event.Error(error)) // 可选:将错误转换为事件
}
.collect { event ->
// 处理事件
}
3. 重试机制
利用 Flow 的重试操作符实现自动重连:
kotlin
factory.events(request)
.retry(3) { error ->
// 判断是否应该重试
error is IOException && error !is CancellationException
}
.collect { event ->
// 处理事件
}
4. 背压处理
当处理速度跟不上事件产生速度时,考虑使用背压策略:
kotlin
factory.events(request)
.buffer(capacity = 10, onBufferOverflow = BufferOverflow.DROP_OLDEST)
.collect { event ->
// 处理事件
}
总结
okhttp-sse-coroutines
模块通过将 SSE 与 Kotlin 协程集成,提供了一种更现代、更简洁的方式来处理服务器发送的事件。它利用 Kotlin 协程的强大特性,如 Flow 和 Channel,简化了异步编程模型,使得处理实时事件流变得更加直观和高效。
对于使用 Kotlin 开发的现代应用,特别是已经采用协程进行异步操作的应用,这个模块提供了与其他协程代码无缝集成的能力,使得整个代码库更加一致和易于维护。