我正在尝试从数据存储中填充值。我只想从数据存储中恢复这些值一次,这就是为什么我在1秒后取消作业的原因。这可以防止它不断更新。
这是行不通的。(1)
suspend fun setupDataStore(context: Context) {
tempDataStore = TempDataStore(context)
val job = Job()
val scope = CoroutineScope(job + Dispatchers.IO)
scope.launch {
tempDataStore.getDieOne.collect {
die1.value = it!!.toInt()
}
tempDataStore.getDisplayText.collect {
displayText.value = it!!
}
tempDataStore.getDieTwo.collect {
die2.value = it!!.toInt()
}
}
delay(1000L)
job.cancel()
}
这是行不通的。(2)
suspend fun setupDataStore(context: Context) {
tempDataStore = TempDataStore(context)
val job = Job()
val scope = CoroutineScope(job + Dispatchers.IO)
scope.launch {
tempDataStore.getDieOne.collect {
die1.value = it!!.toInt()
}
}
scope.launch {
tempDataStore.getDisplayText.collect {
displayText.value = it!!
}
}
scope.launch {
tempDataStore.getDieTwo.collect {
die2.value = it!!.toInt()
}
}
delay(1000L)
job.cancel()
}
这是有效的!(3)
suspend fun setupDataStore(context: Context) {
tempDataStore = TempDataStore(context)
val job = Job()
val job2 = Job()
val job3 = Job()
val scope = CoroutineScope(job + Dispatchers.IO)
val scope2 = CoroutineScope(job2 + Dispatchers.IO)
val scope3 = CoroutineScope(job3 + Dispatchers.IO)
scope.launch {
tempDataStore.getDieOne.collect {
die1.value = it!!.toInt()
}
}
scope2.launch {
tempDataStore.getDisplayText.collect {
displayText.value = it!!
}
}
scope3.launch {
tempDataStore.getDieTwo.collect {
die2.value = it!!.toInt()
}
}
delay(1000L)
job.cancel()
job2.cancel()
job3.cancel()
}
下面是TempDataStore类(4)
class TempDataStore(private val context: Context) {
companion object{
private val Context.dataStore by preferencesDataStore(name = "TempDataStore")
val DISPLAY_TEXT_KEY = stringPreferencesKey("display_text")
val DIE_ONE = stringPreferencesKey("die_one")
val DIE_TWO = stringPreferencesKey("die_two")
}
val getDisplayText: Flow<String?> = context.dataStore.data
.map { preferences ->
preferences[DISPLAY_TEXT_KEY] ?: "Roll to start!"
}
suspend fun saveDisplayText(text: String) {
context.dataStore.edit { preferences ->
preferences[DISPLAY_TEXT_KEY] = text
}
}
val getDieOne: Flow<String?> = context.dataStore.data
.map { preferences ->
preferences[DIE_ONE] ?: "1"
}
suspend fun saveDieOne(dieOne: Int) {
context.dataStore.edit { preferences ->
preferences[DIE_ONE] = dieOne.toString()
}
}
val getDieTwo: Flow<String?> = context.dataStore.data
.map { preferences ->
preferences[DIE_TWO] ?: "2"
}
suspend fun saveDieTwo(dieTwo: Int) {
context.dataStore.edit { preferences ->
preferences[DIE_TWO] = dieTwo.toString()
}
}
suspend fun resetDataStore() {
context.dataStore.edit { preferences ->
preferences.clear()
}
}
}
它是从可组合屏幕中调用的。
LaunchedEffect(true) {
sharedViewModel.setRoles()
sharedViewModel.saveChanges()
sharedViewModel.setupDataStore(context)
}
我希望(1)能起作用。它应该同时运行所有的值,并相应地返回结果。它不填充所有的值,而是只填充第一个名为(3)的值。它起作用,但我想了解为什么它起作用,而不是(1)和(2)。
2条答案
按热度按时间mznpcxlj1#
Calling
collect
on a Flow suspends the coroutine until the Flow completes, but a Flow from DataStore never completes because it monitors for changes forever. So your first call tocollect
prevents the other code in your coroutine from ever being reached.I'm not exactly why your second and third attempts aren't working, but they are extremely hacky anyway, delaying and cancelling as a means to avoid collecting forever.
Before continuing, I think you should remove the nullability from your Flow types:
should be
since you are mapping to a non-nullable value anyway.
I don't know exactly what you're attempting, but I guess it is some initial setup in which you don't need to repeatedly update from the changing values in the Flows, so you only need the first value of each flow. You can use the first value to get that. Since these are pulling from the same data store, there's not really any reason to try to do it in parallel. So your function is pretty simple:
kknvjkwl2#
如果只需要第一个值,为什么不使用Flow的.first()方法呢?这样就不需要那些新的作用域了!
尝试以下操作:
**编辑:**谢谢Tenfour 04的评论!你是对的。我已经修复了我的代码。