首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >无法从Coroutine块android中获取数据

无法从Coroutine块android中获取数据
EN

Stack Overflow用户
提问于 2022-11-23 08:16:29
回答 2查看 51关注 0票数 0

存储库实现,其中挂起上传和取回urls的功能。等待()函数说它应该是“暂停”。所以我添加了一个Coroutine范围块。在该块中,已将urls添加到列表中。作用域中的log语句要求在arraylist中下载urls。但是在块之外,列表是空的。如何在coroutine块之外更新列表,谁能帮助我理解如何使用Coroutine (谢谢)?

我的代码

代码语言:javascript
运行
复制
override suspend fun addProductImagesToFirebaseStorage(
    productImages: List<Uri>
): AddProductImagesResponse {

    return try {
        val downloadUrls = mutableListOf<Uri>()

        val tasks = mutableListOf<UploadTask>()
        productImages.forEach { downloadUrl ->
            val task = categoryImageStorage.reference
                .child("Home").child("PP")
                .child("images")
                .putFile(downloadUrl)
            tasks.add(task)
        }

        Tasks.whenAllSuccess<UploadTask.TaskSnapshot>(tasks).addOnSuccessListener { uploadTask ->
            uploadTask.forEach {
         // downloadUrls.add(it.storage.downloadUrl.await()) Error: Suspension functions can be called only within coroutine body
                CoroutineScope(Dispatchers.Default).launch {
                    downloadUrls.add(it.storage.downloadUrl.await())
                    Log.i(TAG,"Inside the block : $downloadUrls")
                }
                Log.i(TAG,"Outside the block : $downloadUrls")
            }

        }

        Success(downloadUrls)

    } catch(e:Exception) {
        Failure(e)
    }
}
EN

回答 2

Stack Overflow用户

发布于 2022-11-23 09:10:20

这是因为可能会首先执行outside日志,因为将线程更改为Dispatchers.DEFAULT所花费的时间比执行下一行所花费的时间要多。

我想说的是,coroutine将启动,在此之后,outside日志将立即打印列表(该列表为空),然后协同工作将在另一个线程(Dispatchers.DEFAULT)上完成,这与主程序执行流程无关。

我的建议是使用MutableLiveDataLiveData,这样您就可以观察,让主程序在列表中装满downloadUrl时做出反应。

以下是关于LiveDataMutableLiveData的更多信息

票数 0
EN

Stack Overflow用户

发布于 2022-11-23 10:50:54

正如ndriqa所述,外部日志记录发生在内部日志记录之前,因为您的协同机制将并行运行,并等待下载完成后再登录。在下载期间,您在coroutine块之外编写的代码继续执行,在下载完成之前,您的downloadUrls仍然是空的。因此,您可以在外部日志中获得空值。

您的目标是确保您的方法addProductImagesToFirebaseStorage在下载完成后返回具有下载值的Success()。因为您的方法是suspend,所以它可以等待一些长时间的操作才能完成(在您的例子中是download.await())。但是,您正在侦听器的方法中调用await(),因此编译器不知道上下文,也不能确定它是从协同线或挂起函数调用的。

只需像这样调用它,以确保创建具有最新值的Success

代码语言:javascript
运行
复制
val tasks = mutableListOf<UploadTask>()
    productImages.forEach { file -> // I renamed downloadUrl to file here to be clearer
        val url = categoryImageStorage.reference // I also renamed task to url since the result will be not a task but a downloaded url
            .child("Home").child("PP")
            .child("images")
            .putFile(file)
            .await() // wait for it to be put
            .storage
            .downloadUrl
            .await() // wait for it to download
        downloadUrls.add(url)
    }
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/74543613

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档