Firebase和Kotlin合作项目
我有这个静态(伴生对象)函数从Firebase Firestore下载事件信息,并从Firebase Storage下载事件图像:Firebase和Kotlin合作项目,firebase,kotlin,google-cloud-firestore,firebase-storage,Firebase,Kotlin,Google Cloud Firestore,Firebase Storage,我有这个静态(伴生对象)函数从Firebase Firestore下载事件信息,并从Firebase Storage下载事件图像: fun downloadEventInformationAndImages() { FirebaseFirestore.getInstance().collection("events").document(downloadedEventID) .get().addOnSuccessListener { snap -> //Downl
fun downloadEventInformationAndImages() {
FirebaseFirestore.getInstance().collection("events").document(downloadedEventID)
.get().addOnSuccessListener { snap ->
//Download Event Information Here
//Do stuff
GlobalScope.launch(Dispatchers.Main) {
//Download Event Images Here
val downloadEventImage = FirebaseStorage.getInstance().reference.child("Images/Events/$eventID/eventPhoto.jpeg")
.getBytes(1024 * 1024).asDeferred()
val downloadEventFounderImage = FirebaseStorage.getInstance().reference.child("Images/Users/$founderID/profilePhoto.jpeg")
.getBytes(1024 * 1024).asDeferred()
try {
val downloadedImages = mutableListOf<ByteArray>(
downloadEventImage.await(),
downloadEventFounderImage.await())
// Update stuff on UI
} catch(e: StorageException) {
// Error handling
}
}.addOnFailureListener { exception ->
// Error handling
}
}
}
它不起作用(它并没有等到Firebase完成下载——然后我将runBlocking移到函数内部,也不起作用)。如何避免使用GlobalScope?提前感谢。您可以将函数编写为
CoroutineScope
扩展函数:
fun CoroutineScope.downloadEventInformationAndImages() {
...
launch(Dispatchers.Main) {
...
}
并从ViewModel或其他具有范围的地方调用它:
uiScope.downloadEventInformationAndImages()
我在这里看到的最佳选择是将
CoroutineScope
作为下载事件信息和图像的参数传递。那就是
fun downloadEventInformationAndImages(scope: CoroutineScope) {
FirebaseFirestore.getInstance().collection("events").document(downloadedEventID)
.get().addOnSuccessListener { snap ->
//Download Event Information Here
//Do stuff
scope.launch(Dispatchers.Main) { ... }
}
}
需要注意的一点是,您在这里启动的每个协同路由现在都是在您传入的范围内启动的,这意味着如果它失败或被取消,它还将取消任何父协同路由。要了解如何处理此问题,您应该查看文档中的。另一方面,您还可以使用SupervisorJob
(在上面的文档链接中提到)构建您的CoroutineScope
,其中子coroutines失败而不影响父级。最后,当拥有它的对象的生命周期结束时,清理CoroutineScope
也是一种很好的做法。这将避免可能的内存泄漏。可以使用scope.cancel()
或scope.coroutineContext.cancelChildren()
完成清理。第一个终止作用域的作业(传播到所有子作业),第二个只取消可能存在的任何子作业。我建议你花一些时间阅读关于协同程序的文章甚至文档,因为有很多细微差别:)你不能把一个与调用方生命周期相关的CoroutineScope
作为下载事件信息和图像的参数传递给调用方吗?嘿@ricardsteiocora!它是有效的-我很惊讶答案是这么简单-谢谢!:)由于我是Kotlin和Coroutines的新手,在将CoroutineScope作为参数(如内存泄漏等)传递时,有什么特别的事情需要注意吗?很高兴它起了作用:)我会在几分钟后写一个更详细的答案。你好,Andrei!非常感谢你的回答。因为我是Kotlin和Coroutines的新手,所以我无法实现您的答案(我认为我应该这样做)。但是里卡多在第一篇博文的评论中提出的方法对我来说是有效的。再次感谢你的回答。你好,梅廷。没问题:)扩展是非常有用的Kotlin特性。如果你想了解科特林,你总有一天会读到这篇文章的
fun downloadEventInformationAndImages(scope: CoroutineScope) {
FirebaseFirestore.getInstance().collection("events").document(downloadedEventID)
.get().addOnSuccessListener { snap ->
//Download Event Information Here
//Do stuff
scope.launch(Dispatchers.Main) { ... }
}
}