2017-08-08 46 views
0

我有可以如下簡化非規範化數據庫:如何知道兩個嵌套F​​irebaseIndexRecyclerAdapter完成數據加載?

|__ menu 
|  |___ menuKey1 
|    |___ subMenus (key list of subMenus belongs to menu) 
|    |___ other fields... 
| 
|__ subMenu 
|  |___ subMenuKey1 
|    |__ menuItems (key list of menuItems belongs to subMenu) 
|    |__ other fields... 
| 
|__ menuItem 
     |_____ ... 

我想在UI中顯示爲子菜單(外RecyclerView),每個都具有自己的菜單項列表(列表中的一個內外部RecyclerView的每行的RecyclerView)。

rootRef = FirebaseDatabase.getInstance().getReference(); 
DatabaseReference subMenuKeyRef = rootRef.child("menu").child(menuKey).child("subMenus"); 
DatabaseReference subMenuRef = rootRef.child("subMenu"); 
subMenuAdapter = new FirebaseIndexRecyclerAdapter<MySubMenu, SubMenuHolder>(
     MySubMenu.class, 
     R.layout.row_submenu, 
     SubMenuHolder.class, 
     subMenuKeyRef, 
     subMenuRef) { 
    @Override 
    protected void populateViewHolder(SubMenuHolder viewHolder, MySubMenu model, int position) { 
     String subMenuKey = getRef(position).getKey(); 
     DatabaseReference menuItemKeyRef = rootRef.child("subMenu").child(subMenuKey).child("menuItems"); 
     DatabaseReference menuItemRef = rootRef.child("menuItem"); 
     FirebaseIndexRecyclerAdapter menuItemAdapter = new FirebaseIndexRecyclerAdapter<MyMenuItem, MenuItemHolder>(
       MyMenuItem.class, 
       R.layout.row_menu_item, 
       MenuItemHolder.class, 
       menuItemKeyRef, 
       menuItemRef) { 
      @Override 
      protected void populateViewHolder(MenuItemHolder viewHolderx, MyMenuItem modelx, int positionx) { 
       viewHolderx.setName(modelx.getName()); 
       viewHolderx.setPrice(modelx.getPrice()); 
      } 
     }; 
     viewHolder.setName(model.getName()); 
     viewHolder.setMenuItemList(menuItemAdapter); 
    } 
}; 
subMenuList.setAdapter(subMenuAdapter); 

這裏是row_submenu.xml,這是外RecyclerView的一行:我有下面的代碼在我的片段onCreate()實現這個

<?xml version="1.0" encoding="utf-8"?> 
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" 
    xmlns:app="http://schemas.android.com/apk/res-auto" 
    android:layout_width="match_parent" 
    android:layout_height="wrap_content" 
    android:visibility="gone"> 

    <TextView 
     android:id="@+id/submenu_name" 
     android:layout_width="0dp" 
     android:layout_height="wrap_content" 
     android:textAllCaps="true" 
     android:textStyle="bold" 
     app:layout_constraintLeft_toLeftOf="parent" 
     app:layout_constraintRight_toRightOf="parent" 
     app:layout_constraintTop_toTopOf="parent" /> 

    <android.support.v7.widget.RecyclerView 
     android:id="@+id/submenu_menu_items" 
     android:layout_width="0dp" 
     android:layout_height="wrap_content" 
     android:paddingBottom="8dp" 
     app:layoutManager="android.support.v7.widget.LinearLayoutManager" 
     app:layout_constraintBottom_toBottomOf="parent" 
     app:layout_constraintLeft_toLeftOf="parent" 
     app:layout_constraintRight_toRightOf="parent" 
     app:layout_constraintTop_toBottomOf="@id/submenu_name" /> 

</android.support.constraint.ConstraintLayout> 

row_menu_item.xml只是表明在TextViews所以我不菜單項的名稱和價格」把它包括在這裏。

總之,這個設計會在RecyclerViews的初始化過程中引起奇怪的動畫,跳轉等。我有兩個問題:

  • 在設計方面有更好的選擇嗎? (相當於ExpandableListView)

  • 如果不是,我如何檢測初始數據加載是否完成(以便我可以隱藏所有內容,直到檢索到最後一個menuItem)?我認爲在menuItemRef上撥打addListenerForSingleValueEvent不會在這裏工作。

回答

0

我使用了兩個計數器來檢測異步檢索的結束。密鑰計數累計添加到totalItemCount中,因此它保存要在內部適配器內加載的項目總數。當內部適配器填充ViewHolder時,populatedItemCount將增加1,並將其當前值與totalItemCount進行比較。如果值相等,則意味着現在所有數據都被檢索到,並且其行中的父級RecyclerView和RecyclerViews可以顯示。

這裏是我的問題提供嵌套適配器的最後一個版本:

rootRef = FirebaseDatabase.getInstance().getReference(); 
DatabaseReference subMenuKeyRef = rootRef.child("menu").child(menuKey).child("subMenus"); 
DatabaseReference subMenuRef = rootRef.child("subMenu"); 
subMenuAdapter = new FirebaseIndexRecyclerAdapter<MySubMenu, SubMenuHolder>(
     MySubMenu.class, 
     R.layout.row_submenu, 
     SubMenuHolder.class, 
     subMenuKeyRef, 
     subMenuRef) { 
    int totalItemCount = 0; 
    int populatedItemCount = 0; 

    @Override 
    protected void populateViewHolder(SubMenuHolder viewHolder, MySubMenu model, int position) { 
     totalItemCount += model.getMenuItems().size(); 
     String subMenuKey = getRef(position).getKey(); 
     DatabaseReference menuItemKeyRef = rootRef.child("subMenu").child(subMenuKey).child("menuItems"); 
     DatabaseReference menuItemRef = rootRef.child("menuItem"); 
     FirebaseIndexRecyclerAdapter menuItemAdapter = new FirebaseIndexRecyclerAdapter<MyMenuItem, MenuItemHolder>(
       MyMenuItem.class, 
       R.layout.row_menu_item, 
       MenuItemHolder.class, 
       menuItemKeyRef, 
       menuItemRef) { 
      @Override 
      protected void populateViewHolder(MenuItemHolder viewHolderx, MyMenuItem modelx, int positionx) { 
       populatedMenuItemCount++; 
       viewHolderx.setName(modelx.getName()); 
       viewHolderx.setPrice(modelx.getPrice()); 

       // TODO - Find a resolution if this if never gets true 
       if (populatedMenuItemCount == totalMenuItemCount) { 
        (new Handler()).postDelayed(new Runnable() { 
         @Override 
         public void run() { 
          showSubMenuList(); 
         } 
        }, 500); 
       } 
      } 
     }; 
     viewHolder.setName(model.getName()); 
     viewHolder.setMenuItemList(menuItemAdapter); 
    } 
}; 
subMenuList.setAdapter(subMenuAdapter); 

我仍然不知道這一點比較兩個計數器的if語句。會不會有數據檢索以某種方式停止的情況,因此if語句的條件永遠不會變爲真,並且應用程序掛起?

0

FirebaseUI適配器有一個名爲onDataChanged()的方法來檢測數據更改何時完全加載。

查看source code on github。從那裏:

每次從數據庫中更新完成處理後,都會觸發此方法。所以第一次調用這個方法時,初始數據已經被加載 - 包括沒有數據可用的情況。每次下一次該方法被調用時,一個完整的更新(可能包含對多個子項目的更新)已經完成。

您通常會覆蓋此方法以隱藏加載指示符(初始加載後)或完成對UI元素的批量更新。

另請參閱:How to dismiss a progress bar even if there is no view to populate in the FirebaseListAdapter?,我剛更新了此信息(和樣本)。

+0

我知道什麼時候外部適配器的數據加載完成。但是每個條目在這裏創建另一個內部適配器我想知道什麼時候發生了最後一次內部數據加載完成,但是我不能,因爲它們都是異步的。 – Mehmed