使用FirebaseListAdapter填充ListView遇空项及记录数统计问题
看起来你遇到的两个问题(顶部空项、position统计总数无效)都是因为手动删除数据库记录后残留的空节点,以及对FirebaseListAdapter的使用细节没把握好,我来一步步帮你解决:
一、顶部空项的原因及解决
你手动删除两条记录后,Firebase实时数据库可能并没有彻底移除这些节点的key,只是清空了节点内的数据(或者节点还存在但没有任何字段)。FirebaseListAdapter会加载所有匹配query的节点,包括这些空节点,所以就出现了顶部的空项。
解决办法:
检查并清理数据库空节点
登录Firebase控制台,找到/Customer节点,查看是否存在只有key但没有profile相关字段(比如sFN、sTimeServiced)的空节点,直接删除这些节点即可。在Query中过滤空数据
即使数据库里有空节点,也可以通过Query过滤掉没有有效数据的项,比如我们可以过滤掉sTimeServiced字段为空或不存在的节点:Query query = myRef.orderByChild("sTimeServiced").startAt("");这样只会加载有
sTimeServiced字段且不为空的节点,空节点会被自动排除。
二、记录总数统计的正确方式
你用position变量统计总数是错误的,因为position是当前项在ListView中的索引(从0开始),而且如果有空项的话,这个值会包含空项的数量,最后得到的也只是最后一项的索引,不是总记录数。
正确做法:
FirebaseListAdapter本身提供了getCount()方法来获取当前加载的记录总数,但要注意这个方法需要等数据加载完成后调用才准确,所以我们可以通过AdapterDataObserver来监听数据变化,实时更新总数:
// 设置适配器后注册观察者 adapter.registerAdapterDataObserver(new AdapterDataObserver() { @Override public void onChanged() { super.onChanged(); totalRecords = adapter.getCount(); TextView tvCount = findViewById(R.id.Count); tvCount.setText(Integer.toString(totalRecords)); } });
同时要删除你在populateView里更新Count TextView的代码,因为那会每次刷新列表项都覆盖总数,最后显示的只是最后一项的position,不是总数。
三、修改后的完整代码片段
ListView lv; static int totalRecords; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); totalRecords = 0; FirebaseListAdapter<Profile> adapter; lv = findViewById(R.id.listview); lv.setAdapter(null); String sPath = "/Customer/"; sPath = sPath.replaceAll("\\s", ""); if( database != null) { DatabaseReference myRef = database.getReference(sPath); // 过滤空节点的Query Query query = myRef.orderByChild("sTimeServiced").startAt(""); if (query != null) { totalRecords = 0; FirebaseListOptions<Profile> options = new FirebaseListOptions.Builder<Profile>() .setQuery(query, Profile.class) .setLayout(android.R.layout.simple_selectable_list_item) .setLifecycleOwner(this) .build(); adapter = new FirebaseListAdapter<Profile>(options){ @Override protected void populateView(View view, Profile p, int position) { // 只负责填充当前列表项的内容 ((TextView) view.findViewById(android.R.id.text1)).setText(p.sFN + " " + p.sLN + " (" + p.sTelephone + ")"); } }; lv.setAdapter(adapter); lv.setStackFromBottom(true); // 注册观察者统计总数 adapter.registerAdapterDataObserver(new AdapterDataObserver() { @Override public void onChanged() { super.onChanged(); totalRecords = adapter.getCount(); TextView tvCount = findViewById(R.id.Count); tvCount.setText(Integer.toString(totalRecords)); } }); } } }
额外注意点
- 确保你的
Profile类的字段名和数据库中的字段完全匹配(包括大小写),否则FirebaseListAdapter无法正确解析数据,也可能导致空项。 - 如果
setStackFromBottom(true)不是你需要的显示逻辑,可以考虑去掉,避免列表显示位置的混淆。
内容的提问来源于stack exchange,提问作者pumori tech

