我有一个非规范化的数据库,可以简化如下:
|__ 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
无法在此工作。
答案 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会挂起?