Apollo Kotlin中的查询
以可预测、类型安全的方式获取数据是Apollo Kotlin的核心特性之一。Apollo Kotlin。在本指南中,您将了解如何查询一个GraphQL端点并将结果用于您的应用程序。
先决条件
本页假设您对构建GraphQL查询有一定的了解。为了巩固,我们建议您阅读此指南和练习在Apollo沙盒中运行查询。
因为 Apollo Kotlin 使用标准的 GraphQL 语法,您在沙盒中可以运行的任何查询也可以放入 .graphql
文件中。
此页面还假设您已为您的 Android/Kotlin 应用设置了 Apollo Kotlin。有关设置的帮助,请参阅 入门指南。
定义
在 Apollo Kotlin 中,每个您执行的 查询 都表示为实现了 Query
接口 的类实例。为了生成这些类,我们首先需要定义我们想要执行的 GraphQL 操作。
假设我们定义了一个名为 GraphQL 查询的名为 HeroQuery
,如下所示:
query HeroQuery($id: String!) {hero(id: $id) {idnameappearsIn}}
如果我们将此 查询 放在它自己的 .graphql
文件中, Apollo Kotlin 将生成相应的 HeroQuery
类,我们可以使用它来 执行查询。
为了生成类, Apollo Kotlin 需要您的服务器模式,以及包含您的定义 .graphql
操作的所有 文件。它使用这些文件来生成可以用于执行查询和访问类型化结果的代码。
在您的项目(或您作为输入传递给apollo-codegen
的自定脚本的子集)中的所有.graphql
文件都将合并并作为一个 GraphQL文档处理。这意味着,在一个.graphql
文件中定义的片段在所有所有 .graphql
文件中都是可用的。但是,这也意味着操作和片段的名称必须是唯一的(如果不唯一,将会发生验证错误)。
执行
为了执行我们刚刚定义的查询,我们将一个HeroQuery
实例传入到ApolloClient
的query
方法中,如下所示:
val apolloClient = ApolloClient.Builder().serverUrl("https://your.domain/graphql").build()val response = apolloClient.query(HeroQuery(id = "12")).execute()
默认情况下,Apollo Kotlin将I/O工作卸载到后台线程,这意味着在主线程上启动GraphQL操作是安全的。结果也将被调度到调用线程,并且您可以直接使用响应来更新您的数据。
- 在JVM上,默认使用
Dispatchers.IO
进行I/O工作。您可以使用ApolloClient.Builder.dispatcher
更改此调度程序。 - 在Kotlin/native(iOS、macOS、...)上,请求将缓存和网络I/O卸载到恢复到主调度队列的后台线程。因此,
ApolloClient
API 假设它们是在主线程中调用的。无法自定义调度程序,但缓存和网络I/O始终在后台线程中执行。
结果
一个查询的结果以匹配查询字段结构的不可变类层次结构返回。这些类仅包含在查询中包含的字段(省略其他schema字段)。
换句话说,Apollo Kotlin
根据您编写的查询生成类,而不是根据您查询的模式。
例如,给定以下模式:
enum Episode { NEWHOPE, EMPIRE, JEDI }interface Character {id: String!name: String!friends: [Character]appearsIn: [Episode]!}
以及以下查询:
query HeroAndFriendsNames {hero {namefriends {idname}}}
Apollo Kotlin生成一个看起来这样的类型安全的模型(省略细节以关注类结构):
class HeroAndFriendsNamesQuery {data class Data(val hero: Hero)data class Hero(val name: String, friends: List<Friend>)data class Friend(val id: String, val name: String)}
因为 HeroAndFriendsNames
查询不获取 appearsIn
,所以这个属性不是返回结果类型的一部分,无法在此处访问。同样, id
只在 Friend
中可用,而不是在 Hero
。
因为 GraphQL 支持 null 可用性,你在编译时就有类型安全保护。如果请求成功,所有查询的数据(也只有这些数据)都将可访问。在 UI 代码中不需要处理 null 字段。
取消
操作 取消是通过 CoroutineScope
处理的。取消当前作用域将取消任何相关的当前 操作。