如何处理Firebase离线模式和数据推送?

How deal with Firebase offline mode and data push?

使用Firebase时,推荐使用push()命令来管理数据列表。这真的很好,它为列表中推送的数据提供了一个唯一且有序的 id。

但是,当 Firebase 离线(goOffline 或 NetworkOffline)时,如果应用程序尝试将数据推送到列表中,则不会触发完成侦听器,直到应用程序重新在线:所以没有唯一 ID 直到线路又接通了。

1/ 那是 expected/normal 行为吗?

2/ 我没有在文档中看到(据我所知),推送命令在离线状态下的工作方式不同(或仅在在线模式下)。我是不是错过了什么地方?

3/ 我的用例处理拥有关系的数据。这意味着我想在列表中创建一个对象(一种主对象),然后重用这个主对象 ID(由完成侦听器提供)来建立主对象和所有其他相关对象之间的关系。我该如何处理这种离线状态?

代码示例:

    findViewById(R.id.button3).setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            new Firebase(getString(R.string.firebase_url)).child("stack").push().setValue(counter++, new Firebase.CompletionListener() {
                @Override
                public void onComplete(FirebaseError firebaseError, Firebase firebase) {
                    ((TextView) findViewById(R.id.textView3)).setText(String.valueOf(counter) + " - " + firebase.toString());
                }

            });
        }
    });

编辑

这里有4种添加数据的方法:

使用监听器推送

   findViewById(R.id.button3).setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            new Firebase(getString(R.string.firebase_url)).child("stack").push().setValue(counter++, new Firebase.CompletionListener() {
                @Override
                public void onComplete(FirebaseError firebaseError, Firebase firebase) {
                    ((TextView) findViewById(R.id.textView3)).setText(String.valueOf(counter) + " - " + firebase.toString());
                }

            });
        }
    });

SetValue with Listener

    findViewById(R.id.button4).setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            new Firebase(getString(R.string.firebase_url)).child("stackManual").child(UUID.randomUUID().toString()).setValue(counter++, new Firebase.CompletionListener() {
                @Override
                public void onComplete(FirebaseError firebaseError, Firebase firebase) {
                    ((TextView) findViewById(R.id.textView4)).setText(String.valueOf(counter) + " - " + firebase.toString());
                }

            });
        }
    });

没有监听器的SetValue

    findViewById(R.id.button5).setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            Firebase temp = new Firebase(getString(R.string.firebase_url)).child("stackManual").child(UUID.randomUUID().toString());
            temp.setValue(counter++);


            ((TextView) findViewById(R.id.textView5)).setText(String.valueOf(counter) + " - " + temp.getKey().toString());
        }

    });

无监听器推送

    findViewById(R.id.button6).setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            Firebase temp = new Firebase(getString(R.string.firebase_url)).child("stack").push();
            temp.setValue(counter++);

            ((TextView) findViewById(R.id.textView6)).setText(String.valueOf(counter) + " - " + temp.getKey().toString());
        }

    });

似乎仅当数据位于服务器上的数据库中而不是本地数据库中时才会触发侦听器! - 那是对的吗 ? - 有记录吗?

因为知道,现在构建简单的异步应用程序更加困难:如果离线,异步作业的封装可能不会执行,对吧?

so there is no unique id until the line is on again

最后一个说法正确。 Firebase 推送 ID 是在客户端生成的,并且在统计上保证是唯一的。

您可以通过拆分操作轻松地检查这一点:

Firebase ref = new Firebase(getString(R.string.firebase_url));
Firebase newStackRef = ref.child("stack").push();
System.out.println("New key/push id: "+newStackRef.key());
newStackRef.setValue(counter++, new Firebase.CompletionListener() {

即使您未连接到网络,日志输出也会显示新的推送 ID。

IT APPEAR THAT THE LISTENERS ARE TRIGGERED ONLY WHEN THE DATA ARE IN THE DATABASE ON THE SERVER, AND NOT ON THE LOCAL DB! IS THAT CORRECT ?

完成侦听器只会在数据提交到服务器后触发。

来自guide on saving data

If you'd like to know when your data has been committed, you can add a completion listener. Both setValue() and updateChildren() take an optional completion listener that is called when the write has been committed to the database.

但是,本地和远程编辑都会触发常规事件侦听器(如使用 addValueEventListener() 创建的事件侦听器)。这些是您应该用来呈现 UI 等

的侦听器

按照@Andrew-lee 和@Frank-fan-puffelen 的要求(感谢双方同意),解决方案似乎是:

  1. 使用 push() 命令创建唯一 ID
  2. 将侦听器(单值)添加到 (1.) 中先前创建的节点的 firebase ref
  3. 在侦听器中安排您的工作(此处更新 UI,但可能是另一个命令)

    findViewById(R.id.button7).setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            Firebase temp = new Firebase(getString(R.string.firebase_url)).child("stack").push();
            temp.addListenerForSingleValueEvent(new ValueEventListener() {
                @Override
                public void onDataChange(DataSnapshot dataSnapshot) {
                    ((TextView) findViewById(R.id.textView7)).setText(String.valueOf(counter) + " - " + dataSnapshot.getKey().toString());
                }
    
                @Override
                public void onCancelled(FirebaseError firebaseError) {
    
                }
            });
            temp.setValue(counter++);
    
    
        }
    
    });