【发布时间】:2017-11-02 15:39:33
【问题描述】:
我在 Android 应用中使用 Firebase。该应用程序设置了类似群聊的东西,并允许用户加入。 用户获得一个密钥,然后可以将自己连接到相应的 DatabaseReference。 我们需要检查密钥是否有效。因此,在创建组时,主机会自动将自己添加到用户列表中。然后所有新客户端都可以检查列表中是否有条目。如果列表为空,则密钥无效。
这意味着我需要等待 setValue 调用完成。 Firebase 有很多回调可以告诉我这一点,但它们很成问题。有时,他们根本没有被调用。 我已经在这里问过一个关于这种非确定性行为的问题:How to listen for Firebase setValue completion
现在我发现了这些回调的一个新问题。 我已将我的基础架构更改为异步设置。所有交互都打包到 Callables 中并提交给 ExecutorService。结果是一个 Future。现在,如果我想等待某事完成,我可以等待那个未来。在 Future 内部,我仍然需要使用 Firebase 回调。
代码位于名为 DBConnection 的包装类中。
这是我创建新组(派对)的代码:
public Future<DBState> createParty() {
// assert entries
assertState(DBState.SignedIn);
// process for state transition
Callable<DBState> creationProcess = new Callable<DBState>() {
@Override
public DBState call() throws Exception {
lock.lock();
try {
// create a new party
ourPartyDatabaseReference = partiesDatabaseReference.push();
usersDatabaseReference = ourPartyDatabaseReference.child("users");
// try every remedy for the missing callbacks
firebaseDatabase.goOnline();
ourPartyDatabaseReference.keepSynced(true);
usersDatabaseReference.keepSynced(true);
// push a value to the users database
// this way the database reference is actually created
// and new users can search for existing users when they connect
// we can only continue after that task has been completed
// add listeners for success and failure and wait for their completion
// TODO: we need information that this task has been finished
// but no callback seems to work
// onSuccess, onCompletion on the task are not reliable
// and the child and value event listeners on the userDatabaseReference are not reliable, too
final CountDownLatch waiter = new CountDownLatch(1);
usersDatabaseReference.addValueEventListener(new ValueEventListener() {
@Override
public void onDataChange(DataSnapshot dataSnapshot) {
waiter.countDown();
}
@Override
public void onCancelled(DatabaseError databaseError) {
waiter.countDown();
}
});
Task addingTask = usersDatabaseReference.child(user.getUid()).setValue(true);
addingTask.addOnSuccessListener(new OnSuccessListener() {
@Override
public void onSuccess(Object o) {
waiter.countDown();
}
});
addingTask.addOnCompleteListener(new OnCompleteListener() {
@Override
public void onComplete(@NonNull Task task) {
waiter.countDown();
}
});
try {
waiter.await();
} catch (InterruptedException ex) {
}
connectToParty();
} finally {
lock.unlock();
}
// if we could connect, we are now DBState.Connected,
// otherwise we are still DBState.SignedIn
return state;
}
};
// start process
return executorService.submit(creationProcess);
}
你可以这样使用它:
Future<DBState> creationFuture = dbConnection.createParty();
try {
creationFuture.get(TIMEOUT, TimeUnit.MILLISECONDS);
} catch (InterruptedException ex) {
throw new AssertionError("there should be no interrupt");
}catch (TimeoutException ex) {
throw new AssertionError("timeout in party creation");
}catch (ExecutionException ex) {
throw new AssertionError("concurrent execution exception");
}
我已经为此编写了测试。
在测试中,一切正常。我已经执行了至少十几次canCreateParty 测试。
为了确保回调起作用,我将 CountDownLatch 增加到 3 个计数,并向 countDowns 添加断点。到达每个countDown。
但在运行时,不会调用任何回调。 没有一个断点到达,等待未来最终超时。
最奇怪的部分是:我在模拟器旁边打开了 Firebase 控制台。我可以看到如何创建新方和添加用户。无论是在测试中还是在运行时,派对创建都按预期工作,并添加了一个新用户。 为什么我在运行时没有收到回调?
【问题讨论】:
-
只是预感 - “运行时”不涉及不同的密钥库,对吗?就像调试/发布一样 - 因为您将为此使用不同的 SHA1,因此据我所知需要不同的 firebase 密钥
-
嗯,我不知道。我已将我的调试密钥从 android signingReport 添加到 Firebase。我刚刚检查过:该报告只生成一个密钥。我还有其他地方需要检查钥匙吗?无论如何,如果密钥被拒绝,我无法在运行时写入数据库,或者我可以吗?我可以看到正在创建的新方和正在添加的用户——所有这些都是在运行时进行的。只是缺少完成的回调
-
嗯,我不确定——我对你在做什么并不完全熟悉,我只真正使用过 FCM。如果签名报告说有一个 SHA,那么这不应该是问题。在您找出问题所在之前,这是毫无意义的问题之一。仔细检查您的测试是否以任何方式作弊,并确保您不只是丢弃来自 firebase 的任何传入消息。您是否从实际设备中获得相同的行为?我知道这也不重要,但仍然
-
@SaikCaskey,是的,这个问题只有在我发现后才有意义。
标签: java android firebase callback firebase-authentication