为什么我的ListAdapter会循环显示项目?

时间:2014-08-17 15:34:24

标签: android

我有一个带有AbsListView的ListFragment,我写了一个ListAdapter:

@Override
public View onCreateView(final LayoutInflater inflater, final ViewGroup container,
                         Bundle savedInstanceState) {
    View view = inflater.inflate(R.layout.fragment_item, container, false);
    AbsListView mListView = (AbsListView) view.findViewById(R.id.list);
    mListView.setAdapter(getAdapter(inflater));
    mListView.setOnItemClickListener(this);
    return view;
}

private ListAdapter getAdapter(final LayoutInflater inflater) {
    return new ListAdapter() {
        @Override
        public boolean areAllItemsEnabled() {
            return true;
        }

        @Override
        public boolean isEnabled(int position) {
            return true;
        }

        @Override
        public void registerDataSetObserver(DataSetObserver observer) {

        }

        @Override
        public void unregisterDataSetObserver(DataSetObserver observer) {

        }

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

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

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

        @Override
        public boolean hasStableIds() {
            return false;
        }

        @Override
        public View getView(int position, View convertView, ViewGroup parent) {
            ViewHolder holder;
            if (convertView == null) {
                convertView = inflater.inflate(R.layout.item_view_template, parent, false);
                holder = new ViewHolder();
                holder.itemImg = (ImageView) convertView.findViewById(R.id.img_item);
                holder.itemTv = (TextView) convertView.findViewById(R.id.tv_item_name);
                holder.opTv = (TextView) convertView.findViewById(R.id.tv_item_op);
                holder.itemTv.setText(list.get(position).getName());
                convertView.setTag(holder);
            }
            return convertView;
        }

        @Override
        public int getItemViewType(int position) {
            return 1;
        }

        @Override
        public int getViewTypeCount() {
            return 1;
        }

        @Override
        public boolean isEmpty() {
            return false;
        }
    };
}

当我逐步调试时,list有14个项目,但getView方法只被调用了7次(7个项目完全填满了我的屏幕)。当我向上滑动AbsListView时,getView被再次调用了2次,前5个项目再次消失。

例如,我的list有{0,1,2,3,4,5,6,7,8,9,10,11,12,13},结果是:

0
1
2
3
4
5
6(Items below here only disappear after sliding AbsListView up)
7
8
0
1
2
3
4

5 个答案:

答案 0 :(得分:1)

这是因为convertView。 convertView是一个通过滚动列表创建和回收的视图。此视图可以减少GC调用并为您节省内存。滚动列表后,它首先由您最早的列表项分配,例如列表中的第一项消失,您看到第15项第一项的convertView再次传递给您。在这个时间它不是null,所以你跳过赋值给它并且它保留了作为第一项赋值的最后一个赋值的引用。

   @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        ViewHolder holder;
        if (convertView == null) {
            convertView = inflater.inflate(R.layout.item_view_template, parent, false);
            holder = new ViewHolder();
            holder.itemImg = (ImageView) convertView.findViewById(R.id.img_item);
            holder.itemTv = (TextView) convertView.findViewById(R.id.tv_item_name);
            holder.opTv = (TextView) convertView.findViewById(R.id.tv_item_op);
            holder.itemTv.setText(list.get(position).getName());
            convertView.setTag(holder);
        }else{
            holder = (ViewHolder) convertView.getTag(); 
        }
       // here you must use holder.opTv to change values for example initialize to new one
       //  here you must use holder.itemTv to change values for example initialize to new one
      // .....

        return convertView;
    }

答案 1 :(得分:1)

您的getView方法不是很好。请参阅此示例:http://www.vogella.com/tutorials/AndroidListView/article.html#adapterperformance_example

看起来应该类似于:

@Override
    public View getView(int position, View convertView, ViewGroup parent) {
        if (convertView == null) {
            LayoutInflater inflater = context.getLayoutInflater();
            convertView = inflater.inflate(R.layout.item_view_template, null);
            ViewHolder holder = new ViewHolder();
            holder.itemImg = (ImageView) convertView.findViewById(R.id.img_item);
            holder.itemTv = (TextView) convertView.findViewById(R.id.tv_item_name);
            holder.opTv = (TextView) convertView.findViewById(R.id.tv_item_op);
            convertView.setTag(holder);
        }

        ViewHolder holder = convertView.getTag();
        holder.itemTv.setText(list.get(position).getName());
        return convertView;
    }

答案 2 :(得分:0)

我修改getView方法:

        @Override
        public View getView(int position, View convertView, ViewGroup parent) {
            ViewHolder holder;
            convertView = inflater.inflate(R.layout.item_view_template, parent, false);
            holder = new ViewHolder();
            holder.itemImg = (ImageView) convertView.findViewById(R.id.img_item);
            holder.itemTv = (TextView) convertView.findViewById(R.id.tv_item_name);
            holder.opTv = (TextView) convertView.findViewById(R.id.tv_item_op);
            holder.itemTv.setText(list.get(position).getName());
            convertView.setTag(holder);

            return convertView;
        }

只需删除if (convertView == null)现在效果很好。谁可以解释一下?

答案 3 :(得分:0)

  

当我逐步调试它时,列表中有14个项目,但getView方法只调用了7次(7个项目完全填满了我的屏幕)。

适配器正在实例化新的View以填充屏幕。之后,如果您只有一种类型View来显示您的对象数组,那么Android会重复使用这些View来优化流程(为您的每个对象创建新视图的代价很高)数组)。

在创建了7 View之后,您就不会更新它(只有在convertView为空时才会更新,例如在前7个getView(...)调用中。

解决方案应该是:

@Override
public View getView(int position, View convertView, ViewGroup parent) {
    ViewHolder holder;
    if (convertView == null) {
        convertView = inflater.inflate(R.layout.item_view_template, parent, false);
        holder = new ViewHolder();
        holder.itemImg = (ImageView) convertView.findViewById(R.id.img_item);
        holder.itemTv = (TextView) convertView.findViewById(R.id.tv_item_name);
        holder.opTv = (TextView) convertView.findViewById(R.id.tv_item_op);
        convertView.setTag(holder);
    } else {
        holder = (ViewHolderItem) convertView.getTag();
    }
    holder.itemTv.setText(list.get(position).getName());
    return convertView;
}

答案 4 :(得分:0)

这应该有效:

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        ViewHolder holder;
        if (convertView == null) {
            convertView = inflater.inflate(R.layout.item_view_template, parent, false);
            holder = new ViewHolder();
            holder.itemImg = (ImageView) convertView.findViewById(R.id.img_item);
            holder.itemTv = (TextView) convertView.findViewById(R.id.tv_item_name);
            holder.opTv = (TextView) convertView.findViewById(R.id.tv_item_op);
            convertView.setTag(holder);
        }

        holder = (ViewHolder) convertView.getTag();
        holder.itemTv.setText(list.get(position).getName());

        return convertView;
    }