我在 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 控制台。我可以看到如何创建新方和添加用户。无论是在测试还是在运行时,派对创建都按预期工作,并添加了一个新用户。为什么我在运行时没有收到回调?
原因是 Firebase 总是从主线程调用它的回调。
我的测试中的“主”线程被称为“junittestrunnerXXX”之类的东西。Firebase 创建一个名为“main”的新线程来调用回调。
在运行时,“主”线程是实际的“主”线程。如果我调用 get() ,它就会被永久阻止。Firebase 检查此线程是否存在,并且由于它已经存在并且由于它被阻止,因此没有任何反应。
本文收集自互联网,转载请注明来源。
如有侵权,请联系 [email protected] 删除。
我来说两句