使用来自 firebase 的数据创建 ExpandableListView

Posted

技术标签:

【中文标题】使用来自 firebase 的数据创建 ExpandableListView【英文标题】:Creating ExpandableListView with data from firebase 【发布时间】:2021-01-23 11:22:19 【问题描述】:

我正在创建一个任务管理器应用。我在ExpandableListView 中显示这些任务时遇到问题,我正在使用它,因为每个任务都可能有子任务。这是我的数据库结构:

.

ExpandableListView 适配器可能运行良好。但是我在 fillData() 方法中从 firebase 读取数据时遇到问题。

ActivityExpandableListView

public class Tasks extends AppCompatActivity 

    ExpandableListView expandableListView;
    CustomExpandableListAdapter expandableListAdapter;

    List<String> tasks;
    Map<String, List<String>> subtasks;

    private FirebaseDatabase firebasedatabase;
    private DatabaseReference databaseReference;

    @Override
    protected void onCreate(Bundle savedInstanceState) 
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_tasks);

        BottomNavigationView bottomNav = findViewById(R.id.bottom_nav);
        bottomNav.setSelectedItemId(R.id.tasks);
        expandableListView = (ExpandableListView) findViewById(R.id.tasks_list);

        firebasedatabase = FirebaseDatabase.getInstance();
        databaseReference = firebasedatabase.getReference("Tasks");
        fillData();
        expandableListAdapter = new CustomExpandableListAdapter(this, tasks, subtasks);
        expandableListView.setAdapter(expandableListAdapter);




        bottomNav.setOnNavigationItemSelectedListener(new BottomNavigationView.OnNavigationItemSelectedListener() 
            @Override
            public boolean onNavigationItemSelected(@NonNull MenuItem item) 
                switch (item.getItemId())
                    case R.id.notes:
                        startActivity(new Intent(getApplicationContext(), Notes.class));
                        overridePendingTransition(0,0);
                        return true;
                    case R.id.tasks:
                        return true;
                    case R.id.goals:
                        startActivity(new Intent(getApplicationContext(), Goals.class));
                        overridePendingTransition(0,0);
                        return true;
                    case R.id.statistics:
                        startActivity(new Intent(getApplicationContext(), Statistics.class));
                        overridePendingTransition(0,0);
                        return true;
                    case R.id.add:
                        startActivity(new Intent(getApplicationContext(), Add.class));
                        overridePendingTransition(0,0);
                        return true;

                
                return false;
            
        );

    

    public void fillData()
    
        databaseReference.addValueEventListener(new ValueEventListener() 

            @Override
            public void onDataChange(@NonNull DataSnapshot dataSnapshot) 
                if(tasks.size() > 0) tasks.clear();
                for(DataSnapshot ds : dataSnapshot.getChildren())
                
                  String taskName = (String) ds.child("Tasks").getValue();
                  tasks.add(taskName);
                

                expandableListAdapter.notifyDataSetChanged();
            

            @Override
            public void onCancelled(@NonNull DatabaseError databaseError) 

            
        );
    

ExpandableListView 适配器:

public class CustomExpandableListAdapter extends BaseExpandableListAdapter 

private Context context;
private List<String> listHeader;
private Map<String, List<String>> listChildren;
public CustomExpandableListAdapter(Context context, List<String> listHeader, Map<String, List<String>> listChildren)
    this.context = context;
    this.listHeader = listHeader;
    this.listChildren = listChildren;


@Override
public int getGroupCount() 
    return this.listHeader.size();


@Override
public int getChildrenCount(int groupPosition) 
    return this.listChildren.get(listHeader.get(groupPosition)).size();


@Override
public Object getGroup(int groupPosition) 
    return this.listHeader.get(groupPosition);


@Override
public Object getChild(int groupPosition, int childPosition) 
    return this.listChildren.get(this.listHeader.get(groupPosition));


@Override
public long getGroupId(int groupPosition) 
    return groupPosition;


@Override
public long getChildId(int groupPosition, int childPosition) 
    return childPosition;


@Override
public boolean hasStableIds() 
    return false;


@Override
public View getGroupView(int groupPosition, boolean isExpanded, View convertView, ViewGroup parent) 
    String header = (String) getGroup(groupPosition);

    if(convertView == null)
    
        LayoutInflater inflater = (LayoutInflater) context.getSystemService(context.LAYOUT_INFLATER_SERVICE);
        convertView = inflater.inflate(R.layout.list_view_header, null);
    

    TextView headerOfGroup = (TextView) convertView.findViewById(R.id.header_text);
    headerOfGroup.setText(header);
    return convertView;


@Override
public View getChildView(int groupPosition, int childPosition, boolean isLastChild, View convertView, ViewGroup parent) 
    String child = (String) getChild(groupPosition, childPosition);

    if(convertView == null)
    
        LayoutInflater inflater = (LayoutInflater) context.getSystemService(context.LAYOUT_INFLATER_SERVICE);
        convertView = inflater.inflate(R.layout.list_view_child, null);
    

    TextView childText = (TextView) convertView.findViewById(R.id.child_text);
    childText.setText(child);
    return convertView;


@Override
public boolean isChildSelectable(int groupPosition, int childPosition) 
    return true;

【问题讨论】:

【参考方案1】:

据我所知,您问题中的相关代码是:

firebasedatabase = FirebaseDatabase.getInstance();
databaseReference = firebasedatabase.getReference("Tasks");
databaseReference.addValueEventListener(new ValueEventListener() 
    @Override
    public void onDataChange(@NonNull DataSnapshot dataSnapshot) 
        if(tasks.size() > 0) tasks.clear();
        for(DataSnapshot ds : dataSnapshot.getChildren())
        
          String taskName = (String) ds.child("Tasks").getValue();
          tasks.add(taskName);
        

        expandableListAdapter.notifyDataSetChanged();
    

    @Override
    public void onCancelled(@NonNull DatabaseError databaseError) 
    
);

您的代码将侦听器附加到/Tasks,然后循环其子节点,并获取每个子节点的Tasks 子节点。但是,如果我们查看您的数据库结构,则每个任务下都没有 Tasks 子节点。所以这可能会导致一个空项目列表,对于/Tasks 的每个子节点一次


如果您想显示/Tasks 的每个子节点的键(所以屏幕截图中的make a aolicationShoping),您需要使用每个子节点的getKey()

firebasedatabase = FirebaseDatabase.getInstance();
databaseReference = firebasedatabase.getReference("Tasks");
databaseReference.addValueEventListener(new ValueEventListener() 
    @Override
    public void onDataChange(@NonNull DataSnapshot dataSnapshot) 
        if(tasks.size() > 0) tasks.clear();
        for(DataSnapshot ds : dataSnapshot.getChildren()) 
            String taskName = ds.getKey();
            tasks.add(taskName);
        

        expandableListAdapter.notifyDataSetChanged();
    

    @Override
    public void onCancelled(@NonNull DatabaseError databaseError) 
        throw databaseError.toException()
    
);

如果要显示每个子节点的Subtasks 下的所有值,则需要为此添加另一个嵌套循环:

firebasedatabase = FirebaseDatabase.getInstance();
databaseReference = firebasedatabase.getReference("Tasks");
databaseReference.addValueEventListener(new ValueEventListener() 
    @Override
    public void onDataChange(@NonNull DataSnapshot dataSnapshot) 
        if(tasks.size() > 0) tasks.clear();
        for(DataSnapshot taskSnapshot: dataSnapshot.getChildren()) 
            DataSnapshot subtasksSnapshot = taskSnapshot.child("Subtasks");
            for(DataSnapshot subtaskSnapshot: subtasksSnapshot.getChildren()) 
                String taskName = subtaskSnapshot.getValue(String.class);
                tasks.add(taskName);
            
        

        expandableListAdapter.notifyDataSetChanged();
    

    @Override
    public void onCancelled(@NonNull DatabaseError databaseError) 
        throw databaseError.toException()
    
);

【讨论】:

可能你解决了我的问题,但我有一个错误 DataSnapshot subtasksSnapshot: taskSnapshot.child("Subtasks");

以上是关于使用来自 firebase 的数据创建 ExpandableListView的主要内容,如果未能解决你的问题,请参考以下文章

ListView 显示来自 Firebase 问题的所有数据

使用打字稿界面来表示来自 Firebase 的结构化数据?

过滤和显示来自 firebase 数据库的搜索栏结果

Firebase Auth 使用来自不同类的文本输入创建新用户

颤动的谷歌地图无法显示来自firebase的标记

如何从 Firebase 数据创建数组?