gpt4 book ai didi

java - 如何在函数内修改var值?

转载 作者:行者123 更新时间:2023-12-02 01:22:58 25 4
gpt4 key购买 nike

我想设置一个名为userName的变量,该变量应在ValueEventListener中获取一个新值。但是,在函数中设置新值时,它不会更改。输出仍然是“”

private fun getName(){

var userName = ""
val user = fbAuth.currentUser
var uid = user!!.uid

mDatabase = FirebaseDatabase.getInstance().getReference("users")

mDatabase.addValueEventListener(object : ValueEventListener {
override fun onCancelled(p0: DatabaseError) {
TODO("not implemented")
}
override fun onDataChange(snapshot: DataSnapshot) {
userName = snapshot.child(uid).child("name").getValue().toString()
}
})

println(userName)


}


预期输出:John(孩子的名字),
当前输出:“”

最佳答案

侦听器是异步的,如果将println语句放在username =行下面,则它将打印。

实际上,继续执行此操作;观察时间戳;哪个先打印?空的还是回调内部的一个?

var正在被回调修改,但println会在Firebase发出其值之前很久(在计算机时间内)首先执行。

另外,我会反转mDatabase行的顺序。
您本质上是在请求一个值,然后监听结果。结果可能已经发出。您应该先添加侦听器,然后请求数据。

更新:如果我需要另一个回调的值怎么办?

欢迎来到异步编程的世界:-)

您描述的是一组独立的异步操作。您需要值A和值B,但是只有获得值A才能获得值B。两者都是异步的,需要时间,但是您在主线程上没有时间,或者,您有〜16ms计算,测量和绘制屏幕,​​以便操作系统可以保持每秒60帧的速度。这不是很多时间,而是异步编程存在的部分原因!

This other answer已经提供了您所需的工作样本。 This other external link有一个更具体的Observer Listener模式示例。

简而言之,您想要的是一个对象的实例,该对象的实例可在操作完成后立即调用。

在常规的同步函数中,每个语句都在另一个语句之后执行,直到上一个语句没有完成才执行任何语句。因此,所有语句都是阻塞语句。

例如:

var times = 2
var message = "Hello"
var world = "World"
println("The message is $message $times")
println(world)


将打印:

The message is Hello 2
World


这是因为执行点将从一行移到另一行,等待上一行执行。如果一个操作花费时间,则该线程将被阻塞(无法执行其他任何操作),直到该操作完成并且执行点可以移至下一条指令为止。

可以想象,iOS和Android(以及Windows,macOS,Linux等)中的主线程无法被阻止,或者OS无法响应您的触摸和其他事件(例如,在手机,如果用户界面没有响应,并且您无法点击“答案”,则无法处理来电。

这就是为什么我们使用其他“线程”来卸载速度不是很快的事情的原因。随之而来的是思维方式的改变以及正确的计划,因为事情现在变得更加复杂。

让我们看一个简单的示例(一些伪代码,因此要承担任何明显的明显错误,这只是为了说明要点,而不是编写解决方案)。

fun main() {
var hello = "Hello"
var message = thisTakesTime()
println("The message is $hello $message")
println(hello)
}

fun thisTakesTime(): String {
// do something that takes 1 second (1000 ms)
Thread.sleep(1000)
return "World"
}


这将打印

The message is Hello World
Hello


如您所见,除了一整秒的时间里,主线程没有响应,其他都没有改变。例如,如果要在Android上运行此程序,它将运行,但是在Thread.sleep期间,您的应用程序将在一秒钟内不响应。一秒钟很快,请尝试10秒钟;在确定需要ANR(应用程序无响应)对话框之前,这超出了Android操作系统5秒的限制,主线程无法响应。这就是臭名昭著的“看来XXX应用程序没有响应,正在等待或关闭”。

你能做什么?

最初,如果您有太多的回调(在回调B完成之前无法执行回调A,而在回调C完成之前无法执行回调B),然后像这样开始嵌套它们,则最终会导致臭名昭著的 Callback-Hell(在Javascript中) ,但对任何语言/平台均有效)。

基本上跟踪所有这些异步回调,并确保在响应到来时,下一个回调已准备好,以此类推,这很痛苦,而且如果例如在中间回调C失败,则会引入指数复杂性,现在您必须让回调B知道C失败,因此它也必须失败,这又必须让回调A(原始!)知道B失败,因此A必须对此做点什么,A是否需要知道B因为C失败了吗?还是A仅只关心B和B,而B失败的原因无关紧要?

好了,正如您所看到的,即使谈论这一点也变得复杂和混乱,我什至没有涵盖同样复杂的其他可能情况。

我在这里要说的不是您不应该使用回调。这是您必须仔细计划在何时何地使用它们。

Kotlin通过使用 Coroutines可以减少/删除回调地狱,但是这些是一个比较高级的主题,它还要求对组件和零件的设计方式进行根本性的更改。

总而言之,对于您的用例,请记住OOP的黄金法则:制作很少做的小具体类,并且做得很好。如果您需要在各处开始添加太多的 if (),那么您很可能在各地混合使用业务逻辑,随机决策和“关于”情况。

假设您有一个处理位置数据并将其上载到服务器的类。

您可能会想:


在Activity / Fragment(或ViewModel)中编写所有代码;很快变得一团糟。
使用静态方法(或单例模式)创建LocationUtils;一团糟,但也很难测试和嘲笑。如果您需要多个处理类型怎么办?或者,如果要将它们存储在数据库中,又要添加更多静态方法呢?
创建一个小的LocationProcessor类,该类接收两个点(经/纬度),通过一个小函数进行处理,并返回处理后的数据,然后创建另一个名为LocationUploader的类,该类接收来自Processor的干净输入并将其上载到服务器。这些类都不应该考虑“如果我没有权限,如果用户关闭位置该怎么办”,等等。这些问题超出了打算处理位置坐标的类的职责范围,别无其他。应该有其他类负责。请记住,小类,小责任==减少了在单个文件中的麻烦。


结论?

好了,这时有更好的答案,可以为您提供所要查找内容的复制粘贴版本;我相信您今天必须从这堵墙中删除的概念是,为了编写现代,可测试且简单的功能代码,必须改变计划方式。

长话短说:当事物不同步时,您需要保持某个事物(一个对象)随时可以被调用(因此称为回调),监听(或观察)(因此我们称其为监听者或观察者),发出事物(通常称为Observable,因为它可以被“观察”)。

祝好运!

关于java - 如何在函数内修改var值?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57365403/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com