【问题标题】:kotlin syntax with Deferred带有 Deferred 的 kotlin 语法
【发布时间】:2020-09-16 05:24:57
【问题描述】:

我的目标是获得符合此签名 Deferred<HashMap<Long, String>?> 的输出,或者可能更好的类似 Job 等。不确定在 kotlin 中做事的标准方式以及如何调用/使用该函数,是我是新手。

以下是我在模型层中使用的草稿。如果有人能告诉我做异步事情的正确方法,我将不胜感激。

fun findAll(): Deferred<HashMap<Long, String>?> {
    GlobalScope.launch(Dispatchers.IO) {

        async {
            var roles: HashMap<Long, String>? = null
            connection.readableDatabase.query("role", null, null, null, null, null, null).use { cursor ->
                if (cursor.count > 0) roles = HashMap()
                while (cursor.moveToNext()) {
                    roles?.put(cursor.getLong(cursor.getColumnIndex("id")), cursor.getString(cursor.getColumnIndex("name")))
                }
            }
            return roles
        }

    }

}

【问题讨论】:

    标签: android kotlin kotlin-coroutines


    【解决方案1】:

    首先,我不会使用 GlobalScope,因为它“存在”应用程序生命周期时间,并且在应用程序被杀死之前它不会被清除。因此,您可以使用 MVVM 模式并在 viewModel 中使用 viewModelScope 并使用默认调度程序启动协程。在你的 ViewModel 类似:

     fun loadQuestions(type: String) {
            viewModelScope.launch {
                questionsUseCase.invoke(type).fold(::handleError, ::handleUsersResponse)
            }
        }
    
     override fun onCleared() {
            super.onCleared()
            viewModelScope.cancel()
        }
    

    简而言之,您将业务逻辑放在 ViewModel 中,从 ui(activity,fragment) 调用该函数。这个调用函数是一个挂起函数,您可以使用它来代替 Deferred!

    您可以阅读更多内容:https://medium.com/androiddevelopers/coroutines-on-android-part-i-getting-the-background-3e0e54d20bb

    【讨论】:

      【解决方案2】:

      使用withContextasync 构建器的一种方法。 GlobalScope 不推荐使用。 async 将返回一个 Deferred&lt;HashMap&lt;Long, String&gt;?&gt;,而您只对数据感兴趣。 async 在您同时进行多个后台调用的情况下很有用我看不到async 在您的情况下有用。所以基本上你可以做的是让findAll成为一个挂起函数并从一个范围内调用它并直接返回你感兴趣的数据。

      suspend fun findAll(): HashMap<Long, String>? {
           return withContext(Dispatchers.IO) {
                  var roles: HashMap<Long, String>? = null
                  connection.readableDatabase.query("role", null, null, null, null, null, null).use { cursor ->
                      if (cursor.count > 0) roles = HashMap()
                      while (cursor.moveToNext()) {
                          roles?.put(cursor.getLong(cursor.getColumnIndex("id")), cursor.getString(cursor.getColumnIndex("name")))
                      }
                  }
               roles
           }
      }
      

      现在您可以通过CoroutineScope 调用它。如果您在 MVVM 上,您可以在 ViewModel 内使用viewModelScope

       viewModelScope.launch {
          val data = repo.findAll()
      }
      

      如果没有,那么您可以创建一个自定义 Ui 范围并直接从范围中调用它。

      private val uiScope = CoroutineScope(Dispatchers.Main)
      fun getData(){
         uiScope.launch {
             val data = repo.findAll()
         }
       }
      

      【讨论】:

      • 谢谢,附带问题,我可以在主线程上调用挂起函数吗,我假设它不会阻塞 UI 线程?
      • 您可以从任何线程调用suspend,重要的是Dispatchers,正如您在上面看到的suspend fun findAll() 本身在Dispatchers.IO 上被调用,因此您可以直接从Scope 调用。如果需要,您还可以将调度程序设置为launch builder,例如launch(Dispatchers.IO)
      • 感谢您的回答。我很感激。您能否也尝试一下这个问题。 stackoverflow.com/questions/63948153/… 因为两者都是相关的。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2019-04-24
      • 2017-12-01
      • 1970-01-01
      • 2013-02-02
      • 1970-01-01
      • 2019-03-12
      • 2011-01-09
      相关资源
      最近更新 更多