【问题标题】:Output order display wrong输出顺序显示错误
【发布时间】:2019-09-02 06:03:33
【问题描述】:

我遇到了一个非常奇怪的问题。我在FragemtA 中有一个哈希表列表(groupList)。每次运行fragmentA,都要调用checkUser函数,最后在forEach那里得到返回值显示。

    var id = ""

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
            super.onViewCreated(view, savedInstanceState)

            val userId = checkUser()

            activity.groupedList.forEach {
                for (i in it.value) {
                    Log.d(TAG, "user id in groupedList" + userId)
                }
        }

fun checkUser(): String {
        GlobalScope.launch(Dispatchers.Main) {
            val response = WebApi.getOrganizationsList(activity)
            if (response?.status == "success") {
                id = response?.user_id.toString()
                Log.d(TAG,"id in checkUser "+id)
            } else {
                longToast("FAIL")
            }
        }
        return id
    }

为什么我会得到这个输出?

D/xxx: user id in groupedList
D/xxx: user id in groupedList
D/xxx: id in checkUser 46

我希望id in checkUser 46 首先显示,但不是!

期望的输出

D/xxx: id in checkUser 46
D/xxx: user id in groupedList 46
D/xxx: user id in groupedList 46

【问题讨论】:

  • 在这种情况下你会阻塞 UI 线程,对吧?
  • @Blackbelt 你的意思是checkUser 函数?
  • 正确的那个。
  • @Blackbelt 我该如何解决?我需要使用协程从服务器获取 id
  • 什么意思?您已经使用协程获取 id

标签: android kotlin retrofit coroutine


【解决方案1】:

首先,您的协程不需要返回字符串,因为您已经将其结果保存在属性 id 中。

其次,您期望的第一个消息是最后一个消息,因为您正在启动的协程在循环之后完成执行 - 到 forEach 循环运行时,协程还没有完成然而。您必须记住,您的代码不会按顺序执行,因为您没有等待协程完成。

一旦您确定 ID 值已成功检索,一种选择是在协程内执行您的操作(即 forEach 循环):

fun checkUser() {
    GlobalScope.launch(Dispatchers.Main) {
        val response = WebApi.getOrganizationsList(activity)
        if (response?.status == "success") {
            id = response?.user_id.toString()
            Log.d(TAG,"id in checkUser "+id)
            activity.groupedList.forEach {
                for (i in it.value) {
                    Log.d(TAG, "user id in groupedList" + id)
                }
            }
        } else {
            longToast("FAIL")
        }
    }
}

【讨论】:

    【解决方案2】:

    您正在启动一个线程,但没有等待它完成。将其更改为等待,您会没事的。顺便说一句,通常不鼓励使用 GlobalScope。您应该考虑在您的类上实现 CoroutineScope,以便您可以简单地使用关键字“launch”。

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
            super.onViewCreated(view, savedInstanceState)
    
            GlobalScope.launch {
                val userId = checkUser()
    
                activity.groupedList.forEach {
                    for (i in it.value) {
                        Log.d(TAG, "user id in groupedList" + userId)
                    }
            }
        }
    
    suspend fun checkUser(): String = suspendCoroutine { c->
            GlobalScope.launch(Dispatchers.Main) {
                var id = ""
                val response = WebApi.getOrganizationsList(activity)
                if (response?.status == "success") {
                    id = response?.user_id.toString()
                    Log.d(TAG,"id in checkUser "+id)
                } else {
                    longToast("FAIL")
                }
                c.resume(id)
            }
        }
    

    【讨论】:

    • 没问题,很乐意提供帮助,但就像我提到的,考虑离开 GlobalScope,这为发生内存泄漏留下了空间。
    猜你喜欢
    • 2015-03-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-08-26
    • 2019-12-17
    • 1970-01-01
    相关资源
    最近更新 更多