【问题标题】:withContext(Dispatchers.IO) infinitely blocking after runningwithContext(Dispatchers.IO) 运行后无限阻塞
【发布时间】:2021-11-04 02:04:41
【问题描述】:

我是协程的新手,我正在尝试从Dispatchers.IO 的内部存储中加载几个文件以及其他一些东西。所以我开始一个协程,然后调用几个挂起函数,每个函数都使用withContext 来读取它的文件。但是在第一个函数中,withContext 运行它的代码并且永远不会返回,所以协程的其余部分永远不会运行。 withContextDispatchers.IO 有什么特别之处吗?

class MainViewModel(
    application: Application
) : AndroidViewModel(application) {


    private val liveSettings: MutableLiveData<Settings>

    suspend fun loadSettings(context: Context): Settings = withContext(Dispatchers.IO) {
        var settings: Settings
        try {
            context.openFileInput(FileManager.settingsDir).use { stream ->
                val jsonData = stream.readBytes().decodeToString()
                settings = Json.decodeFromString(Settings.serializer(), jsonData)
            }
        } catch (e: IOException){
            settings = Settings(mutableListOf(), mutableListOf())
        }
        Log.d("MainViewModel", "Loading Settings")     // this line is run
        settings
    }



    init{
        Log.i("MainViewModel", "ViewModel Constructed")
        liveSettings = MutableLiveData()


        viewModelScope.launch {
            Log.d("MainViewModel", "constructor coroutine started")
            liveSettings.value = loadSettings(getApplication())
            Log.d("MainViewModel", "Hello")            // this line is not run

            // other stuff...

        }
    }
}

我希望输出像

ViewModel Constructed
constructor coroutine started
Loading Settings
Hello

但输出是

ViewModel Constructed
constructor coroutine started
Loading Settings

【问题讨论】:

  • 在您分享的代码中,当您删除withContext 函数调用时,是否会打印“Hello”?
  • 如果我将viewModelScope.launch { 更改为viewModelScope.launch (Dispatchers.Default) { 并且我将我的设置变量移到MutableLiveData 对象之外(显然MutableLiveDatas 不喜欢除了主线程。但我仍然不明白这对内部withContext 有什么影响。普通的.launch{ 是否使协程在主线程上运行?
  • 我看不出你发布的代码有什么问题。我想知道您是否评论了某些内容或删除了您认为不相关但实际上相关的内容。 viewModelScope.launch 默认使用主线程,是的。如上所示,您对withContext 的使用是正确的。其他地方可能有一些代码阻塞了主线程。

标签: android android-studio kotlin kotlin-coroutines


【解决方案1】:

我的猜测是应用程序正在崩溃,而您没有意识到这一点。仔细检查 logcat。 You cannot set a live data value outside the main thread。你应该改用postValue

    viewModelScope.launch {
        Log.d("MainViewModel", "constructor coroutine started")

        // This is launched on an non UI thread - use postValue
        liveSettings.postValue(loadSettings(getApplication()))

        Log.d("MainViewModel", "Hello")            // this line is not run

        // other stuff...

    }

【讨论】:

  • viewModelScope 默认使用 Dispatchers.Main,因此在主线程上调用此代码。 postValue 不应该是必要的。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2023-01-16
  • 2018-03-13
  • 1970-01-01
  • 2011-02-25
  • 2021-02-26
  • 1970-01-01
  • 2018-03-27
相关资源
最近更新 更多