简体   繁体   中英

How to modify variables outside of their scope in kotlin?

I understand that in Kotlin there is no such thing as "Non-local variables" or "Global Variables" I am looking for a way to modify variables in another "Scope" in Kotlin by using the function below:

class Listres(){
var listsize = 0
fun gatherlistresult(){
    

    var listallinfo = FirebaseStorage.getInstance()
                                     .getReference()
                                     .child("MainTimeline/")
                                     .listAll()
    listallinfo.addOnSuccessListener {
        listResult -> listsize += listResult.items.size
    }
                
    
}
}

the value of listsize is always 0 (logging the result from inside of the .addOnSuccessListener scope returns 8) so clearly the listsize variable isn't being modified. I have seen many different posts about this topic on other sites, but none fit my usecase.

I simply want to modify listsize inside of the .addOnSuccessListener callback

This method will always be returned 0 as the addOnSuccessListener() listener will be invoked after the method execution completed. The addOnSuccessListener() is a callback method for asynchronous operation and you will get the value if it gives success only.

You can get the value by changing the code as below:

class Demo {

 fun registerListResult() {
     var listallinfo = FirebaseStorage.getInstance()
                                     .getReference()
                                     .child("MainTimeline/")
                                     .listAll()
    listallinfo.addOnSuccessListener {
        listResult -> listsize += listResult.items.size
        processResult(listsize)
    }
    listallinfo.addOnFailureListener {
        // Uh-oh, an error occurred!
     }
 }

 fun processResult(listsize: Int) {
    print(listResult+"") // you will get the 8 here as you said
 }
}

What you're looking for is a way to bridge some asynchronous processing into a synchronous context. If possible it's usually better (in my opinion) to stick to one model (sync or async) throughout your code base.

That being said, sometimes these circumstances are out of our control. One approach I've used in similar situations involves introducing a BlockingQueue as a data pipe to transfer data from the async context to the sync context. In your case, that might look something like this:

class Demo {
  var listSize = 0

  fun registerListResult() {
    val listAll = FirebaseStorage.getInstance()
        .getReference()
        .child("MainTimeline/")
        .listAll()

    val dataQueue = ArrayBlockingQueue<Int>(1)

    listAll.addOnSuccessListener { dataQueue.put(it.items.size) }

    listSize = dataQueue.take()
  }
}

The key points are:

  • there is a blocking variant of the Queue interface that will be used to pipe data from the async context (listener) into the sync context (calling code)
  • data is put() on the queue within the OnSuccessListener
  • the calling code invokes the queue's take() method, which will cause that thread to block until a value is available

If that doesn't work for you, hopefully it will at least inspire some new thoughts!

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM