如何绕过 Firebase 缓存刷新数据(在 Android 应用程序中)?

新手上路,请多包涵

在大部分时间必须离线工作的 Android 应用程序上,当它在线时,我需要为 ie 执行一些同步操作:

 User myUser =  MyclientFacade.getUser();
If (myUser.getScore > 10) {
    DoSomething()
}

其中User是Firebase填充的POJO;

Firebase 缓存激活时出现的问题

Firebase.getDefaultConfig().setPersistenceEnabled(true);

并且用户已经在缓存中,数据由第三方(甚至另一台设备)在 Firebase DB 上更新。事实上,当我查询 Firebase 以获取用户时,我首先从缓存中获取数据,然后使用来自 Firebase 服务器的最新数据获取第二个更改事件,但为时已晚!

让我们看看同步方法 MyclientFacade.getUser() :

 Public User  getUser()  {
  Firebase ref = myFireBaseroot.child("User").child(uid);
  ref.keepSynced(true);
  /* try {
    Thread.sleep(3000);
 } catch (InterruptedException e) {
    e.printStackTrace();
 }*/
final CountDownLatch signal = new CountDownLatch(1);

ref.addListenerForSingleValueEvent(new ValueEventListener() {
//ref.addValueEventListener(new ValueEventListener() {
    @Override
    public void onDataChange(DataSnapshot dataSnapshot) {
       this.user = dataSnapshot.getValue(User.class);
       signal.countDown();
    }
    @Override
    public void onCancelled(FirebaseError firebaseError) {
       signal.countDown();
    }
});
signal.await(5, TimeUnit.SECONDS);
ref.keepSynced(false);
return this.user;
}

如果我使用 addValueEventListeneraddListenerForSingleValueEventref.keepSynced --- 混合使用,我会获得相同的行为:

假设我的用户在缓存中的得分值为 5,而来自 Firebase DB 的得分值为 11。

当我调用 getUser 时,我将获得 5 分(Firebase 首先询问缓存),因此我不会调用 doSomething() 方法。

如果我取消注释我示例中的 Thread.sleep() 代码,Firebase 缓存将有足够的时间进行更新,我的 getUser 将返回正确的分值 (11)。

那么如何直接从服务器端直接询问最新值并绕过缓存呢?

原文由 ThierryC 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 405
2 个回答

这个问题也给我的申请带来了很大压力。

I tried everything, from changing .addListenerForSingleValueEvent() to .addValueEventListener() to trying to creatively use .keepSynced() to using a delay (the Thread.sleep() method you have described上面)并没有真正一致地工作(即使是 Thread.sleep() 方法,这在生产应用程序中是不可接受的,也没有给我一致的结果)。

所以我所做的是:在创建一个 查询 对象并调用 .keepSynced() 之后,我继续在我正在查询的节点中编写一个模拟/令牌对象,然后在该操作的完成侦听器中,我删除模拟对象后,执行我想执行的数据检索。

就像是:

  MockObject mock = new MockObject();
    mock.setIdentifier("delete!");

    final Query query = firebase.child("node1").child("node2");

    query.keepSynced(true);

    firebase.child("node1").child("node2").child("refreshMock")
            .setValue(mock, new CompletionListener() {

                @Override
                public void onComplete(FirebaseError error, Firebase afb) {

                    query.addListenerForSingleValueEvent(new ValueEventListener() {

                        public void onDataChange(DataSnapshot data) {

                            // get identifier and recognise that this data
                            // shouldn't be used
                            // it's also probably a good idea to remove the
                            // mock object
                            // using the removeValue() method in its
                            // speficic node so
                            // that the database won't be saddled with a new
                            // one in every
                            // read operation

                        }

                        public void onCancelled(FirebaseError error) {
                        }

                    });

                }

            });
}

到目前为止,这对我一直有效! (好吧,一天左右的时间,所以请加一点盐)。似乎在读取之前执行写入操作以某种方式绕过缓存,这是有道理的。所以数据回来是新鲜的。

唯一的缺点是读取操作之前的额外写入操作,这可能会导致小延迟(显然使用小对象)但如果这是始终保持新鲜数据的代价,我会接受!

希望这可以帮助!

原文由 Antonis427 发布,翻译遵循 CC BY-SA 3.0 许可协议

我发现的解决方法是使用 Firebase 的 runTransaction() 方法。这似乎总是从服务器检索数据。

 String firebaseUrl = "/some/user/datapath/";
final Firebase firebaseClient = new Firebase(firebaseUrl);

    // Use runTransaction to bypass cached DataSnapshot
    firebaseClient.runTransaction(new Transaction.Handler() {
        @Override
        public Transaction.Result doTransaction(MutableData mutableData) {
            // Return passed in data
            return Transaction.success(mutableData);
        }

        @Override
        public void onComplete(FirebaseError firebaseError, boolean success, DataSnapshot dataSnapshot) {
            if (firebaseError != null || !success || dataSnapshot == null) {
              System.out.println("Failed to get DataSnapshot");
            } else {
              System.out.println("Successfully get DataSnapshot");
              //handle data here
            }
        }
    });

原文由 Robert 发布,翻译遵循 CC BY-SA 3.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题