【问题标题】:How to get String as a return value from "GlobalScope.launch" block如何从“GlobalScope.launch”块获取字符串作为返回值
【发布时间】:2021-08-11 02:04:27
【问题描述】:

在这个应用程序中,我使用 HttpURLConnection 下载 Feed RSS“来自 XML 链接”,然后对其进行解析并查看到 listview,但是在我运行应用程序后,我得到了空的 listview

代码

 private fun downloadXML(urlPath: String? ): String {
        val xmlResult = StringBuilder()

        GlobalScope.launch(Dispatchers.IO) {
         kotlin.runCatching {
             try {
                 Log.d(TAG,"Dispatchers.IO Called")
                 val url = URL(urlPath)
                 val connection: HttpURLConnection = url.openConnection() as HttpURLConnection
                 val responseCode = connection.responseCode
                 Log.d(TAG, "DownloadXML: the response code is $responseCode")
                 connection.inputStream.buffered().reader().use { xmlResult.append(it.readText()) }
                 Log.e(TAG,"xmlResult: is ${xmlResult}")
             }catch (ex:Exception){
                 when(ex){
                     is MalformedURLException -> ex.message.toString()
                     is IOException -> ex.message.toString()
                     is SecurityException -> ex.message.toString()
                     else -> ex.message.toString()
                 }
             }
         }

        }
         Log.e(TAG,xmlResult.toString()) //====> THIS CODEDOES NOT EXECUTED
        return xmlResult.toString() // AND THIS
    }

并像这样使用它

 private var feedURL:String = "http://ax.itunes.apple.com/WebObjects/MZStoreServices.woa/ws/RSS/topfreeapplications/limit=10/xml"
    private var feedLimit = 10
    private var feedCashedURL = "INVALIDAED"
    private val STATE_URL = "feedURL"
    private val STATE_LIMIT = "feedLimit"
    private val parseApplication = ParseApplication()


    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = ActivityMainBinding.inflate(layoutInflater)
        setContentView(binding.root)


        downloadURL(feedURL.format(feedLimit))

        val feedAdapter = FeedAdapter(this,R.layout.list_record,parseApplication.application)
        binding.listView.adapter = feedAdapter

        Log.d(TAG,"onCreate called")

    }
    private fun downloadURL(feedURL: String) {

        if(feedURL != feedCashedURL){
            Log.d(TAG, "download URL starting AsyncTask")
            val rssFeed = downloadXML(feedURL)
            parseApplication.parse(rssFeed)
            feedCashedURL = feedURL
            Log.d(TAG, "downloadURL done")
        }else{
            Log.d(TAG, "downloadURL URL not changed")
        }


    }

看起来这两行没有执行,因为即使我得到响应代码 200 和 xmlResult 打印但仅在 GlobalScope.launch 块内,我在结果中什么也没得到,所以如何从 Coroutine 块获取这个返回结果?

 Log.e(TAG,xmlResult.toString())
        return xmlResult.toString()

【问题讨论】:

    标签: android kotlin networking return kotlin-coroutines


    【解决方案1】:

    这两行正在执行,但不是按照您想象的顺序。 GlobalScope.launch() 启动异步操作,它不等待它完成,所以return xmlResult.toString() 可能在xmlResult.append() 之前执行。

    我假设您试图避免阻塞主/UI 线程。但是请注意,您的downloadURL() 仍然设计为需要等待资源下载才能成功返回。而且因为这个方法是从 UI 线程调用的,所以你无法避免阻塞这个线程。

    要解决这个问题,您需要将整个资源加载过程移到异步操作中。这意味着:downloadXML()downloadURL() 甚至向适配器提供数据。只需删除您当前的GlobalScope.launch(),然后在onCreate() 中执行以下操作:

          GlobalScope.launch(Dispatchers.IO) {
    
                val rssFeed = async { downloadXML(feedURL) }
                parseApplication.parse(rssFeed.await())
    
                withContext(Dispatchers.Main){
                    val feedAdapter = FeedAdapter(this@MainActivity, R.layout.list_record, parseApplication.application)
                    binding.listView.adapter = feedAdapter
                }
    
            }
    

    我想这可能不是一个完全有效的示例,因为您可能需要在馈送适配器时跳回 UI 线程。另外,我认为不推荐使用GlobalScope,但我对Android不是很了解,所以我不会提出更好的解决方案。

    【讨论】:

    • 谢谢你,我明白了,请让我用工作代码更新你的答案,我刚刚使用withContext(Dispatchers.Main) 更新用户界面
    • 您不应该在 IO 调度程序中启动它,也不应该使用 async-await。而是在 Main 中启动,使用 withContext(IO) { downloadXML() },然后使用结果更新 GUI。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-08-04
    • 1970-01-01
    • 2013-11-17
    • 2014-05-27
    • 2020-11-28
    • 2022-11-30
    相关资源
    最近更新 更多