如何使用 Firebase 处理异步数据库?

Posted

技术标签:

【中文标题】如何使用 Firebase 处理异步数据库?【英文标题】:How to handle asynchronous Database with Firebase? 【发布时间】:2018-07-21 02:26:23 【问题描述】:

我有很多关于在我的 android 应用中处理异步数据库的问题。

因为我知道数据库是异步的,所以我尝试了几种方法来处理它。正如您在我的代码中看到的,我有两个函数需要在我的数据库中使用数组。我的第一个函数 (setArrayfromDatabase) 将在我的数据库中的数组上应用更改,而我的第二个函数 (setAnotherArray) 需要将此数组与从我的第一个函数应用的更改一起使用。这是我的代码:

    FirebaseDatabase database = FirebaseDatabase.getInstance();
final DatabaseReference myReff =database.getReference("server").child("user");

    myReff.addListenerForSingleValueEvent(new ValueEventListener() 
    @Override
    public void onDataChange(DataSnapshot dataSnapshot) 

        //Take the array from my database
        final ArrayList<Integer> array_from_database;
        GenericTypeIndicator<ArrayList<Integer>> genericTypeIndicator = new GenericTypeIndicator<ArrayList<Integer>>() ;
        array_from_database = dataSnapshot.getValue(genericTypeIndicator) ;

        System.out.println("1");

        //use this array in this first function, and this function will modify it.
        setArray_for_database(array_from_database);

        myReff.addValueEventListener(new ValueEventListener() 
            @Override
            public void onDataChange(DataSnapshot dataSnapshot) 

                //this will be executed only if my array is changed (So only if my other function have been correctly executed
                setAnotherArray(array_from_database);
                System.out.println("3");
            

            @Override
            public void onCancelled(DatabaseError databaseError) 
        );
    

    @Override
    public void onCancelled(DatabaseError databaseError) 

    
);

这里是 setArray_for_database 的代码:

    public void setArray_for_database(ArrayList<Integer> array_from_database)

    FirebaseDatabase database = FirebaseDatabase.getInstance();
    final DatabaseReference myReff =database.getReference();

    //Take the array from my database (gived in parameter)
    final ArrayList<Integer> array = array_from_database;

    myReff.addListenerForSingleValueEvent(new ValueEventListener() 
        @Override
        public void onDataChange(DataSnapshot dataSnapshot) 

            //this will be executed, even if data hasn't been changed because of the method (addListenerForSingleValueEvent)

            System.out.println("2");

            array.set(0,3);

            Map<String, Object> chemainChild = new HashMap<>();
            chemainChild.put("server/user/",array);

            myReff.updateChildren(chemainChild);
        

        @Override
        public void onCancelled(DatabaseError databaseError) 
    );

这是我的窍门。在另一个myReff.addListenerForSingleValueEvent(new ValueEventListener() 中拥有一个myReff.addValueEventListener(new ValueEventListener() 的目的是仅在我的数据库中的数组已更改时才执行onDataChange。但问题是事实并非如此。 这是首先打印的内容:1、3、2 而不是 1、2、3,就像我期望的那样。

你能帮帮我吗?我是否以错误的方式处理问题?在我的数组已更改的情况下,我该怎么做才能只执行我的第二个函数?在执行其他操作之前,如何让我的代码等待数据库中的更改? 希望你能理解我,如果你不明白我的问题,请随时问我问题。

【问题讨论】:

您尝试“加入”两个 Firebase 引用列表的事实意味着您的数据建模错误并且您将其视为关系数据库 @Diridou 这个答案对你有帮助吗? @PeterHaddad 目前我的模拟器有问题,所以我无法测试它,但我会告诉你非常感谢彼得 没问题 How to return dataSnapshot value as a result of a method?的可能重复 【参考方案1】:

改变这个:

   myReff.addValueEventListener(new ValueEventListener() 
        @Override
        public void onDataChange(DataSnapshot dataSnapshot) 

            //this will be executed only if my array is changed (So only if my other function have been correctly executed
            setAnotherArray(array_from_database);
            System.out.println("3");
        

到这里:

final FirebaseDatabase database = FirebaseDatabase.getInstance();
final DatabaseReference myReff = database.getReference();

  myReff.addValueEventListener(new ValueEventListener() 
        @Override
        public void onDataChange(DataSnapshot dataSnapshot) 

          DatabaseReference ref2 = database.getReference();

          //Take the array from my database (gived in parameter)
          final ArrayList<Integer> array = array_from_database;
           System.out.println("2");

        array.set(0,3);

        Map<String, Object> chemainChild = new HashMap<>();
        chemainChild.put("server/user/",array);

        myReff.updateChildren(chemainChild);

            System.out.println("3");
        

上面可能缺少一些代码,但您知道添加方法 public void setArray_for_database(ArrayList&lt;Integer&gt; array_from_database) 中的代码以使其工作。

由于onDataChange 是异步的,意味着程序将继续执行,即使仍然没有检索到数据,这是唯一的方法。

你得到 1-3-2 的原因是:

    进入第一个onDataChange 它打印了“1” 它进入了第一个内部的第二个 onDataChange。 它打印“3”,因为它是异步的,然后在检索数据时 调用方法并打印“2”

所以最好的办法是把数据添加到onDataChange里面的方法里

以上将解决您在问题中遇到的异步问题。但是您确实应该对数据进行非规范化。

阅读本文以了解更多信息:https://firebase.googleblog.com/2013/04/denormalizing-your-data-is-normal.html

【讨论】:

非常感谢@PeterHaddad!但我想知道为什么?! 它打印了“1”,然后在检索值时,因为它是异步的,它转到第二个 onDatachange 并打印“3”,然后它转到第一个并检索数据,然后转到调用方法,因为它现在拥有数据并执行它@Diridou 我已经明白了,谢谢。但是为什么当我把代码放进去时,它可以工作,而当我调用方法时它却不起作用?

以上是关于如何使用 Firebase 处理异步数据库?的主要内容,如果未能解决你的问题,请参考以下文章

如何使数组过滤器与异步函数端一起使用? [复制]

Firebase 保存数据方法异步或同步

如何在 Fire Base 中使用完成处理程序

如何使事件处理程序异步运行?

Vue.js:从 Firebase 存储中检索数据后如何异步加载模板?

如何在 Unity 和 Firebase 中使用异步