Android BaseAdapter导致滚动时ListView出现故障

Android BaseAdapter导致滚动时ListView出现故障,android,listview,Android,Listview,我对一些从书中改编的BaseAdapter代码有问题。在我的应用程序中,我到处都在使用这段代码的变体,但只是在滚动一个长列表时才意识到,ListView中的项目变得混乱,并不是所有的元素都显示出来 很难描述确切的行为,但很容易看出您是否将50个项目排序并开始上下滚动 class ContactAdapter extends BaseAdapter { ArrayList<Contact> mContacts; public ContactAdapter(Array

我对一些从书中改编的BaseAdapter代码有问题。在我的应用程序中,我到处都在使用这段代码的变体,但只是在滚动一个长列表时才意识到,ListView中的项目变得混乱,并不是所有的元素都显示出来

很难描述确切的行为,但很容易看出您是否将50个项目排序并开始上下滚动

class ContactAdapter extends BaseAdapter {

    ArrayList<Contact> mContacts;

    public ContactAdapter(ArrayList<Contact> contacts) {
        mContacts = contacts;
    }

    @Override
    public int getCount() {
        return mContacts.size();
    }

    @Override
    public Object getItem(int position) {
        return mContacts.get(position);
    }

    @Override
    public long getItemId(int position) {
        return position;
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        View view;
        if(convertView == null){
            LayoutInflater li = getLayoutInflater();
            view = li.inflate(R.layout.groups_item, null);
            TextView label = (TextView)view.findViewById(R.id.groups_item_title);
            label.setText(mContacts.get(position).getName());
            label = (TextView)view.findViewById(R.id.groups_item_subtitle);
            label.setText(mContacts.get(position).getNumber());
        }
        else
        {
            view = convertView;
        }
        return view;
    }

}
class ContactAdapter扩展了BaseAdapter{
ArrayList McContacts;
公共联系人适配器(ArrayList联系人){
mContacts=触点;
}
@凌驾
public int getCount(){
返回mContacts.size();
}
@凌驾
公共对象getItem(int位置){
返回mContacts.get(位置);
}
@凌驾
公共长getItemId(int位置){
返回位置;
}
@凌驾
公共视图getView(int位置、视图转换视图、视图组父视图){
视图;
if(convertView==null){
LayoutInflater li=getLayoutInflater();
视图=li.充气(R.layout.groups\u项,空);
TextView标签=(TextView)view.findViewById(R.id.groups\u item\u title);
label.setText(mContacts.get(position.getName());
label=(TextView)view.findViewById(R.id.groups\u item\u subtitle);
label.setText(mContacts.get(position.getNumber());
}
其他的
{
视图=转换视图;
}
返回视图;
}
}

只有在第一次创建
文本视图
小部件时,才将数据放入其中。您需要移动这四条线:

        TextView label = (TextView)view.findViewById(R.id.groups_item_title);
        label.setText(mContacts.get(position).getName());
        label = (TextView)view.findViewById(R.id.groups_item_subtitle);
        label.setText(mContacts.get(position).getNumber());

要在
if
/
else
块之后和方法返回之前更新
文本视图
小部件,无论是循环行还是创建新行。

要进一步澄清Commonware的答案,这里有一些更多信息:

为提高效率,li.inflate操作(此处需要解析XML中的行布局并创建适当的视图对象)由if(convertView==null)语句包装,因此,同一对象的膨胀不会在每次弹出视图时反复发生

但是,getView方法的其他部分用于设置其他参数,因此不应包含在if(convertView==null){}中。。。else{}语句

在该方法的许多常见实现中,一些textView标签、ImageView或ImageButton元素需要使用findViewById以及之后的.setText或.setImageBitmap操作,由列表[position]中的值填充。 这些操作必须在通过膨胀从头创建视图和获取现有视图(如果不为null)(例如刷新时)之后进行


另一个将此解决方案应用于ListView ArrayAdapter的好例子出现在

哦,我明白了。所以ListView最多只包含填充屏幕所需的视图数?@Mr.Dummessive:或多或少。它可以缓存一对,以便能够快速响应滚动请求。但是,在UI空间为10行且适配器为1000行的
ListView
中,
视图的数量将远远接近10而不是1000。大概12或14岁。这就是使用
convertView
进行行循环的要点,因此Android不必创建(以及以后的GC)一大堆行小部件。