Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/android/205.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Android Firebase数据库:如果客户端脱机,规则显然不适用?_Android_Firebase_Firebase Realtime Database_Firebase Security - Fatal编程技术网

Android Firebase数据库:如果客户端脱机,规则显然不适用?

Android Firebase数据库:如果客户端脱机,规则显然不适用?,android,firebase,firebase-realtime-database,firebase-security,Android,Firebase,Firebase Realtime Database,Firebase Security,考虑以下示例: 我正在test/节点上写入一个值,并且我已经设置了一个规则,仅当“(新值)等于(旧值+1)”时才允许写入,即newData.val()==data.val()+1 假设test/节点的初始值为0 如果客户端脱机并执行以下命令: testRef.setValue(1); testRef.setValue(2); testRef.setValue(3); testRef.setValue(4); testRef.setValue(5); 然后,当他返回在线时,值5将写入数据库,但我

考虑以下示例:

我正在
test/
节点上写入一个值,并且我已经设置了一个规则,仅当“(新值)等于(旧值+1)”时才允许写入,即
newData.val()==data.val()+1

假设
test/
节点的初始值为
0

如果客户端脱机并执行以下命令:

testRef.setValue(1);
testRef.setValue(2);
testRef.setValue(3);
testRef.setValue(4);
testRef.setValue(5);
然后,当他返回在线时,值
5
将写入数据库,但我不确定我是否理解原因,因为
5!=0+1
。我猜这是因为本地数据库中缓存了以前的值,但不幸的是,这并不是我想要达到的结果。我希望服务器拒绝该值,因为它不遵循数据库的规则

有没有办法做到这一点

或者是否有其他解决方法,以便我可以实施以下内容:


testRef.setValue(1)->将值写入本地数据库->检查值是否遵循联机数据库的规则->如果值不遵循规则,或者我们无法检查,因为我们处于脱机状态,则从本地数据库中删除值

对于您的问题,我假设“脱机”表示客户端没有连接。在我的测试中,我通过启用飞机模式模拟了这一点

中介绍了Firebase脱机功能。这里提供的一个对您的问题很重要的细节是:

Firebase实时数据库客户端自动保留一个 应用程序脱机时执行的所有写入操作。。。 当应用程序恢复连接时,所有操作都将发送到 Firebase实时数据库服务器

您可以使用下面的代码看到这种行为,它为
setValue()
调用添加了一个完成侦听器。在我的测试中,我将设备置于飞行模式(脱机),运行代码,然后禁用飞行模式以返回联机状态。为每个
setValue()
生成一条日志消息,确认在重新建立连接时写入操作已排队并发送。这解释了写入满足验证规则的原因:客户端不会发送一个最终值为5的写入请求,而是发送五个原始递增值的请求

您可以通过再次运行测试来确认规则是否有效,而无需先将
test
的值重置回0。每次写入都会失败

此代码还演示Firebase客户端如何处理客户端脱机时所做的更改,这些更改后来被安全规则拒绝。脱机时,在客户端缓存中进行更改,并使用新的(未验证的)值触发
onDataChange()
回调。稍后,当客户端联机并且服务器拒绝更改时,
onDataChange()
将使用以前的值再次激发

final DatabaseReference ref = FirebaseDatabase.getInstance().getReference("test");

ref.addValueEventListener(new ValueEventListener() {
    @Override
    public void onDataChange(DataSnapshot dataSnapshot) {
        Log.d(TAG, "onDataChange: test=" + dataSnapshot.getValue(Integer.class));
    }
    @Override
    public void onCancelled(DatabaseError databaseError) {
        throw databaseError.toException();
    }
});

final DatabaseReference.CompletionListener completionListener =
        new DatabaseReference.CompletionListener() {
    @Override
    public void onComplete(DatabaseError databaseError, DatabaseReference databaseReference) {
        if (databaseError == null) {
            Log.d(TAG, "setValue() Success");
        } else {
            Log.d(TAG, "setValue() Failed " + databaseError.getMessage());
        }
    }
};

ref.setValue(1, completionListener);
ref.setValue(2, completionListener);
ref.setValue(3, completionListener);
ref.setValue(4, completionListener);
ref.setValue(5, completionListener);

谢谢,我可以理解,但就我个人而言,如果由于缺少Internet连接而无法验证规则,我希望可以选择从本地缓存中删除该值。我之所以需要它,是因为我正在开发一个协作应用程序,一些节点可以被超过1个用户访问。在任何情况下,如果没有任何Internet连接,是否有从本地缓存中删除值的解决方法?比如说暂停?(即,如果服务器在5秒钟内无法访问,请从缓存中删除所有挂起的写操作/本地值。AFAIK没有API可删除挂起的写操作。请参阅Firebaser FvP中的此答案:。可能您所能做的最好是,并且仅在连接时允许写操作。