在我的活动中,我有一个字符串列表,这些字符串代表要将快照侦听器附加到的Firestore文档。我使用Acivity-ModelView-
存储库结构。在活动的onCreate中,我向ViewModelProvider请求适当的ViewModel。在ViewModel构造函数中,我进行调用以获取存储库(根据“带有视图的Android房间”教程)。我的存储库负责附加firestore侦听器,并将在线数据同步到本地数据库(android会议室)中。
我以前经常与这些侦听器发生内存泄漏,即每次更改Firestore文档时,我的存储库都试图将其的两个,三个,四个..副本下载到本地数据库中!我通过从活动的onDestroy一直到存储库中删除侦听器来解决该问题。
我的问题
是有关此解决方案的定价。我在FireBase网站上读到,快照侦听器每次启动时,至少将其视为一次“文档读取”,即使从未对文档进行任何更改。基本上,每次用户在我的应用中切换活动时,我都会删除并重新绑定十几个监听器(完全相同的文档)。这是否意味着即使30分钟的限制还没有结束,我仍要为每项活动更改支付一份阅读文档?
活动
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mMessageViewModel = new ViewModelProvider(this).get(MessageViewModel.class);
// ....
}
@Override
public void onDestroy(){
mMessageViewModel.removeListeners();
super.onDestroy();
}
视图模型
public MessageViewModel (Application application) {
super(application);
mRepository = new MessageRepository(application);
}
public void removeListeners(){
mRepository.removeListeners();
}
// ...
资料库
private List<ListenerRegistration> my_listeners;
private List<String> my_list;
MessageRepository(Application application) {
MessageRoomDatabase db = MessageRoomDatabase.getDatabase(application);
mMessageDao = db.messageDao();
firedb = FirebaseFirestore.getInstance();
attachListeners();
}
public void attachListeners(){
for(String item : my_list){
colRef = firedb.collection("items").document(item).collection("sub-items");
ListenerRegistration my_listener_registration = colRef
.addSnapshotListener(myListener);
my_listeners.add(my_listener_registration);
}
}
public void removeListeners(){
for(ListenerRegistration my_listener : my_listeners){
my_listener.remove();
}
}
// ...
每次附加侦听器时,Firestore客户端都必须连接到服务器,以检查该侦听器观察到的文档是否已被修改。由于服务器必须为此阅读文档,因此您确实需要为所观察的每个文档的阅读文档付费。
如果您不想这样做,可以考虑通过在source
options中指定它
来告诉客户端从缓存中读取。
DocumentReference docRef = db.collection("cities").document("SF"); // Source can be CACHE, SERVER, or DEFAULT. Source source = Source.CACHE; // Get the document, forcing the SDK to use the offline cache docRef.get(source).addOnCompleteListener(new
OnCompleteListener
() {
…
由于此操作是从本地缓存中读取的,因此您无需为服务器上的读取操作付费,但这当然意味着您可能在提供过时的数据。
问题内容: 我现在正在与Firestore合作,但分页有一些问题。 基本上,我有一个集合(假设有10个项目),其中每个项目都有一些数据和时间戳。 现在,我正在获取前3个项目,如下所示: 在快照侦听器中,我保存了快照中的最后一个文档,以便将其用作下一页的起点。 因此,有时我会要求下一页类似的项目: 现在我的前端中有从索引0到索引5(共6个)的项目。整齐! 如果索引4处的文档现在将其时间戳更新为整个集
但我需要在通过快照获取所有数据后调用一个方法。如何实现?我应该测试什么?
问题内容: servlet和过滤器生命周期之间有什么区别吗? 问题答案: 不,一个servlet和一个过滤器: 在上下文开始时实例化(一次) 该方法称为 他们处理每个请求-首先,它通过所有过滤器,然后到达servlet 当上下文被破坏时(即,当您的容器停止运行或从管理器控制台取消部署您的应用程序时),该方法被调用
问题内容: 我试图区分侦听器和适配器。 它们是否几乎相同,但是在侦听器中,您必须实现接口中的所有方法,但是对于适配器,您可以选择仅实现所需的方法,从而使代码更简洁,更易于阅读? 我还被告知适配器只能通过一种实现实现实例化,而您不能实例化侦听器,我对此并不完全了解。 有人可以解释使用哪一种更好,而另一种却不能用吗? 问题答案: WindowListener是强制您使用所有方法的方法,而WindowA
几天前,有一个问题,有人对包含借用数据本身的类型的可变引用的链接生命周期有问题。问题是使用与类型内借用数据相同生命周期的借用来提供对类型的引用。我试图重新创建问题: 示例代码 我在 中明确地注释了 。这不会编译: 的生存期类似于 的生存期为< code>VecRef 我注意到另一件我不明白的事情。如果我在
当在第四章讨论引用时,我们遗漏了一个重要的细节:Rust 中的每一个引用都有其 生命周期(lifetime),也就是引用保持有效的作用域。大部分时候生命周期是隐含并可以推断的,正如大部分时候类型也是可以推断的一样。类似于当因为有多种可能类型的时候必须注明类型,也会出现引用的生命周期以一些不同方式相关联的情况,所以 Rust 需要我们使用泛型生命周期参数来注明他们的关系,这样就能确保运行时实际使用的