ListView 与 ArrayAdapter 和 ViewHolder 将图标添加到错误的项目

Posted

技术标签:

【中文标题】ListView 与 ArrayAdapter 和 ViewHolder 将图标添加到错误的项目【英文标题】:ListView with ArrayAdapter and ViewHolder adding icons to the wrong item 【发布时间】:2011-03-08 13:58:12 【问题描述】:

我有一个动态的ListView,它使用ArrayAdapter。当从微调器中选择一个名字时,该名字连同一个显示他们是男性还是女性的图标被添加到ListView

大多数情况下一切都很好(名称被正确添加到列表中,并带有一个图标)。但是显示性别的图标被添加到ListView 中的错误项目中。该名称被添加到列表的底部,但图标被放置在列表顶部的名称处。我不知道这是否是我使用ViewHolder 的方式,但android website 中的文档为零。

// Listview inflater
inflater = (LayoutInflater) (this).getSystemService(LAYOUT_INFLATER_SERVICE);

// List Array.
mAdapter = new ArrayAdapter<String>(this, R.layout.player_simple_list, 
                                                 R.id.label, mStrings) 

    @Override
    public View getView(int position, View convertView, ViewGroup parent) 

        Log.i("ANDY","View getView Called");
        // A ViewHolder keeps references to children views to 
        // avoid unneccessary calls to findViewById() on each row.
        ViewHolder holder;

        if (null == convertView) 
            Log.i("ANDY","Position not previously used, so inflating");
            convertView = inflater.inflate(R.layout.player_simple_list, null);
            // Creates a ViewHolder and store references to the
            // two children views we want to bind data to.
            holder = new ViewHolder();
            holder.text = (TextView) convertView.findViewById(R.id.label);
            holder.icon = (ImageView) convertView.findViewById(R.id.icon);
            if (sexmale == true) 
                holder.icon.setImageBitmap(maleicon);
            
            else 
                holder.icon.setImageBitmap(femaleicon);
            
            convertView.setTag(holder);
         else 
            // Get the ViewHolder back to get fast access to the TextView
            // and the ImageView.
            holder = (ViewHolder) convertView.getTag();

        
        // Bind the data efficiently with the holder.
        holder.text.setText(getItem(position));
        // Change icon depending is the sexmale variable is true or false.
        Log.i("ANDY","getCount = "+mAdapter.getCount());
        return convertView;
    
;
setListAdapter(mAdapter);

【问题讨论】:

那里有一些公平的文档:developer.android.com/training/improving-layouts/… 【参考方案1】:

您必须在if-else-if 之后设置图标才能创建或绑定holder。否则,图标只会正确显示在列表的前几个项目中,即直到 ListView 未被填充。

public View getView(int position, View convertView, ViewGroup parent) 

    Log.i("ANDY","View getView Called");
    // A ViewHolder keeps references to children views
    // to avoid unneccessary calls to findViewById() on each row.
    ViewHolder holder;

        if (null == convertView) 
            Log.i("ANDY","Position not previously used, so inflating");
            convertView = inflater.inflate(R.layout.player_simple_list, null);

            // Creates a ViewHolder and store references to
            // the two children views we want to bind data to.
            holder = new ViewHolder();
            holder.text = (TextView) convertView.findViewById(R.id.label);
            holder.icon = (ImageView) convertView.findViewById(R.id.icon);
            convertView.setTag(holder);
         else 
            // Get the ViewHolder back to get fast access to the TextView
            // and the ImageView.
            holder = (ViewHolder) convertView.getTag();

        
        // Bind the data efficiently with the holder.
        holder.text.setText(getItem(position));

        // Change icon depending is the sexmale variable is true or false.
        if (sexmale == true) 
            holder.icon.setImageBitmap(maleicon);
        
        else 
            holder.icon.setImageBitmap(femaleicon);
        
        Log.i("ANDY","getCount = "+mAdapter.getCount());
        return convertView;

【讨论】:

嗨。我试过了,但是所有图标都变成了相同的类型,全部在列表中。即如果选择了男性名称,则所有图标都变为男性。【参考方案2】:

你必须在注释后从 if 中移出几行数据,如question is explained

// Bind the data efficiently with the holder.

所以它看起来像这样

if (null == convertView) 
    Log.i("ANDY","Position not previously used, so inflating");
    convertView = inflater.inflate(R.layout.player_simple_list, null);
    // Creates a ViewHolder and store references to the two children views
    // we want to bind data to.
    holder = new ViewHolder();
    convertView.setTag(holder);
 else 
    // Get the ViewHolder back to get fast access to the TextView
    // and the ImageView.
    holder = (ViewHolder) convertView.getTag();


// Bind the data efficiently with the holder.
holder.text = (TextView) convertView.findViewById(R.id.label);
holder.icon = (ImageView) convertView.findViewById(R.id.icon);
if (sexmale == true) 
    holder.icon.setImageBitmap(maleicon);

else 
    holder.icon.setImageBitmap(femaleicon);

holder.text.setText(getItem(position));

【讨论】:

我不同意,这只会使ViewHolder 无用,因为您每次都在覆盖它。正确的解决方案应该是在if 分支内设置holder.textholder.icon,并在if 块外设置内容(setTextsetImageBitmap)。 我认为覆盖需要在那里,因为如果没有,它将保存与其他记录位置相关的数据。例如,您显示记录 10,如果将重用记录 3 中的缓存视图,如果您不覆盖记录 3 的数据集,则记录 10 将可见。 @Pentium10:不,cristis 是正确的。 ViewHolder 与行相关联,因此它包含的小部件不会改变。需要改变的只是这些小部件的内容。 感谢您的快速回复,非常感谢。如果我理解正确,那么我会得到与下面的评论相同的结果。列表中的所有图标都变成了同性。 我没有看到你改变过sexmale变量,所以它总是一样的。【参考方案3】:

更新: ViewHolder 仅用于保存对项目布局内的组件视图的引用。这有助于避免调用 findViewById 以在具有多个组件的复杂项目布局中渲染每个组件的开销(如本例中的 TextViewImageView)。

我通过使用例程(称为getSex)来检索性数据并设置所有视图数据(包括if-else 块之外的图标)来修复它。

现在的工作代码如下所示:

if (null == convertView) 
    Log.i("ANDY","Position not previously used, so inflating");
    convertView = inflater.inflate(R.layout.player_simple_list, null);

    // Creates a ViewHolder and store references to the two children views
    // we want to bind data to.
    holder = new ViewHolder();
    holder.text = (TextView) convertView.findViewById(R.id.label);
    holder.icon = (ImageView) convertView.findViewById(R.id.icon);
    convertView.setTag(holder);
 else 
    // Get the ViewHolder back to get fast access to the TextView
    // and the ImageView.
    holder = (ViewHolder) convertView.getTag();


// Bind the data efficiently with the holder.
holder.text.setText(getItem(position));
// Change icon depending is the sexmale variable is true or false.
if (getSex (getItem(position)) == true)  
    holder.icon.setImageBitmap(maleicon);

else 
    holder.icon.setImageBitmap(femaleicon);

return convertView;

【讨论】:

以上是关于ListView 与 ArrayAdapter 和 ViewHolder 将图标添加到错误的项目的主要内容,如果未能解决你的问题,请参考以下文章

Android View 不会通过滑动手势滚动,也不会滚动。将 ListView 与 ArrayAdapter 一起使用

片段中的 Android ListView ArrayAdapter 不起作用

搜索在 ArrayAdapter 和 ListView 中不起作用

View(视图)——ListView之ArrayAdapter和SimpleAdapter文集

Android:如何从 listView 和 arrayAdapter 中删除项目

当 ArrayAdapter.isEnabled 返回 false 时,ListView 中的分隔符消失