当前位置: 首页 > 知识库问答 >
问题:

如何将DataSnapshot值作为方法的结果返回?

弘浩瀚
2023-03-14
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) {}
    });
}

共有1个答案

谷泳
2023-03-14

这是异步web API的一个典型问题。您现在不能返回尚未加载的东西。换句话说,您不能简单地创建全局变量并在OnDataChange()方法之外使用它,因为它将始终为NULL。之所以发生这种情况,是因为OnDataChange()方法被称为异步。根据您的连接速度和状态,数据可用可能需要几百毫秒到几秒的时间。

但是不仅Firebase Realtime Database异步加载数据,而且几乎所有的现代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!");
}

附上监听器后!

onDataChange()方法内部!

这可能不是您所期望的,但它准确地解释了为什么返回数据时数据为null

对于大多数开发人员来说,最初的反应是尝试“修复”这个异步行为,我个人建议不要这样做。web是异步的,越早接受这一点,就越早学会如何使用现代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) {}
});
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(new MyCallback() {
    @Override
    public void onCallback(String value) {
        Log.d("TAG", value);
    }
});

这是您可以在OnDataChange()方法之外使用该值的唯一方法。更多的信息,你也可以看看这个视频。

编辑日期:2021年2月26日

更多信息,可以查看以下文章:

    null
    null
 类似资料:
  • 问题内容: 我对Java没有太多的经验。我不确定这个问题是否很愚蠢,但是我需要从Firebase实时数据库中获取一个用户名,并通过此方法返回该名称。因此,我想出了如何获得该值,但是我不明白如何通过此方法返回它。最好的方法是什么? 问题答案: 这是异步Web API的经典问题。您现在无法返回尚未加载的内容。换句话说,您不能简单地创建一个全局变量并在onDataChange()方法外部使用它,因为它将

  • 最简单的例子:我有以下方法: 我想模拟此方法以返回传递的参数作为结果。例如: 我知道我可以硬编码这种行为,但我希望它是通用的。

  • 问题内容: 是否可以将此代码转换为Java 8可选单行表达式? 即如果某个对象不为空,我需要调用一个对象方法并返回其结果,否则返回0。 不适合,因为它返回相同类型的对象,但是我需要方法调用的结果或一些默认值。 问题答案: 几种形式: 其中,最后一个不使用Optional(因此不能严格回答您的问题!)更易于阅读,运行时开销也较小,因此应优先使用。 可以说,如果您反转选项,它甚至更简单: …尽管您可能

  • 是否可以将此代码转换为Java8可选的单行表达式? i、 如果某个对象不是null,我需要调用一个对象方法并返回其结果,否则返回0<代码>可选。不可数()。orElse()不适合,因为它返回相同类型的对象,但我需要方法调用的结果或一些默认值。

  • 问题内容: 我能找到的所有带有猫鼬结果的页面都可以做到这一点: 如何从查询中返回结果,更像这样? 这样我就可以在页面上发布多个结果? 喜欢: 能做到吗? 问题答案: 您正在尝试强制执行同步范例。就是行不通。node.js是单线程的,大部分情况下- 完成io后,便产生了执行上下文。信令通过回调进行管理。这意味着您具有嵌套的回调,命名函数或流控制库,以使外观看起来更好。 https://github.

  • 你可以写出返回结构的函数。如,findCenter函数把一个Rectangle类型作为参数,返回一个Point类型的值,其中包含着该矩形中心的坐标: Point findCenter (Rectangle& box) { double x = box.corner.x + box.width/2; double y = box.corner.y + box.height/2;