【问题标题】:How to modify variables outside of their scope in kotlin?如何在 kotlin 中修改其范围之外的变量?
【发布时间】:2020-08-05 08:08:41
【问题描述】:

我知道在 Kotlin 中没有“非局部变量”或“全局变量”之类的东西,我正在寻找一种方法来使用以下函数在 Kotlin 的另一个“作用域”中修改变量:

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

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

listsize 的值始终为 0(从 .addOnSuccessListener 范围内记录结果返回 8),因此很明显 listsize 变量没有被修改。我在其他网站上看到过很多关于这个主题的不同帖子,但没有一个适合我的用例。

我只是想在.addOnSuccessListener 回调中修改listsize

【问题讨论】:

    标签: variables kotlin scope


    【解决方案1】:

    此方法将始终返回 0,因为在方法执行完成后将调用 addOnSuccessListener() 侦听器。 addOnSuccessListener()asynchronous 操作的回调方法,只有成功才会得到值。

    您可以通过更改以下代码来获取值:

    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
     }
    }
    

    【讨论】:

    • 处理时可能会出错。更新了答案。也添加了addOnFailureListener() callback。请您通过调试达到内部错误
    • 我们可以进一步讨论,但这并不能解决我的问题,请记住我们使用的是 kotlin。在 processresult 函数中访问 listResult 不起作用
    • 处理结果函数内部没有定义列表结果,所以无法打印值。
    • 并且想法是将列表大小更改为 listResult.items.size 的值,这在本示例中也不起作用。
    • 通过将变量传递给处理结果函数来更新答案
    【解决方案2】:

    您正在寻找一种将一些异步处理桥接到同步上下文中的方法。如果可能,最好(在我看来)在整个代码库中坚持一个模型(同步或异步)。

    话虽如此,有时这些情况是我们无法控制的。我在类似情况下使用的一种方法是引入BlockingQueue 作为数据管道,将数据从异步上下文传输到同步上下文。在你的情况下,这可能看起来像这样:

    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()
      }
    }
    

    重点是:

    • Queue 接口的阻塞变体将用于将数据从异步上下文(侦听器)传送到同步上下文(调用代码)
    • 数据是put()OnSuccessListener 内的队列中
    • 调用代码调用队列的take() 方法,这将导致该线程阻塞,直到值可用

    如果这对你不起作用,希望它至少能激发一些新的想法!

    【讨论】:

    • 是的。鉴于同步和异步处理的混合,您的选择仅限于阻塞或轮询。这就是我建议尽可能坚持一种范式的原因之一。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-12-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多