如何知道两个嵌套的FirebaseIndexRecyclerAdapter完成数据加载?

时间:2017-08-08 01:19:50

标签: android firebase firebase-realtime-database firebaseui

我有一个非规范化的数据库,可以简化如下:

|__ 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)。我使用我的片段的onCreate()中的以下代码实现了这一点:

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的行:

<?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中显示menuItem的名称和价格,所以我不在此处包含它。

总而言之,这种设计会在RecyclerViews初始化期间导致奇怪的动画,跳跃等。我有两个问题:

  • 在设计方面有更好的选择吗? (相当于ExpandableListView的东西)

  • 如果没有,我如何检测初始数据加载是否完整(这样我可以隐藏所有内容,直到检索到最后一个menuItem)?我认为在addListenerForSingleValueEvent上致电menuItemRef无法在此工作。

2 个答案:

答案 0 :(得分: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?,我刚刚使用此信息(和示例)进行了更新。

答案 1 :(得分: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语句的条件永远不会变为真,app会挂起?