11. 编写第一个订阅
在本节中,您将使用订阅来接收有关有人预订航班的通知 🚀!订阅 允许您在服务器上的事件发生时实时接收通知。下面是关于全栈后端和它的支持的详细描述...全栈后端 支持基于 WebSockets 的订阅。
编写您的订阅
打开您的 沙盒,点击左下角的模式标签。除了 查询
和 变更
,您还会看到第三种操作类型 订阅,订阅
。单击 订阅 可以看到 tripsBooked
订阅:
该 订阅不需要任何 参数,并返回一个名为 tripsBooked
的单值。由于您可以一次性预订多个行程, tripsBooked
是一个 Int
。它将包含一次预订的行程数,或者如果行程已取消,则为 -1。
单击 tripsBooked
左侧的播放按钮来在浏览器中打开 订阅。打开一个新标签,然后检查 tripsBooked
按钮以将 订阅 添加:
再次,重命名您的订阅以便更容易找到:
点击提交操作按钮,您的订阅将开始监听事件。您可以通过底部左边的面板弹出了解其是否正在运行,那里将接收订阅数据:
测试您的订阅
在资源管理器中打开一个新的标签页。在这个新的标签页中,添加类似于第9步的预订旅行代码,但是使用硬编码的ID:
mutation BookTrip {bookTrips(launchIds: ["93"]){message}}
不要忘记包含身份验证头。在添加操作的下方的沙箱资源管理器面板中,有一个Headers
部分:
点击提交操作按钮。如果一切顺利,那么您已经预订了旅行!在右边面板的顶部,您将看到您BookTrip
的突变的成功JSON,下面是其更新后的JSONTripsBooked
订阅:
继续预订和/或取消旅行,您将在实时看到的订阅面板中收到事件。经过一段时间后,服务器可能会关闭连接,您需要重新启动订阅来继续接收事件。
将订阅添加到项目中
现在您的订阅已工作,将其添加到项目中。在schema.graphqls
和您的其他GraphQL文件旁边创建名为TripsBooked.graphql
的文件,并将订阅的内容粘贴进去。这个过程与您进行的查询和突变操作类似:
subscription TripsBooked {tripsBooked}
配置ApolloClient以使用订阅
本教程使用 subscriptions-transport-ws
协议进行订阅。关于更多选项,如最新的 graphql-ws
或 Appsync,请参见 GraphQL over WebSocket protocols。
在 Apollo.kt
中,为您的 ApolloClient
配置 webSocketServerUrl
:
val apolloClient = ApolloClient.Builder().serverUrl("https://apollo-fullstack-tutorial.herokuapp.com/graphql").webSocketServerUrl("wss://apollo-fullstack-tutorial.herokuapp.com/graphql").okHttpClient(...).build()
wss://
是 WebSocket 协议。
在预订/取消行程时显示 SnackBar
在 MainActivity
中,注册您的订阅并保留返回的协程 Flow 的引用。
使用 collectAsState
获取 Flow 的最新值作为状态。当 Flow 发射值时,它将被存储在 tripBookedResponse
中,并触发 UI 的重新 组合,因为 LaunchedEffect
依赖于它。
RocketReserverTheme {val tripBookedFlow = remember { apolloClient.subscription(TripsBookedSubscription()).toFlow() }val tripBookedResponse: ApolloResponse<TripsBookedSubscription.Data>? by tripBookedFlow.collectAsState(initial = null)LaunchedEffect(tripBookedResponse) {if (tripBookedResponse == null) return@LaunchedEffectval message = when (tripBookedResponse!!.data?.tripsBooked) {null -> "Subscription error"-1 -> "Trip cancelled"else -> "Trip booked! 🚀"}// TODO use the message}
现在让我们在一个 Material SnackBar 中显示消息。
为此,您需要创建一个 SnackbarHostState
并调用它的 showSnackbar
。别忘了将其传递给下面的 Scaffold
:
val snackbarHostState = remember { SnackbarHostState() }val tripBookedFlow = (...)(...)val message = (...)snackbarHostState.showSnackbar(message = message,duration = SnackbarDuration.Short)}Scaffold(topBar = { TopAppBar({ Text(stringResource(R.string.app_name)) }) },snackbarHost = { SnackbarHost(snackbarHostState) },) { paddingValues ->
处理错误
与查询和mutations类似,当连接丢失或发生任何其他协议错误时,订阅将抛出错误。要处理这些情况,您可以配置客户端使用 webSocketReopenWhen
函数重试订阅。返回 true
进行重试,false
停止。为了避免过于频繁的重试,您可以使用 attempt
参数延迟重试:
val apolloClient = ApolloClient.Builder()(...).webSocketReopenWhen { throwable, attempt ->Log.d("Apollo", "WebSocket got disconnected, reopening after a delay", throwable)delay(attempt * 1000)true}
测试您的代码
构建并运行您的应用,然后返回到沙箱资源管理器,并选择设置 BookTrip
变异的标签页。在应用打开时预订新行程,您应该会看到一个 🚀 快速回复栏
教程结束,恭喜! 🎉
更多资源
使用本文档的其余部分了解更多高级主题,如 缓存 或 Gradle 配置。
请通过以下方式提问:在我们的 GitHub 仓库中创建一个问题,加入社区或在 KotlinLang Slack 的频道上停留(在此获取邀请)。
如果您想更深入地了解并查看 GraphQL 在实际应用中的使用,可以查看这些使用 Apollo Kotlin 的开源项目: