BaseAdapter无法从视图中正确删除项目?

时间:2016-08-18 18:47:29

标签: android listview baseadapter

我已经制作了一个自定义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不再显示任何内容,包括我注册新密钥时。

2 个答案:

答案 0 :(得分:1)

在android中对BaseAdapter和ListView的源代码进行了一些研究后,这个问题(Android - What does adapter.notifyDataSetInvalidated do?

您可能首先确定的是,您的数据并非完全绑定到适配器。通常,BaseAdapter只是一个接口集合,它不包含arraylist的任何字段。这意味着大小,提取数据在你身上。要指示数据集不再有效,您应该覆盖方法notifyDataSetInvalidated()。

我尝试将您的代码复制到我的项目中。方法notifyDataSetInvalidated()和notifyDataSetChanged()都将更新整个列表,这批准了arraylist并不完全绑定到适配器。它只是一个获取数据列表的适配器。我想知道谷歌文档没有明确解释如何处理这种方法。

答案 1 :(得分:0)

最后,问题只是在引用我的数据时出错。因为Java是一种非常安全的语言并且不允许显式指针,所以我想在这一行的某个时刻我制作了数据对象的副本,而不是将我要更新的那个传递给ListView。在简化我的代码并以最简单的方式创建数据并将数据传递到表之后,它就完全正常运行了。