我已经制作了一个自定义BaseAdapter类来在ListView中显示注册码。每当我向列表添加另一个密钥并调用notifyDataSetChanged()
时,ListView就会在视觉上更新。我的数据结构只是一个包含几个字符串和一个int的简单结构的ArrayList。但是,当我尝试清除密钥列表并调用notifyDataSetChanged()
时,视觉上没有任何结果。当我关闭并重新打开应用程序时,列表应该是空的。在致电notifyDataSetChanged()
之前,我现在致电notifyDataSetInvalidated()
。这样,只要我清除密钥,视觉效果就会正确更新,但Google documentation警告不要使用该方法,除非您完全使用该适配器完成。当我擦除它们后注册更多的键时,它们仍会显示在ListView中,这使得notifyDataSetInvalidated()
看起来像是一个有效的解决方案。如果我继续为ListView使用相同的BaseAdapter和ArrayList,是否存在与此方法相关的任何危险?有更好的解决方案吗?这是我的自定义BaseAdapter实现:
class KeyAdapter extends BaseAdapter implements Database.KeyRegistrationListener {
private ArrayList<Database.KeyDetails> keyInfo;
public KeyAdapter(ArrayList<Database.KeyDetails> keyInfo) {
this.keyInfo = keyInfo;
}
@Override
public int getCount() {
return keyInfo.size();
}
@Override
public Database.KeyDetails getItem(int position) {
return keyInfo.get(position);
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public View getView(int pos, View convertView, ViewGroup parent) {
TextView userID;
TextView appName;
TextView date;
TextView time;
if (convertView == null) {
convertView = getLayoutInflater().inflate(R.layout.registration_item, parent, false);
userID = (TextView) convertView.findViewById(R.id.user_id);
appName = (TextView) convertView.findViewById(R.id.app_name);
date = (TextView) convertView.findViewById(R.id.date_used);
time = (TextView) convertView.findViewById(R.id.time_used);
convertView.setTag(R.id.user_id, userID);
convertView.setTag(R.id.app_name, appName);
convertView.setTag(R.id.date_used, date);
convertView.setTag(R.id.time_used, time);
} else {
userID = (TextView) convertView.getTag(R.id.user_id);
appName = (TextView) convertView.getTag(R.id.app_name);
date = (TextView) convertView.getTag(R.id.date_used);
time = (TextView) convertView.getTag(R.id.time_used);
}
Database.KeyDetails key = getItem(pos);
userID.setText(key.userID);
appName.setText(key.appName);
date.setText(key.date);
time.setText(key.time);
return convertView;
}
@Override
public void notifyKeysUpdated(Database.KeyDetails newKeyDesc) {
if (newKeyDesc == null) {
keyInfo.clear();
notifyDataSetInvalidated();
notifyDataSetChanged();
} else{
keyInfo.add(newKeyDesc);
notifyDataSetChanged();
}
}
}
每当我向数据库添加密钥时,我的包装类会为SQLite数据库调用notifyKeysUpdated()
方法。如果我的数据库对象提供了监听器null
,则表示数据库中的所有密钥都已清除,并且ListView应该在视觉上为空。
修改
自从我开始使用notifyDataSetInvalidated()
以来,ListView不再显示任何内容,包括我注册新密钥时。
答案 0 :(得分:1)
在android中对BaseAdapter和ListView的源代码进行了一些研究后,这个问题(Android - What does adapter.notifyDataSetInvalidated do?)
您可能首先确定的是,您的数据并非完全绑定到适配器。通常,BaseAdapter只是一个接口集合,它不包含arraylist的任何字段。这意味着大小,提取数据在你身上。要指示数据集不再有效,您应该覆盖方法notifyDataSetInvalidated()。
我尝试将您的代码复制到我的项目中。方法notifyDataSetInvalidated()和notifyDataSetChanged()都将更新整个列表,这批准了arraylist并不完全绑定到适配器。它只是一个获取数据列表的适配器。我想知道谷歌文档没有明确解释如何处理这种方法。
答案 1 :(得分:0)
最后,问题只是在引用我的数据时出错。因为Java是一种非常安全的语言并且不允许显式指针,所以我想在这一行的某个时刻我制作了数据对象的副本,而不是将我要更新的那个传递给ListView。在简化我的代码并以最简单的方式创建数据并将数据传递到表之后,它就完全正常运行了。