繁体   English   中英

Android中的RecyclerView的ValueEventListener与ChildEventListener

[英]ValueEventListener vs ChildEventListener for RecyclerView in Android

火力地堡数据库的用户知道,有听数据两个基本的听众: ValueEventListenerChildEventListener 当我们听一个对象时它很有用,但是当我们听一些收集时变得非常困难。

要指定问题,让我们假设我们有HackerNews提要,我们在Firebase中监听例如“posts”对象。

当然我们在我们的应用程序中使用RecyclerView来显示帖子,我认为好主意是使用FirebaseUI,但问题是我们想要在更改服务器端或测试时制作更抽象的应用程序。 所以我们会使用一些适配器,但这是另一个问题

正如我所提到的,我们有两个听众,问题哪个更好

当我们使用ValueEventListener我们将获得整个集合,但是如果有任何更改,例如一个用户更改了帖子的内容,我们将不得不重新加载整个数据,这意味着通过昂贵的网络传输发送更多字节。 另一个问题是当我们使用multilisteners时,这里是示例:

Post有userId,但我们想显示他的名字,所以在onDataChanged方法中我们获取用户数据,如下所示:

postsReference.addValueEventListener(new ValueEventListener() {
    @Override
    public void onDataChange(DataSnapshot dataSnapshot) {
        for (DataSnapshot data : dataSnapshot.getChildren()) {
            Post post = data.getValue(Post.class);   
            usersReference.child(post.getUserId()).addListenerForSingleValueEvent(new ValueEventListener() {

                @Override
                public void onDataChange(DataSnapshot dataSnapshot) {
                    // Here we have user data
                }

                @Override
                public void onCancelled(FirebaseError firebaseError) {

                }
            });
        }
    }

    @Override
    public void onCancelled(FirebaseError firebaseError) {
    }
});

您可以看到,现在我们必须将每个帖子分别添加到RecyclerView ,这将为我们提供可能我们应该使用ChildEventListener线索。

所以现在当我们使用``ChildEventListener时问题是一样的 - 我们必须将每个帖子分别添加到RecyclerView但是当有人更改帖子内容时,firebase只向我们发送这一帖子,这意味着通过网络传输的数据更少。

我们不喜欢单独向RecyclerView添加帖子,因为例如: - 添加加载指示器很困难,因为我们不知道所有数据何时到来。 - 用户可以获得不断刷新的视图,而新的帖子而不是整个列表变得可见。 - 很难对该集合进行排序,我们将不得不在适配器中进行排序。

将firebase用于收集的最佳实践是什么,也许比我上面写的更好的解决方案?

编辑

数据方案如下所示:

"posts" : {
    "123456" : {
        "createdAt" : 1478696885622,
        "content" : "This is post content",
        "title" : "This is post title",
        "userId" : "abc"
    },
    "789012" : {
        "createdAt" : 1478696885622,
        "content" : "This is post content 2",
        "title" : "This is post title 2",
        "userId" : "efg"
    }
}
"users" : {
    "abc" : {
        "name" : "username1"
    },
    "efg" : {
        "name" : "username2"
    }
}

编辑2

我犯了一个错误 - >当某些内容发生变化时,Firebase不会在ValueEventListener获取整个数据。 它只有“三角洲”, 是证据。

这个问题有几个问题(即绩效,进度指标,处理新数据,如排序)。 当然,您应该提出一个考虑到您的要求优先级的解决方案。 IMO既ValueEventListenerChildEventListener有自己的使用情况:

  1. ChildEventListener一般是同步回复对象列表的推荐方式。 使用列表文档中甚至提到了这一点:

    使用列表时,应用程序应该侦听子事件,而不是用于单个对象的值事件。

    这是因为您的客户端仅接收具有特定更新(添加或删除)的已更改子项,而不是每次更新时的整个列表。 因此,它允许更精细地处理列表的更新。

  2. 当您需要在修改子项时处理整个列表时, ValueEventListener会更有用。 必须在RecyclerView对列表进行排序时就是这种情况。 通过获取整个列表,对其进行排序并刷新视图的数据集,可以更轻松地完成此操作。 另一方面,使用ChildEventListener ,进行排序更加困难,因为每次更新事件只能访问列表中的一个特定子项。

性能的角度来看,即使ValueEventListener在同步更新时也意识到“delta”,我倾向于认为它仅在客户端效率较低,因为客户端必须在整个列表,但这仍然比在网络端具有低效率要好得多。

关于持续刷新和进度指标 ,最重要的是Firebase数据库是一个实时数据库,因此实时数据的持续馈送是一个固有的特性。 如果不需要更新事件,则只需使用addListenerForSingleValueEvent方法只读取一次数据。 如果要在加载第一个快照时显示进度指示器,也可以使用此选项:

// show progress indicator
postsReference.addListenerForSingleValueEvent(new ValueEventListener() {
    @Override
    public void onDataChange(DataSnapshot dataSnapshot) {
        // load initial data set
        // hide progress indicator when done loading
    }

    ...
});

我有同样的确切问题( ValueEventListener VS ChildEventListenerRecyclerView Android中)。

我使用的解决方案是这样结合:

假设dbref指向我的帖子所在的firebase数据库位置。

  1. 使用电平 (ValueEventListener)来填充当前数据的DBREF列表中recyclerview。 像这样: vel = dbref.addValueEventListener(vel);
  2. 一旦我在DBREF当前数据的列表,我移除DBREF听者VEL: dbref.removeEventListener(vel); 如果您使用dbref.addListenerForSingleValueEvent(vel); 在第1步。
  3. 编写一个Query 查询来过滤从现在开始在dbref中插入的新帖子。 像这样: query = dbref.orderByChild(post.createdat).startAt(System.currentTimeMillis())
  4. 附加一个cel (ChildEventListener)来查询只接收新帖子: query.addChildEventListener(cel);

在Firebase上处理收集数据时,您应该使用:

  • onChildAdded
  • onChildChanged
  • onChildRemoved
  • onChildMoved

您可能不需要所有这些,但我发现通常onChildAddedonChildRemoved通常是必不可少的。 您必须对适配器中的数据更改进行排序和跟踪,并将其传递回每个更新的子项上的RecyclerView。

相比之下,你可以使用ValueEventListener并简单地更新整个列表,但是就像你说的那样,这意味着该列表中的每次更新都会导致集合中的所有对象被发送给你,这将花费你的用户数据并花费你更多Firebase上的带宽。 如果您的数据经常更新,则不建议这样做。

资源

我会在任何一天使用onchildAdded监听器,在这种情况下,它有几个优点,首先你已经想出了网络操作,假设有100个帖子,即使一个被改变,你将得到所有这些回调。 而在onChildListener中,您将获得唯一更改的帖子的回调。 所以你可以做的是将firebase的回调映射到像这样的回收器视图方法:: -

onChildAdded - >你必须将dataSnapshot转换为你的类并调用recyclerView.notifyItemAdded()

onChildRemoved - > recyclerView.notifyItemRemoved(int)

onChildChanged - > recyclerView.notifyItemChanged(int)

onChildMoved - >(你可能不需要这个,它用于订购/优先级)

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM