【问题标题】:StateFlow Observer is being triggered Two Times - Is this a good solution?StateFlow Observer 被触发两次 - 这是一个好的解决方案吗?
【发布时间】:2021-09-03 17:28:08
【问题描述】:

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

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

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

这是一个好的解决方案,我必须问一下?因为我使用的是协程,所以线程没有被阻塞,我只是在等待 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()
        }
    }
}

【问题讨论】:

    标签: android kotlin android-room android-jetpack-compose stateflow


    【解决方案1】:

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

    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)
           }
        }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-11-08
      • 1970-01-01
      • 2012-02-18
      • 2020-02-14
      • 1970-01-01
      相关资源
      最近更新 更多