1

At 'urichecking2' log, I can see there is value. But in 'uriChecking' the uriList is null. why the uriList.add not work??

private fun getPhotoList() {
        val fileName = intent.getStringExtra("fileName")

        Log.d("fileNameChecking", "$fileName")

        val listRef = FirebaseStorage.getInstance().reference.child("image").child(fileName!!)
        var tmpUrl:Uri = Uri.parse(fileName)
        Log.d("firstTmpUri","$tmpUrl")

        listRef.listAll()
            .addOnSuccessListener { listResult ->
                for (item in listResult.items) {
                    item.downloadUrl.addOnCompleteListener { task ->
                        if (task.isSuccessful) {
                            tmpUrl = task.result
                            Log.d("secondTmpUri","$tmpUrl")
                            Log.d("urichecking2","$task.result")
                            uriList.add(task.result)
                        } else {
                        }
                    }.addOnFailureListener {
                        // Uh-oh, an error occurred!
                    }
                }
            }
        Log.d("thirdTmpUri","$tmpUrl")
        Log.d("urichecking", "$uriList")
    }

If I do this, the log is output in the order of first, third, and second, and the desired value is in second, but when third comes out, it returns to the value of first.

Joffrey
  • 32,348
  • 6
  • 68
  • 100
minhyeok
  • 11
  • 2
  • What makes you certain that uriList is null? If the list would be nullable, Kotlin would not allow you to add something without checking for null first. – thinkgruen Dec 06 '22 at 16:39
  • I printed the list through the log, and the value came out like this []. The list is "private val uriList = arrayListOf()" <- this – minhyeok Dec 06 '22 at 16:46
  • Ah, thanks for clarifying. If you want to log the actual results of the `task.result`, you need to wrap it entirely in curly braces: `${task.result}`. In your case `task` can be something that gets logged, but `task.result` might not exist. Can you retry with the curly braces? Right now you log `$task` and then add the String `".result"` at the end. Edit: okay, seems the post got updated with this change in mind already. hope it's still useful. – thinkgruen Dec 06 '22 at 16:50
  • Where is the urichecking2 log? – leonardkraemer Dec 06 '22 at 16:51

1 Answers1

2

The listAll method (like most cloud APIs these days, including downloadUrl which you also use) is asynchronous, since it needs to make a call to the server - which may take time. This means the code executes in a different order than you may expect, which is easiest to see if you add some logging:

Log.d("Firebase","Before starting listAll")

listRef.listAll()
    .addOnSuccessListener { listResult ->
        Log.d("Firebase","Got listResult")
    }
Log.d("Firebase","After starting listAll")

When you run this code it outputs:

Before starting listAll
After starting listAll
Got listResult

This is probably not the order you expected, but it perfectly explains why you can't see the list result. By the time your Log.d("urichecking", "$uriList") runs, none of the uriList.add(task.result) has been called yet.


The solution for this is always the same: any code that needs the list result, has to be inside the addOnCompleteListener callback, be called from there, or be otherwise synchronized.

So in its simplest way:

listRef.listAll()
    .addOnSuccessListener { listResult ->
        for (item in listResult.items) {
            item.downloadUrl.addOnCompleteListener { task ->
                if (task.isSuccessful) {
                    uriList.add(task.result)
                    Log.d("urichecking", "$uriList")
                }
            }
        }
    }

This is an incredibly common mistake to make if you're new to programming with asynchronous APIs, so I recommend checking out

Frank van Puffelen
  • 565,676
  • 79
  • 828
  • 807
  • One more link about the general case: [Why does my function that calls an API or launches a coroutine return an empty or null value?](https://stackoverflow.com/questions/57330766/why-does-my-function-that-calls-an-api-or-launches-a-coroutine-return-an-empty-o) – Tenfour04 Dec 06 '22 at 17:29
  • 1
    Thanks @Tenfour04! I was looking for a link like that, but got distracted by the Kotlin language guide. :) I added the link to my answer. – Frank van Puffelen Dec 06 '22 at 17:35