我正在尝试使用通过Firebase连接的对等方从我的Android应用中更新部分WebView。为此,执行将返回所需数据的阻塞操作可能会有所帮助。例如,Chat示例的实现将等待另一个聊天参与者在push.setValue()返回之前写入某些内容。 Firebase可以实现这种行为吗?
答案 0 :(得分:32)
import com.google.android.gms.tasks.Tasks;
Tasks.await(taskFromFirebase);
答案 1 :(得分:11)
在常规JVM上,您可以使用常规Java同步原语执行此操作。
例如:
// create a java.util.concurrent.Semaphore with 0 initial permits
final Semaphore semaphore = new Semaphore(0);
// attach a value listener to a Firebase reference
ref.addValueEventListener(new ValueEventListener() {
// onDataChange will execute when the current value loaded and whenever it changes
@Override
public void onDataChange(DataSnapshot dataSnapshot) {
// TODO: do whatever you need to do with the dataSnapshot
// tell the caller that we're done
semaphore.release();
}
@Override
public void onCancelled(FirebaseError firebaseError) {
}
});
// wait until the onDataChange callback has released the semaphore
semaphore.acquire();
// send our response message
ref.push().setValue("Oh really? Here is what I think of that");
但这不适用于Android。这是一件好事,因为在影响用户界面的任何事情中使用这种类型的阻止方法是个坏主意。我有这个代码的唯一原因是因为我需要进行单元测试。
在面向用户的真实代码中,您应该采用事件驱动的方法。因此,不是"等待数据来,然后发送我的消息",我会"当数据进来时,发送我的消息":
// attach a value listener to a Firebase reference
ref.addValueEventListener(new ValueEventListener() {
// onDataChange will execute when the current value loaded and whenever it changes
@Override
public void onDataChange(DataSnapshot dataSnapshot) {
// TODO: do whatever you need to do with the dataSnapshot
// send our response message
ref.push().setValue("Oh really? Here is what I think of that!");
}
@Override
public void onCancelled(FirebaseError firebaseError) {
}
});
最终结果完全相同,但此代码不需要同步,也不会在Android上屏蔽。
答案 2 :(得分:8)
我提出了另一种同步获取数据的方法。 先决条件是不在UI线程上。
final TaskCompletionSource<List<Objects>> tcs = new TaskCompletionSource<>();
firebaseDatabase.getReference().child("objects").addListenerForSingleValueEvent(new ValueEventListener() {
@Override
public void onDataChange(DataSnapshot dataSnapshot) {
Mapper<DataSnapshot, List<Object>> mapper = new SnapshotToObjects();
tcs.setResult(mapper.map(dataSnapshot));
}
@Override
public void onCancelled(DatabaseError databaseError) {
tcs.setException(databaseError.toException());
}
});
Task<List<Object>> t = tcs.getTask();
try {
Tasks.await(t);
} catch (ExecutionException | InterruptedException e) {
t = Tasks.forException(e);
}
if(t.isSuccessful()) {
List<Object> result = t.getResult();
}
我测试了我的解决方案并且工作正常,但请证明我错了!
答案 3 :(得分:0)
下面是一个基于Alex简洁答案的较长示例:
import com.google.android.gms.tasks.Tasks;
import com.google.firebase.firestore.CollectionReference;
import com.google.firebase.firestore.DocumentSnapshot;
import com.google.firebase.firestore.FirebaseFirestore;
import com.google.firebase.firestore.Query;
import com.google.firebase.firestore.QuerySnapshot;
final FirebaseFirestore firestore = FirebaseFirestore.getInstance();
final CollectionReference chatMessageReference = firestore.collection("chatmessages");
final Query johnMessagesQuery = chatMessageReference.whereEqualTo("name", "john");
final QuerySnapshot querySnapshot = Tasks.await(johnMessagesQuery.get());
final List<DocumentSnapshot> johnMessagesDocs = querySnapshot.getDocuments();
final ChatMessage firstChatMessage = johnMessagesDocs.get(0).toObject(ChatMessage.class);
请注意,这不是一个好习惯,因为它会阻塞UI线程,通常应该使用回调。但这在特定情况下有帮助。
答案 4 :(得分:0)
如果有人还在考虑如何使用Kotlin的协程,则可以使用kotlinx-coroutines-play-services
。
添加到您的应用build.gradle
文件中:
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-play-services:1.1.1"
然后简单地:
suspend fun signIn(email: String, password: String) {
try {
val auth: FirebaseAuth = FirebaseAuth.getInstance()
auth.signInWithEmailAndPassword(email, password).await()
} catch (e: FirebaseAuthException) {
println("${e.errorCode}: ${e.message}")
}
}
答案 5 :(得分:0)
我做了一个简单的类,可以在Android中同步调用任务。
请注意,这类似于Javascript
的异步等待功能。
检查我的gist。
以下是使用它的示例代码。
TasksManager.call(() -> {
Tasks.await(AuthManager.signInAnonymously());
// You can use multiple Tasks.await method here.
// Tasks.await(getUserTask());
// Tasks.await(getProfileTask());
// Tasks.await(moreAwesomeTask());
// ...
startMainActivity();
return null;
}).addOnFailureListener(e -> {
Log.w(TAG, "signInAnonymously:ERROR", e);
});