使用数据作为 Map 的 notifyDataSetChanged 后 Android ListView 不刷新

Posted

技术标签:

【中文标题】使用数据作为 Map 的 notifyDataSetChanged 后 Android ListView 不刷新【英文标题】:Android ListView not refreshing after notifyDataSetChanged with data as Map 【发布时间】:2014-08-18 16:10:37 【问题描述】:

我使用了带有地图值的列表适配器作为数据。当我使用adapter.notifyDataSetChanged(); 时,列表中的数据没有更新。但是,如果我用 ArrayList 替换 Map 一切正常。以下是我的适配器代码。

public class CategoryAdapter extends BaseAdapter 
ArrayList<Category> list = new ArrayList<Category>();
Context context;

public CategoryAdapter(Context context, Map<String, Category> categories) 
    this.context = context;
    list.clear();
    list.addAll(categories.values());


@Override
    public int getCount() 
        return list.size();
    

@Override
    public View getView(int position, View convertView, ViewGroup parent) 
        final ViewHandler handler;

        LayoutInflater inflater = (LayoutInflater) context
                .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        if (convertView == null) 
            convertView = inflater.inflate(R.layout.category_list_item, null);
            handler = new ViewHandler();
            handler.name = (TextView) convertView.findViewById(R.id.name);
            handler.count = (TextView) convertView.findViewById(R.id.count);
            convertView.setTag(handler);
         else 
            handler = (ViewHandler) convertView.getTag();
        
        Category category = list.get(position);
        handler.name.setText(category.getMenuName());
        handler.count.setText(category.getCount() + "");
        if (category.getCount() <= 0) 
            handler.count.setVisibility(View.INVISIBLE);
         else 
            handler.count.setVisibility(View.VISIBLE);
        

        return convertView;
    

我的活动代码是

private void loadCategories() 
    sampleDB = openOrCreateDatabase(AppConstants.DB_NAME, MODE_PRIVATE,
            null);
    Cursor menuCursor = sampleDB.rawQuery("select * from menu", null);

    categories.clear();
    while (menuCursor.moveToNext()) 
        String menu = menuCursor.getString(menuCursor
                .getColumnIndex("name"));
        String id = menuCursor.getString(menuCursor.getColumnIndex("id"));
        Category category = new Category(menu, id);
        categories.put(id, category);
    
    menuCursor.close();
    categoryAdapter.notifyDataSetChanged();

oncreate() 方法中我已经声明适配器如下

categoryAdapter = new CategoryAdapter(context, categories);
        categoryList.setAdapter(categoryAdapter);
        loadCategories();

每次我点击刷新按钮时,它都会调用loadCategories(); 方法。 在相同的代码中,如果我用 ArrayList 替换 Map 一切正常。

现在我的问题是为什么 List 不刷新 Map 值。请给我澄清一下。

提前致谢。

【问题讨论】:

你在哪里添加/更改categoryAdapter的内容 对不起。 categoryAdapter 是使用 categories 映射声明的。请参阅我更新的问题。每次我点击刷新按钮 loadCategories() 都会调用。并且在那个类别中值发生变化。 onCreate() 唯一创建CategoryAdapter? 实例的地方。如果是这样,您的categoryAdapterArrayList&lt;Category&gt; list 不会更新 是的,oncreate() 是为CategoryAdapter 创建实例的唯一地方。即使我使用notifyDataSetChanged()ArrayList&lt;Category&gt; list 也不会生效。 那是因为你没有更新适配器实例的列表。让我想出一个我认为可行的答案。请稍等片刻... 【参考方案1】:

您必须向 CategoryAdapter 添加一个方法来更改实例的列表,如下所示

public class CategoryAdapter extends BaseAdapter 
ArrayList<Category> list = new ArrayList<Category>();
Context context;

public CategoryAdapter(Context context, Map<String, Category> categories) 
    this.context = context;
    list.clear();
    list.addAll(categories.values());


@Override
public int getCount() 
    return list.size();


//ADD THIS METHOD TO CHANGE YOUR LIST
public void addItems(Map<String, Category> categories)
    list.clear();
    list.addAll(categories.values());


@Override
public View getView(int position, View convertView, ViewGroup parent) 
    final ViewHandler handler;

    LayoutInflater inflater = (LayoutInflater) context
            .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
    if (convertView == null) 
        convertView = inflater.inflate(R.layout.category_list_item, null);
        handler = new ViewHandler();
        handler.name = (TextView) convertView.findViewById(R.id.name);
        handler.count = (TextView) convertView.findViewById(R.id.count);
        convertView.setTag(handler);
     else 
        handler = (ViewHandler) convertView.getTag();
    
    Category category = list.get(position);
    handler.name.setText(category.getMenuName());
    handler.count.setText(category.getCount() + "");
    if (category.getCount() <= 0) 
        handler.count.setVisibility(View.INVISIBLE);
     else 
        handler.count.setVisibility(View.VISIBLE);
    

    return convertView;


并像这样更改您的 loadCategories(请注意,我在 notifyDataSetChanged() 之前调用 addItems()

private void loadCategories() 
sampleDB = openOrCreateDatabase(AppConstants.DB_NAME, MODE_PRIVATE,
        null);
Cursor menuCursor = sampleDB.rawQuery("select * from menu", null);

categories.clear();
while (menuCursor.moveToNext()) 
    String menu = menuCursor.getString(menuCursor
            .getColumnIndex("name"));
    String id = menuCursor.getString(menuCursor.getColumnIndex("id"));
    Category category = new Category(menu, id);
    categories.put(id, category);

menuCursor.close();

//ADD CALL TO addItems TO UPDATE THE LIST OF THE categoryAdapter instance
categoryAdapter.addItems(categories);
categoryAdapter.notifyDataSetChanged();

【讨论】:

工作得很好。谢谢。 不使用addItems() 如果我用public CategoryAdapter(Context context, ArrayList&lt;Category&gt; categories) this.context = context; list=categories; 替换构造函数,它可以正常工作,但不能使用Map。你能解释一下吗? 你在loadCategories()中调用那个构造函数吗? 没有。更新类别 ArrayList 后,我​​调用了 notifyDataSetChanged(),它工作正常。 哦,我现在明白了。在您的构造函数中,您将categories 分配给list。所以如果你更新你的categories,你更新你的list然后你的数据就改变了【参考方案2】:

你试过说:

categoryList.setAdapter(null);
categoryList.setAdapter(categoryAdapter);

【讨论】:

以上是关于使用数据作为 Map 的 notifyDataSetChanged 后 Android ListView 不刷新的主要内容,如果未能解决你的问题,请参考以下文章

使用 stl map 作为 struct 的成员

如何使用 map 函数正确并行运行 pyspark 代码

弹簧数据 jpa。返回 Map 作为分组操作的结果

Map集合

如何解决“不能使用 null 作为映射键!”使用 Group_Map 在 Python 3 中出现 Spark.SQL 错误

为啥我可以在 std::map<std::string, int> 中使用 const char* 作为键