繁体   English   中英

如何以干净简单的方式将数据从 ViewModel 获取到 Activity 或 Fragment?

[英]How can I get data from ViewModel to Activity or Fragment in clean and simple way?

我有一个问题......有时,我需要直接从 ViewModel 获取数据。 例如,假设 ViewModel 中有一个isChecked()方法。 我想在 if 条件下使用它。

if(viewModel.isChecked()){
    // TODO:
}

所以,我现在正在做的是:

fun isChecked(): Boolean = runBlocking {
    val result = dbRepo.getData()
    val response = apiRepo.check(result)
    return response.isSuccessful
}

它使用 runBlocking。 因此,它在 MainThread 上运行。 我认为这不是一个好方法,因为它可以冻结屏幕。 但是是的,如果条件需要运行,它需要等待它从数据库和网络获取数据。

我能想到的另一种方法是使用 LiveData。 但是,我不能在这种情况下使用它。 所以,我需要在观察者块中移动条件。 但有时,这不能完成,因为条件之前可能有一些东西。 它看起来并不直接,而是在这里和那里编写代码并最终获得该数据。

那么,还有比这更简单的方法吗?

使用lifecyclescope.launch(Dispatcher.IO) 而不是runblocking

如果您有类似的异步操作,最好的选择是重新考虑如何完全使用数据。 不要尝试返回它,而是使用 LiveData 或回调来异步处理响应,而不会导致 UI 挂起或变得滞后。

回调获取 state

如果没有关于如何使用isChecked()的更多详细信息,很难确定最适合您的解决方案是什么,但是一种可行的模式是使用回调来处理您以前放入 if 语句中的内容,就像这样(在视图模型中):

fun getCheckedState(callback: (Boolean)->Unit) {
    viewModelScope.launch {
        // do long-running task to get checked state,
        // using an appropriate dispatcher if needed
        val result = dbRepo.getData()
        val response = apiRepo.check(result)

        // pass "response.isSuccessful" to the callback, to be
        // used as "isChecked" below
        callback(response.isSuccessful)
    }
}

您可以像这样从活动或片段中调用它:

viewModel.getCheckedState { isChecked ->
  if( isChecked ) {
    // do something
  }
  else {
    // do something else
  }
}

// CAUTION: Do NOT try to use variables you set inside 
// the callback out here!

请注意- 您传递给getCheckedState的回调中的代码不会立即运行。 不要尝试在回调 scope 之外使用你在里面设置的东西,否则你会陷入这个常见问题

更简单的回调

或者,如果你只想在isChecked为真时运行一些代码,你可以像这样简化回调

fun runIfChecked(callback: ()->Unit) {
    viewModelScope.launch {
        // do long-running task to get checked state,
        // using an appropriate dispatcher if needed
        val result = dbRepo.getData()
        val response = apiRepo.check(result)

        // pass "response.isSuccessful" to the callback, to be
        // used as "isChecked" below
        if( response.isSuccessful ) {
            callback()
        }
    }
}

并调用它

viewModel.runIfChecked {
  // do something
}

// Again, don't try to use things from the callback out here!

在您的 ViewModel class 上尝试以下代码:

suspend fun isChecked(): Boolean {
    val response: Response? = null
    val job = viewModelScope.launch(Dispatchers.IO) {
        response = dbRepo.getData()
    }
    job.join()
    return response.isSuccessful
}

从活动:

viewModel.viewModelScope.launch(Dispatchers.IO) {
    if (viewModel.isChecked()) {
        // Do your staff
    }
}

希望它工作文件。 如果没有让我评论

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM