gpt4 book ai didi

android - 等待 Firebase 实时数据库的先前任务需要在新任务开始之前先完成

转载 作者:搜寻专家 更新时间:2023-11-01 09:26:43 29 4
gpt4 key购买 nike

我正在使用 Task API在我的应用程序中从通常来自不同节点的 Firebase 数据库检索数据。我有一个 Firebase 数据库的辅助类,如下所示:

public class FirebaseDbHelper {

public Task<DataSnapshot> getData() {
TaskCompletionSource<DataSnapshot> source = new TaskCompletionSource<>();
DatabaseReference dbRef = FirebaseDatabase.getInstance().getReference(FIRST_NODE).child(SUB_NODE);
dbRef.addListenerForSingleValueEvent(new ValueEventListener() {
@Override
public void onDataChange(DataSnapshot dataSnapshot) {
source.setResult(dataSnapshot);
}

@Override
public void onCancelled(DatabaseError databaseError) {
source.setException(databaseError.toException());
}
});
return source.getTask();
}

}

如您所见,getData() 返回一个 Task 对象,我在我的交互器类上使用它(我正在为我的应用程序使用 MVP 架构),如下所示:

public class TestDbInteractor {

private FirebaseDbHelper mDbHelper;
private Listener mListener;

public TestDbInteractor(@NonNull Listener listener) {
mDbHelper = new FirebaseDbHelper();
mListener = listener;
}

void getData() {
mDbHelper.getData().addOnCompleteListener(task -> {
if (task.isSuccessful()) {
mListener.onGetDataSuccess(new MyObject(task.getResult()));
} else {
mListener.onGetDataFailed(task.getException());
}
});
}

public interface Listener {

void onGetDataSuccess(MyObject object);

void onGetDataFailed(Exception exception);

}

}

这按预期工作。但是,我们注意到一个行为,当检索大量数据时,即使启动任务的 Activity 已经完成 finish(),任务仍会继续并尝试完成。我认为,这可以被视为内存泄漏,因为一个进程仍在运行,即使它应该已经停止/销毁。

更糟糕的是,当我尝试获取不同的数据(在不同的 Activity 中使用不同的任务到 Firebase 中的不同节点)时,我们注意到它等待前一个任务先完成,然后再继续这个新任务.

为了提供更多上下文,我们正在开发一个类似于 Telegram 的聊天应用程序,用户可以在其中拥有多个房间,我们看到的行为是在用户进入房间时发生的。这是流程:

  1. 用户进入房间,我请求房间详细信息的数据。
  2. 获得房间详细信息后,我会显示它,然后请求消息。我只检索最近的 10 个。在此期间,我只显示 Activity 的进度条。

为了完整的消息细节,我从Firebase上的不同节点获取数据,这是我主要使用Tasks的地方。

  1. 收到消息后,我将其传递给 View 以显示消息,然后为新消息附加一个监听器。一切都按预期进行。

当用户做这样的事情时,我在开头提到的行为是显而易见的:

  1. 用户进入带有消息的房间,立即检索房间详细信息,消息仍在加载。
  2. 用户离开房间(按后退按钮),这会让用户返回房间列表,然后进入另一个房间。

此时,房间详细信息的检索花费了如此长的时间 - 我们认为这很奇怪,因为一开始的数据并不是那么大。

经过多次测试,我们得出结论,检索时间长是由于当前任务(获取房间详细信息)仍在等待上一个任务(获取消息)在不同的 Activity 中启动,先完成再开始。

我试图实现我的答案 here ,尝试使用 CancellableTask,但我不知道如何在我当前的实现中使用它,在我使用 TaskCompletionSource 的地方,你只能设置一个结果或异常。

我在想,如果我将任务完成源移动到交互器类级别而不是助手,这可能会奏效——我还没有尝试过。我认为这是可能的,但需要花费大量时间来重构我已有的类。

所以我想为什么不试试 Doug's answer ,使用 Activity 范围的监听器。所以我像下面这样测试它。

在我的activity中,我添加了一个getActivity()方法,可以在presenter中调用:

public class TestPresenter
implements TestDbInteractor.Listener {

private View mView;

private TestDbInteractor mDbInteractor;

@Override
void bindView(View view) {
mView = view;

mDbInteractor = new TestDbInteractor(this);
}

@Override
void requestMessages() {
mDbInteractor.getData(mView.getActivity());
}

// Listener stuff below

}

并像这样更新了我的 getData():

void getData(@NonNull Activity activity) {
mDbHelper.getData().addOnCompleteListener(activity, task -> {
if (task.isSuccessful()) {
mListener.onGetDataSuccess(new MyObject(task.getResult()));
} else {
mListener.onGetDataFailed(task.getException());
}
});
}

不幸的是,这似乎不起作用,退出 Activity 仍然等待任务完成,然后在不同 Activity 中启动的新任务开始。

最佳答案

如果您启动对实时数据库的查询,它将始终运行直至完成,无论是否有任何监听器附加到返回的任务。没有办法取消该工作,既不能通过手动删除最后一个监听器,也不能通过使用自动删除的 Activity 范围的监听器。运动中的查询保持运动。 此外,进出 RTDB 的所有流量都通过单个套接字进行管道传输,这意味着在一个未完成的查询之后的后续查询结果将必须等待队列中它前面的所有内容先完成。 这可能是您观察到的根本原因 - 您有一个不完整的查询,其他查询正在等待,无论您是否使用任务 API。

幸运的是,如果您启用了持久化,则第二个查询应该由第一个查询的缓存提供服务,而不需要再次往返服务器。

如果您需要确保在破坏 Activity 的配置更改中保留第一个查询的结果,那么您应该使用类似 LiveData 的东西从 Android 架构组件来管理它,这样你就可以在配置更改后从中断的地方继续查询。如果这样做,请不要使用 Activity 范围的监听器。

我写了一篇关于 using architecture components with Firebase 的三部分博文,这也可能令人感兴趣。

关于android - 等待 Firebase 实时数据库的先前任务需要在新任务开始之前先完成,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50072660/

29 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com