【问题标题】:Using Global Variables with Coroutines in Android在 Android 中将全局变量与协程一起使用
【发布时间】:2019-12-06 10:07:05
【问题描述】:

我在下面的代码中启动了一个协程来处理数据的检索并将它们存储到本地数据库中:

private var lastRequestedPage = 1
private var isRequestInProgress = false
private val viewModelScope = CoroutineScope(viewModelJob + Dispatchers.Main)

// function that is called from several places
private fun requestAndSaveData(){
    if(isRequestInProgress) return

    isRequestInProgress = true
    viewModelScope.launch{
        withContext(Dispatchers.IO){
            // 2 heavyweight operations here:
            // retrieve some data via Retrofit & place it into the local data via Room Persistence Library
        }
    }

    lastRequestedPage++
    isRequestInProgress = false
}

代码sn-p说明

网络调用和数据库操作是基于一个名为isRequestInProgress 的布尔值完成的。当它为假时,它被设置为真,网络和数据库操作可以由协程启动,然后lastRequestedPage增加,然后我们再次将isRequestInProgress设置为假,这样整个过程就可以通过来自任何地方的程序。 请注意,lastRequestedPage 作为参数传递给 Retrofit 网络调用函数,因为数据来自的 Web 服务使用分页(为简洁起见,我省略了它)。

我的问题

我可以假设这个逻辑适用于这样的协程吗?我可以用这样的解决方案遇到一些不好的线程问题吗?我之所以问是因为我对协程的概念不熟悉,并且我正在从我的另一个项目中调整此逻辑,在该项目中,我使用了带有 Retrofit 的侦听器和回调来执行异步工作(每当调用 Retrofit#onResponse 方法时,我都会增加 lastRequestedPage 变量并设置isRequestInProgress 回到 false)。

【问题讨论】:

    标签: android asynchronous kotlin kotlin-coroutines


    【解决方案1】:

    简短回答:不,这行不通。这是不正确的。

    当你调用viewModelScope.launch { }GlobalScope.launch { } 时,launch 内的块被暂停。然后程序流转到下一条语句。

    在您的情况下,viewModelScope.launch { } 将暂停对withContext(...) 的调用并继续执行lastRequestedPage++ 语句。

    它会在实际开始请求之前立即增加lastRequestedPage 和切换isRequestInProgress 标志。

    您要做的是将这些语句移动到 launch { } 块内。

    这就是流程的工作方式。

    • 主线程
    • 暂停块(启动调用)
    • 继续 - 不要关心暂停的块 - 进行 UI 更改等。

    要更好地了解它的工作原理,请尝试此代码。

        Log.d("cor", "Hello, world!") // Main thread
        GlobalScope.launch {
            // Suspend this block. Wait for Main thread to be available
            Log.d("cor", "I am inside the launch block") // Main thread
            withContext(Dispatchers.IO) {
                delay(100L) // IO thread
                Log.d("cor", "I am inside the io block") // IO thread
            }
            Log.d("cor", "IO work is done") // Back to main thread
        }
        Log.d("cor", "I am outside the launch block") // Main thread
    

    输出是

    D/cor: Hello, world!
    D/cor: I am outside the launch block
    D/cor: I am inside the launch block
    D/cor: I am inside the io block
    D/cor: IO work is done
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-10-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-11-16
      相关资源
      最近更新 更多