跳到主要内容

处理丢失的渲染上下文(Handling a lost render context)

渲染上下文是 Rive worker 用来渲染的 GPU 设备(Vulkan)或 GPU 上下文(OpenGL)。GPU 驱动重置或失败时,它可能丢失。之后,该 worker 上的 Rive 实例会停止更新。worker 不会自行恢复,因此应用需要替换它。

检测丢失的渲染上下文(Detecting a lost render context)​

从 v11.16.0 起,可以用 RiveWorker.renderContextStatus 检测丢失的渲染上下文。这个 StateFlow 一开始是 RenderContextStatus.Ready,当 Rive 检测到丢失时变为 RenderContextStatus.Lost。它不会再变回去。

Rive 在 worker 下一次绘制时检测丢失,并在 worker 被轮询时更新状态。生命周期处于 resumed 时,rememberRiveWorker 和 rememberRiveWorkerOrNull 默认会为你轮询 worker。如果你自己创建 RiveWorker,需要调用 beginPolling。

Ready 只表示 Rive 还没有检测到丢失。它不表示 worker 上的每个操作都会成功,因此仍要处理 Rive API 可能抛出的错误。Rive 也可能漏掉某些丢失,例如第一次出现在它所绘制的 surface 正在创建或调整大小时的丢失。

用新的 worker 恢复(Recovering with a new worker)​

要恢复,请创建一个新的 worker,并在上面重新加载内容。如果你用 RiveWorker 构造函数创建 worker,请自己释放丢失的 worker。同时关闭你在没有 remember 函数的情况下从它加载的任何东西,例如文件和图像。旧 worker 只有在被释放、且从它加载的一切都已关闭之后才会关闭。

在 Compose 中恢复(Recovering in Compose)​

参见 Compose 渲染上下文恢复示例,其中由 Android ViewModel 持有 worker。

你可以把 worker 以及从它加载的一切放进一个 key 块,并在状态变为 Lost 时更改这个 key。key 变化时,Compose 会销毁该块。其中的 remember 函数会关闭它们加载的内容并释放旧 worker。然后该块会用新的 worker 再次运行。

创建新 worker 可能失败,因此下面的示例使用 rememberRiveWorkerOrNull。它返回 null 而不是抛出异常,这样你可以显示后备界面。

setContent {
var workerGeneration by remember { mutableIntStateOf(0) }
key(workerGeneration) {
val errorState = remember { mutableStateOf<Throwable?>(null) }
val riveWorker = rememberRiveWorkerOrNull(errorState)
if (riveWorker == null) {
// Show a fallback. Changing workerGeneration tries again.
ErrorMessage(errorState.value)
} else {
LaunchedEffect(riveWorker) {
// Waits until the worker loses its render context.
riveWorker.renderContextStatus.first { it == RenderContextStatus.Lost }
workerGeneration++
}

val riveFile = rememberRiveFile(
RiveFileSource.RawRes.from(R.raw.my_rive_file),
riveWorker
)
when (riveFile) {
is Result.Loading -> LoadingIndicator()
is Result.Error -> /* Handle the error */
is Result.Success -> Rive(riveFile.value)
}
}
}
}

用 RiveCanvasSession 恢复(Recovering with RiveCanvasSession)​

实验性的 RiveCanvasSession 在丢失后会停止推进和渲染,但 beginPlaying 在你关闭会话或取消其协程之前不会返回。请自己观察 renderContextStatus,然后关闭会话以及你加载的内容,并在新的 worker 上重新创建它们。参见 Canvas 渲染上下文恢复示例。

重新加载资源(Loading assets again)​

嵌入 Rive 文件中的资源会随文件再次加载。你自己加载的图像、字体和音频只能在加载它们的那个 worker 上使用,因此要在新的 worker 上重新加载。保留它们的字节,或准备好再次下载。

恢复状态(Restoring state)​

新 worker 上的一切都从初始状态开始。状态机从入口状态开始,新的视图模型实例具有初始值。如果你的应用更改过视图模型属性,请在新的视图模型实例上再次设置它们。再次设置只会在状态机的过渡使用这些属性时改变其状态。

看完还有疑问?进群交流下!
与众多 Rive 创作者、开发者一起交流探讨与答疑解惑。
加入交流群