Upload a file to Firebase Storage and get a downloadUrl. How can I return the result in a Kotlin function?

大憨熊 提交于 2021-01-21 05:38:45

问题


I have a function that uploads a local file to Firestore Storage using uploadTask. I followed the instructions given in the docs. Here is my code:

fun uploadAudioFile(file: File){
    val audioFilePathUri = Uri.fromFile(file)
    val ref = currentUserRef.child("audioFiles/" + System.currentTimeMillis() + "." + "m4a")
    val uploadTask = ref.putFile(audioFilePathUri)

    val urlTask =
        uploadTask.continueWithTask(Continuation<UploadTask.TaskSnapshot, Task<Uri>> { task ->
            if (!task.isSuccessful) {
                task.exception?.let {
                    throw it
                }
            }
            return@Continuation ref.downloadUrl
        }).addOnCompleteListener { task ->
            if (task.isSuccessful) {
                val downloadUri = task.result
                Log.d("STORAGE_UTIL", "downloadUri: " + downloadUri)
            } else {
                // Handle failures
            }
        }
}

The function works fine and renders the correct downloadUri.

Now my question: I want to rewrite this function so that it returns that downloadUri. Something like this:

 fun uploadAudioFile(file: File): Uri? {
    val audioFilePathUri = Uri.fromFile(file)
    val ref = currentUserRef.child("audioFiles/" + System.currentTimeMillis() + "." + "m4a")
    val uploadTask = ref.putFile(audioFilePathUri)

    val urlTask =
        uploadTask.continueWithTask(Continuation<UploadTask.TaskSnapshot, Task<Uri>> { task ->
            if (!task.isSuccessful) {
                task.exception?.let {
                    throw it
                }
            }
            return@Continuation ref.downloadUrl
        }).addOnCompleteListener { task ->
            if (task.isSuccessful) {
                val downloadUri = task.result
                Log.d("STORAGE_UTIL", "downloadUri: " + downloadUri)
            } else {
                // Handle failures
            }
        }
    return downloadUri 
}

This gives me a unresolved reference on the return statement's downloadUri. How can I solve this?


回答1:


There is no way you can return your downloadUri as a result of a method and this is because Firebase APIs are asynchronous. This means that onComplete() function returns immediately after it's invoked, and the callback from the Task it returns, will be called some time later. So unfortunately there are no guarantees about how long it will take, it may take from a few hundred milliseconds to a few seconds before that data is available. Because that method returns immediately, the value of your downloadUri variable you're trying to return, will not have been populated from the callback yet.

Basically, you're trying to return a value synchronously from an API that's asynchronous. That's not a good idea. You should handle the APIs asynchronously as intended.

A quick solve for this problem would be to use the value of your downloadUri variable only inside the onComplete() method. Basically, all the logic that exist inside your uploadAudioFile() method should be moved inside the callback. If you want to use that value outside the callback, I recommend you see the last part of my anwser from this post in which I have explained how it can be done using a custom callback.



来源:https://stackoverflow.com/questions/57818573/upload-a-file-to-firebase-storage-and-get-a-downloadurl-how-can-i-return-the-re

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!