- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我对 Java 没有太多经验。我不确定这个问题是否愚蠢,但我需要从 Firebase 实时数据库获取用户名并返回此名称作为此方法的结果。所以,我想出了如何获取这个值,但我不明白如何返回它作为这个方法的结果。最好的方法是什么?
private String getUserName(String uid) {
databaseReference.child(String.format("users/%s/name", uid))
.addListenerForSingleValueEvent(new ValueEventListener() {
@Override
public void onDataChange(DataSnapshot dataSnapshot) {
// How to return this value?
dataSnapshot.getValue(String.class);
}
@Override
public void onCancelled(DatabaseError databaseError) {}
});
}
最佳答案
这是异步 Web API 的一个典型问题。您现在无法退回尚未加载的内容。换句话说,您不能简单地创建一个全局变量并在 onDataChange()
方法之外使用它,因为它始终为 null
。发生这种情况是因为 onDataChange()
方法被异步调用。根据您的连接速度和状态,可能需要几百毫秒到几秒的时间才能获得数据。
不仅 Firebase 实时数据库会异步加载数据,而且几乎所有现代 Web API 也会异步加载数据,因为这可能需要一些时间。因此,您的主应用程序代码会在辅助线程上加载数据时继续执行,而不是等待数据(这可能会导致用户的应用程序对话框无响应)。然后,当数据可用时,将调用 onDataChange() 方法,并且可以使用该数据。换句话说,当调用 onDataChange()
方法时,您的数据尚未加载。
让我们举个例子,在代码中放置一些日志语句,以便更清楚地了解发生了什么。
private String getUserName(String uid) {
Log.d("TAG", "Before attaching the listener!");
databaseReference.child(String.format("users/%s/name", uid)).addListenerForSingleValueEvent(new ValueEventListener() {
@Override
public void onDataChange(DataSnapshot dataSnapshot) {
// How to return this value?
dataSnapshot.getValue(String.class);
Log.d("TAG", "Inside onDataChange() method!");
}
@Override
public void onCancelled(DatabaseError databaseError) {}
});
Log.d("TAG", "After attaching the listener!");
}
如果我们运行这段代码,输出将是:
Before attaching the listener!
After attaching the listener!
Inside onDataChange() method!
这可能不是您所期望的,但它准确地解释了为什么您的数据在返回时为 null
。
大多数开发人员的最初 react 是尝试“修复”此异步行为
,我个人建议不要这样做。网络是异步的,您越早接受这一点,就能越早学习如何利用现代 Web API 提高工作效率。
我发现重新构建这种异步范例的问题是最简单的。我没有说“首先获取数据,然后记录它”,而是将问题描述为“开始获取数据。加载数据后,记录它”。这意味着任何需要数据的代码都必须位于 onDataChange()
方法内部或从内部调用,如下所示:
databaseReference.child(String.format("users/%s/name", uid)).addListenerForSingleValueEvent(new ValueEventListener() {
@Override
public void onDataChange(DataSnapshot dataSnapshot) {
// How to return this value?
if(dataSnapshot != null) {
System.out.println(dataSnapshot.getValue(String.class));
}
}
@Override
public void onCancelled(DatabaseError databaseError) {}
});
如果你想在外面使用它,还有另一种方法。您需要创建自己的回调来等待 Firebase 返回数据。要实现此目的,首先,您需要创建一个如下所示的界面
:
public interface MyCallback {
void onCallback(String value);
}
然后您需要创建一个实际从数据库获取数据的方法。该方法应如下所示:
public void readData(MyCallback myCallback) {
databaseReference.child(String.format("users/%s/name", uid)).addListenerForSingleValueEvent(new ValueEventListener() {
@Override
public void onDataChange(DataSnapshot dataSnapshot) {
String value = dataSnapshot.getValue(String.class);
myCallback.onCallback(value);
}
@Override
public void onCancelled(DatabaseError databaseError) {}
});
}
最后只需调用 readData()
方法,并在需要的地方将 MyCallback
接口(interface)的实例作为参数传递,如下所示:
readData(new MyCallback() {
@Override
public void onCallback(String value) {
Log.d("TAG", value);
}
});
这是您可以在 onDataChange()
方法之外使用该值的唯一方法。欲了解更多信息,您还可以看看这个 video 。
编辑:2021 年 2 月 26 日
更多信息,您可以查看以下文章:
以及以下视频:
关于java - 如何返回 DataSnapshot 值作为方法的结果?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56930388/
我想了解 Ruby 方法 methods() 是如何工作的。 我尝试使用“ruby 方法”在 Google 上搜索,但这不是我需要的。 我也看过 ruby-doc.org,但我没有找到这种方法。
Test 方法 对指定的字符串执行一个正则表达式搜索,并返回一个 Boolean 值指示是否找到匹配的模式。 object.Test(string) 参数 object 必选项。总是一个
Replace 方法 替换在正则表达式查找中找到的文本。 object.Replace(string1, string2) 参数 object 必选项。总是一个 RegExp 对象的名称。
Raise 方法 生成运行时错误 object.Raise(number, source, description, helpfile, helpcontext) 参数 object 应为
Execute 方法 对指定的字符串执行正则表达式搜索。 object.Execute(string) 参数 object 必选项。总是一个 RegExp 对象的名称。 string
Clear 方法 清除 Err 对象的所有属性设置。 object.Clear object 应为 Err 对象的名称。 说明 在错误处理后,使用 Clear 显式地清除 Err 对象。此
CopyFile 方法 将一个或多个文件从某位置复制到另一位置。 object.CopyFile source, destination[, overwrite] 参数 object 必选
Copy 方法 将指定的文件或文件夹从某位置复制到另一位置。 object.Copy destination[, overwrite] 参数 object 必选项。应为 File 或 F
Close 方法 关闭打开的 TextStream 文件。 object.Close object 应为 TextStream 对象的名称。 说明 下面例子举例说明如何使用 Close 方
BuildPath 方法 向现有路径后添加名称。 object.BuildPath(path, name) 参数 object 必选项。应为 FileSystemObject 对象的名称
GetFolder 方法 返回与指定的路径中某文件夹相应的 Folder 对象。 object.GetFolder(folderspec) 参数 object 必选项。应为 FileSy
GetFileName 方法 返回指定路径(不是指定驱动器路径部分)的最后一个文件或文件夹。 object.GetFileName(pathspec) 参数 object 必选项。应为
GetFile 方法 返回与指定路径中某文件相应的 File 对象。 object.GetFile(filespec) 参数 object 必选项。应为 FileSystemObject
GetExtensionName 方法 返回字符串,该字符串包含路径最后一个组成部分的扩展名。 object.GetExtensionName(path) 参数 object 必选项。应
GetDriveName 方法 返回包含指定路径中驱动器名的字符串。 object.GetDriveName(path) 参数 object 必选项。应为 FileSystemObjec
GetDrive 方法 返回与指定的路径中驱动器相对应的 Drive 对象。 object.GetDrive drivespec 参数 object 必选项。应为 FileSystemO
GetBaseName 方法 返回字符串,其中包含文件的基本名 (不带扩展名), 或者提供的路径说明中的文件夹。 object.GetBaseName(path) 参数 object 必
GetAbsolutePathName 方法 从提供的指定路径中返回完整且含义明确的路径。 object.GetAbsolutePathName(pathspec) 参数 object
FolderExists 方法 如果指定的文件夹存在,则返回 True;否则返回 False。 object.FolderExists(folderspec) 参数 object 必选项
FileExists 方法 如果指定的文件存在返回 True;否则返回 False。 object.FileExists(filespec) 参数 object 必选项。应为 FileS
我是一名优秀的程序员,十分优秀!