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

f0brbegy  于 2022-11-13  发布在  Android
关注(0)|答案(3)|浏览(319)

我有一个问题......有时候,我需要直接从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上运行。我不认为这是一个好方法,因为它会冻结屏幕。但是是的,如果条件需要运行,它需要等待,直到它从DB和网络获得数据。
我想到的另一种方法是使用LiveData。但是,我不能在条件中使用它。所以,我需要在观察者块中移动条件。但是,有时候,这无法做到,因为在条件之前可能有一些东西。而且看起来不直接,而是到处写代码,最后得到数据。
那么,还有比这更简单的方法吗?

xjreopfe

xjreopfe1#

如果遇到这样的问题,最好的办法是重新考虑如何使用数据。不要试图返回数据,而是使用LiveData或回调来异步处理响应,而不会导致UI挂起或变得滞后。在这些情况下,你实际上只有三种选择:
1.使用回调来处理接收响应的时间
1.使用LiveData等可观察数据来处理何时收到响应
1.将方法更改为suspend函数并从协程调用它
强制方法等待主线程返回而不使用其中一个方法导致应用程序挂起。

回调以获取状态

如果没有关于如何使用isChecked()的更多细节,很难说哪种解决方案最适合您,但一种可行的模式是使用回调来处理您之前在if语句中输入的内容,如下所示(在ViewModel中):

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

您可以从Activity或片段中调用它,如下所示:

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的回调中的代码不会立即运行。不要尝试在回调范围之外使用您在其中设置的内容,否则您将陷入此常见问题
    更简单的回拨

或者,如果您只想在isChecked为true时运行某些代码,则可以将回调简化为

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)

        // only call the callback when it's true
        if( response.isSuccessful ) {
            callback()
        }
    }
}

并调用它

viewModel.runIfChecked {
  // do something
}

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

ezykj2lf2#

使用生命周期scope.launch(Dispatcher.IO)而不是运行阻塞

7kqas0il

7kqas0il3#

在ViewModel类上尝试以下代码:

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

起始活动:

// Suppose you have a button
findViewById<Button>(R.id.btn).setOnClickListener({
    CoroutineScope(Dispatchers.Main).launch {
        if (viewModel.isChecked()) {
            Log.d("CT", "Do your others staff")
        }
    }
})

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

相关问题