[英]Wait for Preferences Datastore to retrieve data from preferences datastore in workmanager
[英]How do I wait until data from Preferences DataStore is loaded?
我正在尝试制作 LibGDX 动态壁纸。 但我认为这与我目前遇到的问题无关。 基本上,我将墙纸的设置存储在 Preferences DataStore 中。 现在,如果您需要从 DataStore 检索数据,则需要检索 Kotlin Flow
并使用它来获取首选项。 在 LibGDX 的ApplicationListener
的onCreate()
方法中,我需要创建一个 KtxScreen object。我决定将所有首选项传递到我的Screen
的构造函数中。 但是,由于Flow
的数据只能在协程内获取,因此我无法使用用户首选项作为构造函数参数来构造我的KtxScreen
object,因为我需要等到我的Flow
发出值。 我用一段非常非常脏的while (userPreferences == null) Unit
代码解决了这个问题,它基本上阻止了整个应用程序,直到发出首选项,这样我才能构建我的KtxScreen
。 解决这个问题的好方法是什么?
在 libGDX 中阻塞渲染线程是可以接受的。 这是一个独立于 Android 主线程的线程,因此它不会冻结 Android UI 或让您面临 ANR(应用程序未响应错误)的风险。 它会在阻塞时冻结任何游戏/墙纸渲染,但是当您仍在加载场景时这没关系。
所以,在create()
或render()
中使用runBlocking
来等待第一批设置是可以接受的。 由于 KtxScreen 不使用create()
,您可以直接在属性初始化时阻塞。 您可以在 Flow 上调用first()
以仅从中获取一个项目,这对于 KtxScreen class 的初始设置来说很好。
如果您使用的是 libKtx 中的ktx-async
库,您可以在渲染线程上收集您的流程,这样如果用户在您的墙纸运行时更新设置,它会安全地更新您的设置。
这是您如何实现这一目标的一个示例(我没有测试它),但是有许多可接受的不同方式可以处理它。 注意:这是假设您在渲染线程而不是 Android 主线程上实例化此屏幕。 渲染线程用于在您的游戏 class 上调用create()
,这是实例化您的第一个屏幕的典型位置。
class MyScreen(
val settingsFlow: Flow<UserPreferences>
): KtxScreen {
var prefs: UserPreferences = runBlocking { settingsFlow.first() }
init {
settingsFlow
.drop(1) // the first one should be the value we already got above
// unless the user changed them impossibly fast
.onEach { prefs = it }
.launchIn(KtxAsync)
}
//...
}
如果你想在你的壁纸中显示某种初始加载图像,你可以像这样在你的render
function 中使用 if/else。 但我不认为这是必要的,因为偏好可能需要不到半秒的时间来加载。
class MyScreen(
val settingsFlow: Flow<UserPreferences>
): KtxScreen {
var _prefs: UserPreferences? = null
init {
settingsFlow
.onEach { _prefs = it }
.launchIn(KtxAsync)
}
override fun render() {
val prefs = _prefs // for the sake of smart-casting
if (prefs == null) {
renderLoadingImage()
} else {
renderScene(prefs)
}
}
//...
private fun renderScene(prefs: UserPreferences) {
//...
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.