我有一个Android聊天应用程序,它可以在本地SQLite DB和Firebase实时数据库中存储所有消息。
在RecyclerView中显示消息时,我从本地数据库中查询它们(因为本地存储了一些未存储在实时数据库中的附加数据)。
我需要实时更新显示的消息发送和读取状态,这是我从实时数据库中获得的。
为recycleler视图的onBindViewHolder中的每条消息设置一个值事件监听器是否可以?
这样我只会监听当前显示在屏幕上的消息中的更改,而不会从服务器获取整个消息列表。(正是我需要的)
2个问题: - 这个解决方案是好还是有更好的方法? - 我需要删除回收器视图中不可见的项目的侦听器。我怎么做?
我没有使用FirebaseUI(我知道它解决了我的问题),但我想从本地数据库而不是从服务器提供数据,只从firebase实时数据库获取一个字段的更新。
这个解决方案是好还是有更好的方法?
是的,不!我会建议你FirebaseUI绝对是最好的选择,但你已经提到过你不想使用它。因此,不使用FirebaseUI的事实,这似乎是最好的选择。 [我建议你直接从可以给你准确答案的Firebase人那里对此进行评论。]你也应该知道,如果一旦视图离开屏幕你没有删除回调,你最终会得到成千上万的听众(他们中的大多数是多余的)晃来晃去,吃掉了记忆,什么也没做。
我需要删除在回收器视图中已经不可见的项的侦听器。我怎么做?
很简单。您可以使用onViewDetachedFromWindow(MyViewHolder holder)
的recyclerView
方法,它为您提供即将从视图中删除的处理程序。您可以使用此调用来删除回调。
怎么样?
followRef.removeEventListener(followListener);
问题是 - 您需要引用回调以将其从该位置删除。你可以用两种方式做到这一点。如果你有太多不同的听众,你可以创建一个可以跟踪所有听众的hashmap
。只要有需要,您就可以获得听众的参考并将其删除。
另一种方式是:
@Override
public void onBindViewHolder(final MyViewHolder holder, int position) {
User user = data.get(position);
holder.name.setText(user.Name);
holder.surname.setText(user.Surname);
holder.id = user.id; //Id is same as the key used to point this user.
holder.followers.setText("Loading..");
DatabaseReference userFollowers = mRef.child(holder.id).child("Followers");
followListener = new ValueEventListener() {
@Override
public void onDataChange(DataSnapshot dataSnapshot) {
holder.followers.setText(String.valueOf(dataSnapshot.getValue()));
}
@Override
public void onCancelled(DatabaseError databaseError) {
}
};
userFollowers.addValueEventListener(followListener); //Adds a listener
}
@Override
public void onViewDetachedFromWindow(MyViewHolder holder) {
DatabaseReference followRef = mRef.child(holder.id).child("Followers");
followRef.removeEventListener(followListener); //Removes the listener
super.onViewDetachedFromWindow(holder);
}
该代码可能有轻微错误,我已按照此问题编写。没有测试过。但我希望你有这个主意。
问题:[即使这个问题有一个小问题谁是我仍然试图找到的最佳解决方案]:当你关闭包含recyclerView
的活动时,函数onViewDetachedFromWindow(MyViewHolder holder)
在特定时间不会被调用屏幕上的项目。因此,每当recyclerView
活动结束时,它都会保留很少的回调(与屏幕上可见项目的数量相同)。
即使我最近潜入Firebase数据库。欢迎任何改进/建议。
在Cloud Firestore中,您不需要在SQLite中保存内容,因为缓存已由Firestore处理,以防侦听器使用此类内容。
private ListenerRegistration registration;
然后在你的onBindView里面你可以这样做。
registration = query.addSnapshotListener(new EventListener<QuerySnapshot>() {
@Override
public void onEvent(QuerySnapshot documentSnapshots, FirebaseFirestoreException e) {
});
在onDetach
if(registration != null)
registration.remove();
根据this文档,它代表一个监听器,因此使用addSnapShotListener初始化它是正确的方法。另外我认为将侦听器放在ViewHolder中是非常合适的,这样你就可以使用它并在onViewAttachedFromWindow和onViewDetachedFromWindow内部处理它们。