问题是:我的MainActivity中的布局是在我有机会完成调用firebase以恢复应用程序数据之前生成的。如果我旋转屏幕,从而导致onCreate在MainActivity中再次运行,则生成的所有内容都正常。
在我的应用程序中,我有一个自定义的应用程序类实现,它对Firebase进行一系列调用,以恢复数据/确保数据始终同步。然而,我有大约20个ValueEventListeners,而不是几个下面有很多孩子的ValueEventListeners。这是为了防止每次用户生成少量数据时,我的应用程序几乎同步整个数据库,并避免在异步操作数据时可能发生的冲突。有趣的是,ValueEventListeners实际上并没有按照编码的顺序获取数据,所以当最后一个完成时,我无法将布尔值设置为true。
我想知道是否有一种简单的方法来检测Firebase读取是否全部完成,而不是在每个监听器的末尾放置一些代码并执行手动执行此操作。我查看了Application类和Firebase中可用的方法,到目前为止我还没有找到任何有效的方法。
我的应用程序类中的一些代码:
public class CompassApp extends Application {
...然后在应用程序的onCreate中:
// Fetching Data from DB.
FirebaseDatabase database = FirebaseDatabase.getInstance();
DatabaseReference dbRef = database.getReference();
// Current User Data
dbRef.child("currentAppData").child("workingOut").addValueEventListener(new ValueEventListener() {
@Override
public void onDataChange(DataSnapshot dataSnapshot) {
activeFirebaseConnections += 1;
// Stops executing method if there is no data to retrieve
if (!dataSnapshot.exists()) {
return;
}
workingOut = dataSnapshot.getValue(boolean.class);
activeFirebaseConnections -= 1;
}
@Override
public void onCancelled(DatabaseError databaseError) {
Log.e(TAG, "Firebase read of sleepDebt failed");
}
});
dbRef.child("currentAppData").child("sleeping").addValueEventListener(new ValueEventListener() {
@Override
public void onDataChange(DataSnapshot dataSnapshot) {
activeFirebaseConnections += 1;
// Stops executing method if there is no data to retrieve
if (!dataSnapshot.exists()) {
return;
}
sleeping = dataSnapshot.getValue(boolean.class);
activeFirebaseConnections -= 1;
}
@Override
public void onCancelled(DatabaseError databaseError) {
Log.e(TAG, "Firebase read of sleepDebt failed");
}
});
(等等...剩下的只是更多的ValueEventListeners)
@Doug Stevenson回答很棒。对我来说几乎是现成的。我唯一改变的是,我没有显式创建AllOnCompleteListener类,而是编写了如下代码:
private OnCompleteListener<Map<DatabaseReference, DataSnapshot>> allListener;...
allListener = new OnCompleteListener<Map<DatabaseReference, DataSnapshot>>() {
@Override
public void onComplete(@NonNull Task<Map<DatabaseReference, DataSnapshot>> task) {
if (task.isSuccessful()) {
final Map<DatabaseReference, DataSnapshot> result = task.getResult();
// Look up DataSnapshot objects using the same DatabaseReferences you passed into FirebaseMultiQuery
for (Map.Entry<DatabaseReference, DataSnapshot> entry : result.entrySet()) { ...}
我的应用程序也面临着同样的问题。在对如何检查firebase是否完成了数据检索进行了长时间的研究后,我找到了这个解决方案。< br>
因此,当您的应用程序中有多个事件侦听器时。Firebase不按顺序逐个执行此侦听器
值事件侦听器始终在最后执行
因此,如果要在检索到所有数据时执行某些操作,可以调用ValueEventListener并执行一个方法,该方法将加载其中的所有视图。
因此,使用 rootRef.addListenerForSingleValueEvent()
并在其 onDataChanged()
中执行从 Firebase 检索数据后要执行的内容。
这对我有用,希望对你也有用
我目前正在使用我为启动多个数据负载而创建的实用程序类。当所有侦听器都完成时,它将触发最终任务。这里的关键是巧妙地使用Play Services提供的新任务工具进行异步编程。您可能可以使用其他异步框架来完成所有这些,但任务随Play Services免费提供,并在Firebase的其他部分中使用,因此您不妨学习使用它们。:-)
我在 Google I/O 2016 上做了一个关于任务的演讲。下面是一个视频链接,该视频直接跳转到该会话的相关部分。
public class FirebaseMultiQuery {
private final HashSet<DatabaseReference> refs = new HashSet<>();
private final HashMap<DatabaseReference, DataSnapshot> snaps = new HashMap<>();
private final HashMap<DatabaseReference, ValueEventListener> listeners = new HashMap<>();
public FirebaseMultiQuery(final DatabaseReference... refs) {
for (final DatabaseReference ref : refs) {
add(ref);
}
}
public void add(final DatabaseReference ref) {
refs.add(ref);
}
public Task<Map<DatabaseReference, DataSnapshot>> start() {
// Create a Task<DataSnapsot> to trigger in response to each database listener.
//
final ArrayList<Task<DataSnapshot>> tasks = new ArrayList<>(refs.size());
for (final DatabaseReference ref : refs) {
final TaskCompletionSource<DataSnapshot> source = new TaskCompletionSource<>();
final ValueEventListener listener = new MyValueEventListener(ref, source);
ref.addListenerForSingleValueEvent(listener);
listeners.put(ref, listener);
tasks.add(source.getTask());
}
// Return a single Task that triggers when all queries are complete. It contains
// a map of all original DatabaseReferences originally given here to their resulting
// DataSnapshot.
//
return Tasks.whenAll(tasks).continueWith(new Continuation<Void, Map<DatabaseReference, DataSnapshot>>() {
@Override
public Map<DatabaseReference, DataSnapshot> then(@NonNull Task<Void> task) throws Exception {
task.getResult();
return new HashMap<>(snaps);
}
});
}
public void stop() {
for (final Map.Entry<DatabaseReference, ValueEventListener> entry : listeners.entrySet()) {
entry.getKey().removeEventListener(entry.getValue());
}
snaps.clear();
listeners.clear();
}
private class MyValueEventListener implements ValueEventListener {
private final DatabaseReference ref;
private final TaskCompletionSource<DataSnapshot> taskSource;
public MyValueEventListener(DatabaseReference ref, TaskCompletionSource<DataSnapshot> taskSource) {
this.ref = ref;
this.taskSource = taskSource;
}
@Override
public void onDataChange(DataSnapshot dataSnapshot) {
snaps.put(ref, dataSnapshot);
taskSource.setResult(dataSnapshot);
}
@Override
public void onCancelled(DatabaseError databaseError) {
taskSource.setException(databaseError.toException());
}
}
}
你使用它的方式是这样的。确定需要从中加载数据的所有数据库引用
,并将其存储在活动的成员中。然后,在 onStart() 上的
活动期间,将它们全部传递到 FirebaseMultiQuery 的实例中,并在其上调用 start()。
它将返回一个任务,该任务将生成数据库引用的映射到它将生成的DataSnapshot。掌握该任务后,注册一个最终侦听器,该侦听器将在加载所有数据时触发:
firebaseMultiQuery = new FirebaseMultiQuery(dbRef1, dbRef2, dbRef3, ...);
final Task<Map<DatabaseReference, DataSnapshot>> allLoad = firebaseMultiQuery.start();
allLoad.addOnCompleteListener(activity, new AllOnCompleteListener());
在你的 onStop()
中,不要忘记调用 stop()
以确保一切都已正确关闭:
firebaseMultiQuery.stop();
任务完成后触发的侦听器接收映射中的所有数据,其外观如下:
private class AllOnCompleteListener implements OnCompleteListener<Map<DatabaseReference, DataSnapshot>> {
@Override
public void onComplete(@NonNull Task<Map<DatabaseReference, DataSnapshot>> task) {
if (task.isSuccessful()) {
final Map<DatabaseReference, DataSnapshot> result = task.getResult();
// Look up DataSnapshot objects using the same DatabaseReferences you passed into FirebaseMultiQuery
}
else {
exception = task.getException();
// log the error or whatever you need to do
}
// Do stuff with views
updateUi();
}
}
也许值得注意的是,写入数据的Firebase数据库调用也会返回您可以侦听以完成的任务。此外,Firebase存储使用任务,Firebase身份验证也是如此。
此处的代码当前可能不适用于 Firebase 数据库查询,该查询不是对数据库中节点的简单命名引用。这取决于它们是否以一种与键入哈希映射一致的方式进行哈希处理。
上面的代码仍然有些实验性,但到目前为止我还没有遇到任何问题。这看起来有很多代码,但是如果你做很多并发加载,它真的很方便。
如何在包含回收器视图的活动开始时显示Progressbar,一旦回收器视图从firebase数据库加载数据,应该隐藏该视图? 在onCreate方法中,我显示了我的ProgressBar,但我不知道什么时候应该隐藏它。 你们能给我点主意吗?谢谢
我是胡克斯的新手,遇到了一些让我追自己尾巴的案例。 希望有人能解释或提供对我有意义的解决方案: > 下面这个线程:如何调用加载函数与反应使用效果只有一次 我试着在没有依赖性的情况下使用useEffect,eslint不喜欢这样,他们建议添加一个“跳过下一行”,这似乎有点骇人:
问题内容: 我正在将React与Firebase一起使用来开发一个小型Web应用程序。为了进行身份验证,我使用了上下文API,并且在上下文中添加了登录用户的详细信息。 AuthProvider.tsx AuthConsumer.tsx PrivateRoute.tsx App.tsx 用户已经登录,并且会话持久性设置为本地。问题是,当我尝试本地主机/订阅(这是一条私有路由)时,context.is
我正在应用程序中从firebase realtime下载数据。我们在splashscreen上下载这些数据。在下载此数据之前,splashscreen屏幕不应关闭。找不到如何执行此操作 这是我的密码;
PrimeFaces 5.0、JSF 2.2、Glassfish 4.1.1、, 我假设我的设置中有些东西没有正确配置,但我不确定该看什么。。。 所以我使用managedbeans来支持JSF页面。在页面上的PrimeFace元素中,如果我使用oncomplete属性,它引用的方法将在页面加载时被调用。我不想让它在每次加载页面时调用这个方法,我也不认为应该这样! 我已经在几页和不同的元素中对此进行
问题内容: 浏览器窗口调整大小后如何调用函数? 我正在尝试这样做,但是遇到了问题。我正在使用JQuery Resize事件函数: 但是,如果用户手动调整浏览器窗口的大小,则会 连续 调用此功能。这意味着,它可能会在很短的时间间隔内多次调用此函数。 如何仅 一次 调用调整大小功能(一旦浏览器窗口调整大小后)? 更新 也不必使用全局变量。 问题答案: 您可以将参考ID存储到任何setInterval或