在Android中将全局变量与协程一起使用

时间:2019-12-06 10:07:05

标签: android asynchronous kotlin kotlin-coroutines

我有以下代码,在其中我启动一个协程以处理数据的检索并将其存储到本地数据库中:

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
}

代码段的描述

网络调用和数据库操作基于名为isRequestInProgress的布尔值完成。如果设置为false,则将其设置为true,协程可以启动网络和数据库操作,然后在将lastRequestedPage再次设置为false之前递增isRequestInProgress,以便整个过程可以可以从任何地方再次由程序启动。 请注意,lastRequestedPage作为参数传递给Retrofit网络调用函数,因为数据所来自的Web服务使用了分页(为简洁起见,我省略了它)。

我的问题

我可以假定这种逻辑可以与这样的协程一起工作吗?这样的解决方案可以解决一些不好的线程问题吗?我之所以问是因为我对协程的概念不熟悉,因此我从另一个我的项目中改编了此逻辑,在该项目中,我使用了带有Retrofit的侦听器和回调来执行异步工作(每当Retrofit#onResponse方法被称为我递增{{1} }变量,并将lastRequestedPage设置为false)。

1 个答案:

答案 0 :(得分: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