2016-12-07 69 views
14

Firebase數據庫用戶知道有兩個用於監聽Data的基本偵聽器:ValueEventListener和ChildEventListener。當我們傾聽一個對象時,它非常有效,但是當我們傾聽一些對象時變得相當困難。Android中的RecyclerView的ValueEventListener vs ChildEventListener

要指定問題,我們假設我們有HackerNews提要,並且我們會聽取例如Firebase中的「帖子」對象。

當然,我們在我們的應用程序中顯示帖子的RecyclerView,我認爲好的想法會使用FirebaseUI,但問題是我們想在更改服務器端或測試的情況下製作更抽象的應用程序。所以我們會使用一些適配器,但這是另一個question

我們有兩位聽衆,正如我提到的,問題是哪個更好

當我們使用ValueEventListener時,我們將獲得整個集合,但是如果有任何更改,就像一個用戶更改了帖子的內容,我們將不得不重新加載整個數據,這意味着通過昂貴的網絡傳輸發送更多字節。另一個問題是,當我們的用戶multilisteners,這裏是例子:

  • 郵政有用戶id,但我們要顯示他的名字,所以在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,因爲例如: - 很難添加加載指示符,因爲我們不知道所有數據何時到達。 - 用戶不斷刷新視圖,而新帖子而不是整個列表變得可見。 - 很難對這個集合進行排序,我們必須在適配器中這樣做。

問題

比我上面寫的什麼是使用火力與收集的最佳做法,也許更好的解決方案?

編輯

數據方案是這樣的:

"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

我犯了一個錯誤 - >火力地堡不ValueEventListener獲取整個數據如果有什麼東西改變。它只得到「delta」,here就是證明。

+0

你能告訴我你的數據庫模式? –

+0

我編輯的問題。 – ThirdMartian

+0

沒有你提到的那些。 [Firebase UI]中的FirebaseRecyclerAdapter(https:// github。com/firebase/FirebaseUI-Android)在這種情況下是最好的 –

回答

2

當與火力地堡收集數據的工作,你應該使用:

  • onChildAdded
  • onChildChanged
  • onChildRemoved
  • onChildMoved

你可能並不需要所有這些,但我發現通常是onChildAddedonChildRemoved往往是必不可少的。您必須對適配器中的數據進行排序和跟蹤,並將其傳遞給每個更新後的孩子的RecyclerView。

相比之下,您可以使用ValueEventListener並簡單地更新整個列表,但是就像您所說的那樣,這意味着該列表中的每個更新都會導致集合中的所有對象都會發送給您,這會耗費您的用戶數據並在Firebase上花費更多帶寬。如果您的數據經常更新,則不推薦這樣做。

Source

+0

請參閱我的編輯2 – ThirdMartian

+0

Firebase將隨時返回您的'ValueEventListener'連接到的任何位置的全部數據快照。 [來源](https://firebase.google.com/docs/database/android/read-and-write#listen_for_value_events) –

+0

是的,但它不會完全下載它,我只是得到整個數據快照,但數據庫內部將只發送「delta」 – ThirdMartian

12

有這幾個問題的關注(即性能,進度指示器,搬運等對它們進行排序的新數據)。當然,你應該想出一個解決方案,考慮到你的要求的優先級。 IMO既ValueEventListenerChildEventListener有自己的使用情況:

  1. ChildEventListener通常是同步回覆對象列表的推薦方式。這甚至在documentation on working with lists中提到:

    在處理列表時,應用程序應該監聽子事件而不是單個對象使用的值事件。

    這是因爲您的客戶端只接收到具有特定更新(添加或刪除)的更改的子,而不是每個更新的整個列表。因此,它允許更細粒度地處理列表的更新。

  2. ValueEventListener當您需要在修改孩子時處理整個列表時可能更有用。當您必須對RecyclerView中的列表進行排序時,就是這種情況。通過獲取整個列表,對其進行排序並刷新視圖的數據集,這樣做更容易。另一方面,使用ChildEventListener,進行排序更加困難,因爲每次更新事件只能訪問列表中的一個特定子項。

從一個性能點,因爲即使ValueEventListener知道的「增量」,而後再同步更新,我會傾向於認爲它是效率較低只在客戶端的,因爲客戶端必須對整個列表進行處理,但這仍然比網絡方面效率低下要好得多。

關於不斷刷新和進度指標,需要注意的最重要的事情是,火力地堡數據庫是實時數據庫,從而實時數據的恆定飼料的固有特性。如果不需要更新事件,則只需使用addListenerForSingleValueEvent方法即可僅讀取一次數據。如果你想在加載第一個快照顯示進度指示器,您還可以使用此:

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

    ... 
}); 
2

我會ANYDAY在這種情況下使用onchildAdded聽衆,也有它的一些優點,首先你已經找到了網絡操作,假設有100個帖子,即使有一個變化,你會得到所有的回調。而在onChildListener中,您將獲得唯一被更改的帖子的回調。那麼,你所能做的就是火力點的回調與回收方法意見像這樣::地圖 -

onChildAdded - >您必須轉換的DataSnap到您的類並調用recyclerView.notifyItemAdded()

onChildRemoved - - > recyclerView.notifyItemRemoved(INT)

onChildChanged - > recyclerView.notifyItemChanged(INT)

onChildMoved - >(你可能不需要這個,它是排序/優先級)

3

我有相同的確切問題(Android中的RecyclerView的ValueEventListener vs ChildEventListener)。

我使用的解決方案是雙方這種方式結合:

假設DBREF指向一個火力點DB的位置在我的職位是。

  1. 使用VEL(ValueEventListener)來填充recyclerview與當前數據的列表中DBREF。事情是這樣的:vel = dbref.addValueEventListener(vel);
  2. 一旦我有當前的數據在DBREF名單,我從刪除偵聽VEL DBREFdbref.removeEventListener(vel);。 如果您在步驟1中
  3. 使用dbref.addListenerForSingleValueEvent(vel); 編寫一個查詢查詢從現在開始,在過濾DBREF 插入新職位這是沒有必要的。事情是這樣的: query = dbref.orderByChild(post.createdat).startAt(System.currentTimeMillis())
  4. 附上CEL(ChildEventListener)到查詢只接收新的職位:query.addChildEventListener(cel);
相關問題