加入我们,于10月8日至10日在纽约市,学习最新关于GraphQL联邦和API平台工程的技巧、趋势和新闻。参加2024年纽约市GraphQL峰会
文档
免费开始
您正在查看此软件旧版本的文档。 切换到最新稳定版本。

Apollo Kotlin中的归一化缓存


提供了两个内置的归一化缓存用于存储和重用GraphQL操作的结果:

  • 一个内存缓存MemoryCache
  • 一个SQLite缓存SqlNormalizedCache

您可以在应用中使用这些缓存中的一个(或两个!)来提高其大多数操作的响应性。

要开始使用更粗粒度且设置更快的缓存策略,请参阅HTTP缓存

归一化缓存是什么?

在一个中,归一化缓存将您的每个GraphQL的响应分解成包含的各个单独对象。然后,每个对象根据其缓存ID作为独立条目进行缓存。这意味着如果多个响应中包含相同的对象,则该对象可以合并为一个缓存条目。这减少了缓存的整体大小,并有助于保持您缓存的日期数据一致且新鲜。

您还可以使用归一化缓存作为您UI的单一流真相,使其能够响应缓存中的更改。要了解更多关于过程的信息,请参阅此博客文章

归一化响应

看看这个例子

query GetFavoriteBook {
favoriteBook { # Book object
id
title
author { # Author object
id
name
}
}
}

查询返回一个Book对象,该对象又包含一个Author对象。从的示例响应如下:

{
"favoriteBook": {
"id": "bk123",
"title": "Les Guerriers du silence",
"author": {
"id": "au456",
"name": "Pierre Bordage"
}
}
}

规范化缓存不会直接存储此响应。相反,它默认将其拆分为以下条目:

缓存
"favoriteBook": {"id": "bk123", "title": "Les guerriers du silence", "author": "ApolloCacheReference{favoriteBook.author}"}
"favoriteBook.author": {"id": "au456", "name": "Pierre Bordage"}
"QUERY_ROOT": {"favoriteBook": "ApolloCacheReference{favoriteBook}"}

⚠️ 这些默认生成的缓存 ID(如 favoriteBookfavoriteBook.author)对于数据去重来说并不理想。请参阅 指定缓存 ID

  • 请注意,author Book ApolloCacheReference{favoriteBook.author}。这是对 Author 缓存条目的引用。
  • 请注意,如果已缓存至少一个查询的结果,则会始终存在 QUERY_ROOT 条目。此条目包含对查询中包含的每个顶层 field 的引用(例如,favoriteBook)。

提供的缓存

内存缓存

Apollo Kotlin 的 MemoryCache 是一个用于存储GraphQL操作对象的规范化内存缓存。要使用它,首先将 apollo-normalized-cache 软件包添加到您的 build.gradle[.kts] 文件中的依赖项中:

build.gradle[.kts]
dependencies {
implementation("com.apollographql.apollo3:apollo-normalized-cache:3.8.5")
}

然后,像这样在您的 ApolloClient 初始化中包含缓存:

// Creates a 10MB MemoryCacheFactory
val cacheFactory = MemoryCacheFactory(maxSizeBytes = 10 * 1024 * 1024)
// Build the ApolloClient
val apolloClient = ApolloClient.Builder()
.serverUrl("https://...")
// normalizedCache() is an extension function on ApolloClient.Builder
.normalizedCache(cacheFactory)
.build()

由于标准化缓存是可选的,normalizedCache() 是定义在 apollo-normalized-cache 模块中的 ApolloClient.Builder() 的一个扩展函数。它接受一个 NormalizedCacheFactory 参数,以便在需要时可以在主线程之外创建缓存。

一个 MemoryCache 是一个最近最少使用(LRU)缓存。它根据以下条件在内存中保持条目:

名称描述
maxSizeBytes缓存的最高大小,以字节为单位。
expireAfterMillis存在缓存条目的超时时间,以毫秒为单位。默认情况下,无超时。

当您的应用停止时,MemoryCache 中的数据将永远丢失。如果您需要持久化数据,可以使用 SQLite 缓存

SQLite 缓存

Apollo Kotlin 的 SQLite 缓存使用 SQLDelight 来持久化存储数据。您可以使用它来跨应用重启持久化数据,或者当缓存数据过大无法放入内存时。

要启用 SQLite 缓存支持,将 apollo-normalized-cache-sqlite 依赖项添加到您的项目 build.gradle 文件中:

build.gradle.kts
dependencies {
implementation("com.apollographql.apollo3:apollo-normalized-cache-sqlite:3.8.5")
}

然后根据您的平台目标(不同平台使用不同的驱动程序)将 SQLite 缓存包含在您的 ApolloClient 初始化中:

// Android
val sqlNormalizedCacheFactory = SqlNormalizedCacheFactory("apollo.db")
// JVM
val sqlNormalizedCacheFactory = SqlNormalizedCacheFactory("jdbc:sqlite:apollo.db")
// iOS
val sqlNormalizedCacheFactory = SqlNormalizedCacheFactory("apollo.db")
// Build the ApolloClient
val apolloClient = ApolloClient.Builder()
.serverUrl("https://...")
.normalizedCache(sqlNormalizedCacheFactory)
.build()

然后您可以使用 SQLite 缓存,就像使用 MemoryCache 一样。

链式缓存

为了最大限度地发挥标准化缓存的优势,您可以将 MemoryCacheFactorySqlNormalizedCacheFactory 链接起来:

val memoryFirstThenSqlCacheFactory = MemoryCacheFactory(10 * 1024 * 1024)
.chain(SqlNormalizedCacheFactory(context, "db_name"))

每当 Apollo Kotlin 尝试读取缓存数据时,它会按顺序检查每一个链式缓存直到遇到匹配项。然后它会立即返回那些缓存数据,而不读取任何额外的缓存。

每当 Apollo Kotlin 将数据写入缓存时,那些写入会沿着链式缓存逐级传播。

设置获取策略

在将标准化缓存添加到您的 ApolloClient 初始化后,Apollo Kotlin 自动使用 FetchPolicy.CacheFirst 作为所有查询的默认(客户端全局)获取策略。要更改默认设置,可以在客户端构建器上调用 fetchPolicy

val apolloClient = ApolloClient.Builder()
.serverUrl("https://...")
.fetchPolicy(FetchPolicy.NetworkOnly)
.build()

您还可以为特定的查询自定义缓存的使用方式,通过设置该查询的获取策略。

以下代码片段展示了如何设置所有可用的获取策略及其行为

val response = apolloClient.query(query)
// (Default) Check the cache, then only use the network if data isn't present
.fetchPolicy(FetchPolicy.CacheFirst)
// Check the cache and never use the network, even if data isn't present
.fetchPolicy(FetchPolicy.CacheOnly)
// Always use the network, then check the cache if network fails
.fetchPolicy(FetchPolicy.NetworkFirst)
// Always use the network and never check the cache, even if network fails
.fetchPolicy(FetchPolicy.NetworkOnly)
// Execute the query
.execute()

CacheAndNetwork 策略可以产生多个值,所以您应该使用 toFlow() 而不是 execute()

apolloClient.query(query)
// Check the cache and also use the network (1 or 2 values can be emitted)
.fetchPolicy(FetchPolicy.CacheAndNetwork)
// Execute the query and collect the responses
.toFlow().collect { response ->
// ...
}

指定缓存 ID

query GetFavoriteBook {
favoriteBook { # Book object
id
title
author { # Author object
id
name
}
}
}
缓存
"favoriteBook": {"id": "bk123", "title": "Les guerriers du silence", "author": "ApolloCacheReference{favoriteBook.author}"}
"favoriteBook.author": {"id": "au456", "name": "Pierre Bordage"}
"QUERY_ROOT": {"favoriteBook": "ApolloCacheReference{favoriteBook}"}

query AuthorById($id: String!) {
author(id: $id) {
id
name
}
}
}

缓存
"favoriteBook": {"id": "bk123", "title": "Les guerriers du silence", "author": "ApolloCacheReference{favoriteBook.author}"}
"favoriteBook.author": {"id": "au456", "name": "Pierre Bordage"}
"author(\"id\": \"au456\")": {"id": "au456", "name": "Pierre Bordage"}
"QUERY_ROOT": {"favoriteBook": "ApolloCacheReference{favoriteBook}", "author(\"id\": \"au456\")": "ApolloCacheReference{author(\"id\": \"au456\")}"}

  • 占用的空间更多。

缓存
"Book:bk123": {"id": "bk123", "title": "Les guerriers du silence", "author": "ApolloCacheReference{Author:au456}"}
"Author:au456": {"id": "au456", "name": "Pierre Bordage"}
"QUERY_ROOT": {"favoriteBook": "ApolloCacheReference(Book:bk123)", "author(\"id\": \"au456\")": "ApolloCacheReference{Author:au456}"}

方法

有两种方法可用于指定对象的缓存 ID

上一页
简介
下一页
声明性缓存 ID
评分文章评分在GitHub上编辑编辑论坛Discord

©2024Apache Graph Inc.,以Apache GraphQL的名义。

隐私政策

公司