如何绕过 Firebase 缓存来刷新数据(在 Android 应用中)? [英] How to bypass the Firebase cache to refresh data (in Android app)?

查看:15
本文介绍了如何绕过 Firebase 缓存来刷新数据(在 Android 应用中)?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在大多数时间必须离线工作的 Android 应用程序上,当它在线时,我需要执行一些同步操作,例如:

On an Android application which must works offline most of the time I need, when it's online, to do some synchronous operations for i.e. :

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

其中 User 是 Firebase 填充的 POJO;

Where User is a POJO filled by Firebase;

Firebase 缓存激活时出现问题

The problem occurs when the Firebase cache is activated

Firebase.getDefaultConfig().setPersistenceEnabled(true);

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

and the user is already in cache and the data are updated on Firebase DB by a third party (or even by another device). Indeed when I query Firebase to get the User I obtain first the data from the cache and later a second change event with the latest data from the Firebase server, but it's too late!

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

Let's see the synchronous method 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 混合使用,我会获得相同的行为:

I obtain the same behavior if I use addValueEventListener or addListenerForSingleValueEvent mixed with ref.keepSynced:

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

Let's say my user's score value in cache is 5 and from Firebase DB is 11.

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

When I call getUser I will obtain the score of 5 (Firebase ask cache first) so I will not call the doSomething() method.

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

If I uncomment the Thread.sleep() code from my example, the Firebase cache will have enough time to be updated and my getUser will return the correct score value (11).

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

推荐答案

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

This was a problem that was causing me a lot of stress in my application too.

我尝试了一切,从将 .addListenerForSingleValueEvent() 更改为 .addValueEventListener() 到尝试创造性地使用 .keepSynced() 到使用延迟(您在上面描述的 Thread.sleep() 方法)并且没有什么真正一致的(即使是 Thread.sleep() 方法,这不是真正可以接受的在生产应用中没有给我一致的结果).

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 above) and nothing really worked consistently (even the Thread.sleep() method, which wasn't really acceptable in a production app didn't give me consistent results).

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

So what I did was this: after creating a Query object and calling .keepSynced() on it, I then proceed to write a mock/token object in the node I'm querying and THEN in that operation's completion listener, I do the data retrieval I want to do, after deleting the mock object.

类似于:

 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) {
                        }

                    });

                }

            });
}

到目前为止,这对我来说一直有效!(好吧,一天左右,所以把它和一粒盐一起吃).似乎在读取之前进行写入操作以某种方式绕过缓存,这是有道理的.所以数据回来了.

This has worked consistently so far for me! (well, for a day or so, so take this with a grain of salt). It seems like doing a write operation before reading somehow bypasses the cache, which makes sense. So the data comes back fresh.

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

The only downside is the extra write operation before the read operation, which may cause a small delay (obviously use a small object) but if that's the price for always fresh data, I'll take it!

希望这有帮助!

这篇关于如何绕过 Firebase 缓存来刷新数据(在 Android 应用中)?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆