微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

StateFlow Observer 被触发两次 - 这是一个好的解决方案吗?

如何解决StateFlow Observer 被触发两次 - 这是一个好的解决方案吗?

好的,所以我一直在使用带有 Room 数据库的 StateFlow。现在我有一个常见的案例。在我的应用程序开始时,我有一个逻辑,如果 ROOM 数据库为空,我应该显示一个 EmptyContent(),否则我将显示 ROOM 数据库中的 ListContent()。

现在每次我启动应用程序时,我总是让 EmptyContent() 显示半秒,然后显示 ListContent()。之后,当我使用该应用程序时,一切正常。但是在那个应用程序启动时,当 ROOM 数据库正在工作时,我猜 EmptyContent() 只显示一小段时间(因为我的 StateFlow 认值是一个空列表),然后显示来自数据库的实际 LIST .

现在我有一个解决方案,只需在协程中使用 delay() 函数,等待例如 200 毫秒,然后触发读取数据库函数,因为那些 200 毫秒足以让 ROOM 数据库实际获取值并使用实际数据更新我的 STATE FLOW 变量,而不是在开始时使用该 StateFlow 认值半秒。

这是一个很好的解决方案吗,我必须问一下?因为我使用的是协程,线程没有被阻塞,我只是在等待 ROOM 数据库第二次更新我的 STATE FLOW 变量。

@Composable
fun displayContent(
    tasks: List<TodoTask>,ListContent: @Composable () -> Unit
) {
    val scope = rememberCoroutinescope()
    var counter by remember { mutableStateOf(0)}
    LaunchedEffect(Unit){
        scope.launch {
            delay(200)
            counter = 1
        }
    }
    if(counter == 1){
        if (tasks.isNotEmpty()) {
            ListContent()
        } else {
            EmptyContent()
        }
    }
}

解决方法

我的建议是映射您的预期状态。 例如:

sealed class RequestState<out T> {

    object Idle : RequestState<Nothing>()

    object Loading : RequestState<Nothing>()

    data class Success<T>(val data: T) : RequestState<T>()
    
    data class Error(
        val t: Throwable,var consumed: Boolean = false
    ) : RequestState<Nothing>()
}

你的函数应该是这样的:

@Composable
fun YourScreen() {
   val requestState = viewModel.screenData.collectAsState()
   when (requestState) {
       is Idle -> 
           // This is the default state,do nothing
       is Loading -> 
           // Display some progress indicator
       is Success ->
           YourListScreen(requestState.data) // Show the list
       is Error ->
           // Display an error.
   }
   LaunchedEffect(Unit) {
      viewModel.loadData()
   }
}

当然,在您的视图模型中,您必须正确地发出这些值...

class YourView: ViewModel() {
    private val _screenData =
        MutableStateFlow<RequestState<List<ToDoTask>>>(RequestState.Idle)
    val screenDatae: StateFlow<RequestState<List<ToDoTask>>> = _screenData

    fun loadData() {
       _screenData.value = Loading
       try {
           // load the data from database
           _screenData.value = Success(yourLoadedData)
       } catch (e: Exception) {
           _screenData.value = Error(e)
       }
    }
}

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。