recyclerview的onBindViewHolder内的Android Firebase监听器

Posted

技术标签:

【中文标题】recyclerview的onBindViewHolder内的Android Firebase监听器【英文标题】:Android Firebase listener inside onBindViewHolder of recyclerview 【发布时间】:2017-03-28 03:59:46 【问题描述】:

我有一个 android 聊天应用程序,它将所有消息都存储在本地 SQLite 数据库和 Firebase 实时数据库中。

在 RecyclerView 中显示消息时,我从本地数据库中查询它们(因为本地存储了一些额外的数据,而不是存储在实时数据库中)。

我需要实时更新显示的消息发送和读取状态,这是我从实时数据库获得的。

在recycler view的onBindViewHolder里面给每条消息设置一个value事件监听器会不会好?

这样我只听当前显示在屏幕上的消息的变化,而不是从服务器获取整个消息列表。(正是我需要的)

2 个问题: - 这个解决方案很好还是有更好的方法? - 我需要删除在回收站视图中已经不可见的项目的侦听器。我该怎么做?

我不使用 FirebaseUI(我知道它可以解决我的问题),但我想从我的本地数据库而不是服务器中显示数据,并且只从 firebase 实时获取一个字段的更新数据库。

【问题讨论】:

【参考方案1】:

这个解决方案好还是有更好的方法?

是的,不是的!我会建议你使用 FirebaseUI,这绝对是最好的选择,但你已经提到你不想使用它。因此,考虑到不使用 FirebaseUI 的事实,这似乎是最好的选择。 [我建议您直接从能够为您提供准确答案的 Firebase 人员那里获取有关此问题的评论。]您还应该知道,如果您在视图离开屏幕后不删除回调,你最终会得到成百上千的听众,(其中大多数是多余的)悬而未决并吃掉记忆,实际上什么都不做。

我需要删除在回收站视图中已经不可见的项目的侦听器。我该怎么做?

很简单。您可以使用recyclerViewonViewDetachedFromWindow(MyViewHolder holder) 方法,它为您提供即将从视图中删除的处理程序。您可以使用此调用来删除回调。

怎么做?

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 数据库。欢迎对答案提出任何改进/建议。

【讨论】:

【参考方案2】:

在 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 中操作它。

【讨论】:

以上是关于recyclerview的onBindViewHolder内的Android Firebase监听器的主要内容,如果未能解决你的问题,请参考以下文章

recyclerview 内的 RecyclerView 只显示父 recyclerview 的最后一项

关于RecyclerView

RecyclerView详解

RecyclerView

RecyclerView小结

水平 RecyclerView 内的水平 RecyclerView