Android中的RecyclerView的ValueEventListener vs ChildEventListener [英] ValueEventListener vs ChildEventListener for RecyclerView in Android

查看:170
本文介绍了Android中的RecyclerView的ValueEventListener vs ChildEventListener的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

Firebase数据库用户知道有两个监听数据的基本侦听器:ValueEventListener和ChildEventListener。当我们听一个对象的时候它很好用,但是当我们听一些集合的时候变得相当困难。



要指定问题,让我们假设我们有HackerNews提要, Firebase中的发布对象。

当然,我们的应用程序中有显示帖子的RecyclerView,我认为好的想法是使用FirebaseUI,但问题是,我们希望做更多的抽象应用程序改变服务器端或测试。所以我们会使用一些适配器,但这是另一个问题。 / p>

我们有两个听众,问题是哪个更好



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


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

      (DataSnapshot data:dataSnapshot.getChildren()){
    发布后的内容=新的ValueEventListener(){
    @Override
    public void onDataChange(DataSnapshot dataSnapshot){
    data.getValue(Post.class);
    usersReference.child(post.getUserId())。addListenerForSingleValueEvent(new ValueEventListener(){
    $ b @Override
    public void onDataChange(DataSnapshot dataSnapshot){
    //这里我们有用户数据
    }

    @Override
    public void onCancelled(FirebaseError firebaseError){

    }
    });
    }
    }

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




现在我们必须添加每个帖子到RecyclerView分开,这将给我们提示,也许我们应该使用ChildEventListener。

所以现在当我们使用ChildEventListener的问题是相同的 - 我们必须添加每个发送到RecyclerView分开,但当有人改变发布内容,firebase发送给我们只有这一个职位,这意味着更少的数据通过网络。



我们不喜欢分别添加帖子到RecyclerView,因为例如:
- 很难添加加载指示符,因为我们不知道所有数据何时到达。
- 用户不断刷新视图,而新帖子,而不是整个列表变得可见。
- 很难对这个集合进行排序,我们将不得不这样做,也许在适配器。



问题



使用firebase进行收集的最佳实践,也许比我上面写的更好的解决方案是什么?
$ b 编辑

数据方案如下所示:

  :{
123456:{
createdAt:1478696885622,
content:这是帖子内容,
title:这是帖子标题,
userId:abc
},
789012:{
createdAt:1478696885622,
content:This post内容2,
title:这是帖子标题2,
userId:efg
}
}
users:{
abc:{
name:username1
},
efg:{
name:username2
}
}

编辑2



我犯了一个错误 - Firebase在某些事情发生变化时,并没有在ValueEventListener中获取整个数据。它只获得三角洲,此处是证明。

解决方案

这个问题有几个问题(即性能,进度指标,处理新数据,如排序) 。当然,你应该想出一个解决方案,考虑到你的要求的优先级。 IMO ValueEventListener ChildEventListener 有它们的用例:


  1. ChildEventListener 通常是同步对象列表的推荐方式。这甚至在有关使用列表的文档中提到:


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

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

  2. 当你需要在修改一个孩子的时候处理整个列表的时候更有用。当您必须对 RecyclerView 中的列表进行排序时,就是这种情况。通过获取整个列表,对其进行排序并刷新视图的数据集,这样做更容易。另一方面,使用 ChildEventListener ,进行排序更加困难,因为每次更新事件只能访问列表中的一个特定子项。


性能的观点来看,即使 ValueEventListener 意识到delta同步更新时,我倾向于认为它只是在客户端效率较低,因为客户端必须在整个清单,但这仍然比在网络方面效率低下更好。

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

  //显示进度指示器
postsReference.addListenerForSingleValueEvent(new ValueEventListener(){
@Override
public void onDataChange(DataSnapshot dataSnapshot){
//载入初始数据集
//完成后隐藏进度指示器加载
}

...
});


Firebase Database users know that there are two basic listeners for listening Data: ValueEventListener and ChildEventListener. It works great when we listen for one object, but becomes quite difficult when we listen for some collection.

To specify question, let's imagine that we have HackerNews feed, and we listen e.g. "posts" object in Firebase.

Of course we have RecyclerView in our app for displaying posts and I think good idea would be using FirebaseUI, but the problem is that we want to make more abstract application in case of changing server side or tests. So we would use some adapters, but this is another question.

We have two listeners as I mentioned, question is which is better?

When we use ValueEventListener we will get whole collection, but in case of any changes, like one user changed content of the post, we will have to reload whole data, which means more bytes sending via expensive network transfer. Another problem is when we user multilisteners, and here is example:

  • Post has userId, but we want to display his name, so in onDataChanged method we have fetch user data, like this:

    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) {
         }
    });
    

You can see that now we have to add each post to RecyclerView seperately, which would give us clue that maybe we should use ChildEventListener.

So now when we use ChildEventListener the problem is the same - we have to add each post to RecyclerView separately but when someone changes post content, firebase sends to us only this one post, which means less data via network.

We don't like adding post separately to RecyclerView, because e.g.: - It's hard to add loading indicator, cause we don't know when all data comes. - Users gets constantly refreshing view, while new posts comes instead of whole lists becomes visible. - It's hard to sort that collection, we will have to do that maybe in adapter.

Question

What are best practices for using firebase with collection, and maybe better solutions than I wrote above?

EDIT

Data scheme would look like this:

  "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"
    }
  }

EDIT 2

I made one mistake -> Firebase is not fetching whole data in ValueEventListener when something has changed. It gets only "delta", here is proof.

解决方案

There are several concerns in this question (namely performance, progress indicator, handling new data such as sorting them). Naturally you should come up with a solution that takes into consideration the priority of your requirements. IMO both ValueEventListener and ChildEventListener have their use cases:

  1. ChildEventListener is generally the recommended way of sync'ing lists of objects. This is even mentioned in the documentation on working with lists:

    When working with lists, your application should listen for child events rather than the value events used for single objects.

    This is because your client only receives the changed child with the specific update (addition or removal) as opposed to the whole list on every update. Therefore, it allows a more granular level of handling of the updates to the list.

  2. ValueEventListener can be more useful when you need to process the entire list upon modification of a child. This is the case when you have to sort the list in your RecyclerView. It's much more easier to do this by getting the entire list, sorting it and refresh the data set of the view. On the other hand, using a ChildEventListener, it's more difficult to do the sorting because you only have access to one specific child in the list per update event.

From a performance point of view, given that even ValueEventListener is aware of the "delta" while sync'ing the update, I would tend to think of it as less efficient only on the client side, because the client has to do the processing on the entire list, but this is still much better than having the inefficiency at the network side.

Regarding constant refresh and progress indicators, the most important thing to note is that the Firebase database is a realtime database, hence a constant feed of realtime data is an inherent characteristic. If update events are not needed, you can simply use the addListenerForSingleValueEvent method to read the data only once. You can also use this if you want to display a progress indicator upon loading the first snapshot:

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

    ...
});

这篇关于Android中的RecyclerView的ValueEventListener vs ChildEventListener的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆