【问题标题】:ListView returns duplicate references to View onClickListView 返回对 View onClick 的重复引用
【发布时间】:2014-08-14 08:33:09
【问题描述】:

我的代码 expands LinearLayoutclicked。当列表中有 14 个或更少的项目时,它工作正常。一旦有超过 14 个项目,它就会重复引用。发生的情况是单击列表中的第一个项目会同时展开第一个和第 15 个项目。当有 300 个或更多项目时,它甚至看起来是随机的。我已经有一段时间没有运气了

这是我的自定义适配器

public class Scanvinadapter extends BaseAdapter {

    private Activity activity;
    private ArrayList data;
    private static LayoutInflater inflater = null;
    public Resources res;
    Scanvinmodel model = null;
    int i = 0;
    ScanlistListener mCallback;

    public Scanvinadapter(Activity a, ArrayList d, Resources resLocal){
        activity = a;
        data = d;
        res = resLocal;
        inflater = (LayoutInflater)activity.getSystemService(Context.LAYOUT_INFLATER_SERVICE);

        try {
            mCallback = (ScanlistListener) activity;
        } catch (ClassCastException e) {
            throw new ClassCastException(activity.toString()
                    + " must implement ScanlistListener");
        }


    }

    @Override
    public int getCount() {
        if(data.size()<=0)
            return 1;
        return data.size();
    }

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

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

    public static class ViewHolder{
        public TextView scanlistvin;
        public TextView scanlistbay;
    }


    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        View vi = convertView;
        LinearLayout ll = null;
        ViewHolder holder;
        if(convertView == null){
            vi = inflater.inflate(R.layout.scanlistview, null);
            holder = new ViewHolder();

            ll = (LinearLayout) vi.findViewById(R.id.scanlist);
            ll.setLayoutParams(new AbsListView.LayoutParams(LayoutParams.MATCH_PARENT,100));
            Log.v("position", String.valueOf(position));
            i = i+1;
            vi.setId(i);
            ll.setOnClickListener(new OnClickListener() {
                public void onClick(View v) {
                    mCallback.scanlistclick(v, 0);
                }
            });

            //vi.setOnClickListener(new OnItemClickListener( position ));

            holder.scanlistvin = (TextView) vi.findViewById(R.id.scanlistvin);
            holder.scanlistbay = (TextView) vi.findViewById(R.id.scanlistbay);
            vi.setTag(holder);
        }else
            holder = (ViewHolder)vi.getTag();

        if(data.size()<=0){
            holder.scanlistvin.setText("No Data");
        }else{
            model = null;
            model = (Scanvinmodel) data.get(position);

            holder.scanlistvin.setText(model.getVin());
            holder.scanlistbay.setText(model.getBay());
            return vi;
        }
        return null;
    }


    public void onClick(View v) {
        Log.v("CustomAdapter", "=====Row button clicked=====");
    }

    private class OnItemClickListener implements OnClickListener{
        private int mPosition;

        OnItemClickListener(int position){
            mPosition = position;
        }
        @Override
        public void onClick(View v) {

            Log.v("CustomAdapter", String.valueOf(mPosition) );
            mCallback.scanlistclick(v, mPosition);
        }
    }

    public interface ScanlistListener{
        public void scanlistclick(View v, int i);
    }
}

这里是每次点击时调用的工具覆盖开始。我显示了 id,它似乎在重复 id。所有数据都是唯一的。

@Override
public void scanlistclick(View v, int i) {
    new Animutils().expand(v);
    Log.wtf("wtf", String.valueOf(v.getId()));
}

这是展开视图的动画

public class Animutils {
    private static final long ANIMATION_DURATION = 250;
    protected static final String TAG = "Animutils.java";

    public void expand(final View v) {
        //v.measure(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);
        final int targtetHeight = v.getMeasuredHeight();
        //final int targtetHeight = 500;

        //v.getLayoutParams().height = 114;
//      v.setVisibility(View.VISIBLE);
        Animation a = new Animation(){
            @Override
            protected void applyTransformation(float interpolatedTime, Transformation t) {
                //v.getLayoutParams().height = interpolatedTime == 1 ? LayoutParams.WRAP_CONTENT : (int)(targtetHeight * interpolatedTime);
                //v.getLayoutParams().height = interpolatedTime == 1 ? 500 : (int)(targtetHeight + 25);
                if(interpolatedTime == 0){
                    v.getLayoutParams().height = targtetHeight + 25;
                }else{
                    if(v.getLayoutParams().height == 500){
                        cancel();
                    }else{
                        v.getLayoutParams().height = v.getLayoutParams().height +25;
                    }
                }
                v.requestLayout();
            }

            @Override
            public boolean willChangeBounds() {
                return true;
            }
        };

// 1dp/ms

        a.setDuration(ANIMATION_DURATION);
        // a.setDuration((int)(targtetHeight / v.getContext().getResources().getDisplayMetrics().density));
        v.startAnimation(a);
    }



    public void collapse(final View v) {
        final int initialHeight = v.getMeasuredHeight();

        Animation a = new Animation(){
            @Override
            protected void applyTransformation(float interpolatedTime, Transformation t) {
                if(interpolatedTime == 1){
                    v.setVisibility(View.GONE);
                }else{
                    v.getLayoutParams().height = initialHeight - (int)(initialHeight * interpolatedTime);
                    v.requestLayout();
                }
            }

            @Override
            public boolean willChangeBounds() {
                return true;
            }
        };

        // 1dp/ms
        a.setDuration(ANIMATION_DURATION);
        // a.setDuration((int)(initialHeight / v.getContext().getResources().getDisplayMetrics().density));
        v.startAnimation(a);
    }
}

更新的适配器

@Override
public View getView(int position, View convertView, ViewGroup parent) {
    View vi = convertView;
    LinearLayout ll = null;
    ViewHolder holder;
    if(convertView == null){
        vi = inflater.inflate(R.layout.scanlistview, null);
        ll = (LinearLayout) vi.findViewById(R.id.scanlist);
        ll.setLayoutParams(new AbsListView.LayoutParams(LayoutParams.MATCH_PARENT,100));
        holder = new ViewHolder();
        holder.scanlist = (LinearLayout) vi.findViewById(R.id.scanlist);
        holder.scanlistvin = (TextView) vi.findViewById(R.id.scanlistvin);
        holder.scanlistbay = (TextView) vi.findViewById(R.id.scanlistbay);
        Log.v("position", String.valueOf(position));
        vi.setTag(holder);
    }else{
        holder = (ViewHolder)vi.getTag();
        ll = holder.scanlist;
        Log.v("position", String.valueOf(position));

    } 

    ll.setOnClickListener(new OnClickListener() {
        public void onClick(View v) {
            mCallback.scanlistclick(v, 0);
        }
    });




    if(data.size()<=0){
        holder.scanlistvin.setText("No Data");
    }else{
        model = null;
        model = (Scanvinmodel) data.get(position);

        holder.scanlistvin.setText(model.getVin());
        holder.scanlistbay.setText(model.getBay());

    }
    return vi;
 }

【问题讨论】:

  • i = i+1; vi.setId(i); 的目的是什么? getView 的调用次数可能比列表中的项目数多得多...

标签: android listview android-arrayadapter


【解决方案1】:

将此添加到适配器

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

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

【讨论】:

  • 根据这篇文章stackoverflow.com/questions/5300962/… 这个解决方案没有提供任何性能,它实际上使 convertView 始终为空,因此您可以删除查看器。我认为这虽然被接受,但并不能正确解决问题。
【解决方案2】:

试试这个人:只需从你所有的 if - else 语句中提取点击分配就是这样,一些东西

喜欢下面的代码。那么问题是什么,有什么解决办法呢?

您说过,当我在列表中填充 14 项后单击列表中的第 1 项时,一切正常,但是当我单击第 1 项时列表中填充更多项时,第 15 项也会响应。那为什么呢?

这是因为 convertView。 convertView 是通过滚动列表创建和回收的视图。这个视图减少了 GC 的调用,也为你节省了内存。在您滚动列表后,它首先由您最早的列表项分配,例如列表的第一项消失并且您看到第 15 项,第一项的 convertView 再次传递给您。在这个时候它不是空的,所以你跳过点击分配给它,它持有最后一次点击分配的引用,即第一个项目的分配。因此,当您单击第 1 项时,这意味着您也单击了第 15 项,因为它们的单击分配是相同的。所以每一行都必须由新的事件监听器分配。

@Override
    public View getView(int position, View convertView, ViewGroup parent) {
        View vi = convertView;
        LinearLayout ll = null;
        ViewHolder holder;
        if(convertView == null){
            vi = inflater.inflate(R.layout.scanlistview, null);
            holder = new ViewHolder();

            ll = (LinearLayout) vi.findViewById(R.id.scanlist);
            ll.setLayoutParams(new AbsListView.LayoutParams(LayoutParams.MATCH_PARENT,100));
            Log.v("position", String.valueOf(position));
            i = i+1;
            vi.setId(i);
            holder.scanlist = (LinearLayout) vi.findViewById(R.id.scanlist);
            holder.scanlistvin = (TextView) vi.findViewById(R.id.scanlistvin);
            holder.scanlistbay = (TextView) vi.findViewById(R.id.scanlistbay);
            vi.setTag(holder);
        }else{
            holder = (ViewHolder)vi.getTag();
            ll= holder.scanlistview;
            ll.setLayoutParams(new AbsListView.LayoutParams(LayoutParams.MATCH_PARENT,100));
        } 

         ll.setOnClickListener(new OnClickListener() {
                public void onClick(View v) {
                    mCallback.scanlistclick(v, 0);
                }
            });    
        if(data.size()<=0){
            holder.scanlistvin.setText("No Data");
        }else{
            model = null;
            model = (Scanvinmodel) data.get(position);

            holder.scanlistvin.setText(model.getVin());
            holder.scanlistbay.setText(model.getBay());
            return vi;
        }


        return null;
    }

【讨论】:

  • 只是为了解释这里的问题是,当 convertView 为空但视图不为空(视图被回收)时,您只为按钮创建侦听器,您没有设置侦听器任何东西
  • @K3NN3TH 我为我的回答添加了一些解释。它可以帮助你!
  • 谢谢,我快到了,现在我有列表,但没有附加点击
  • @K3NN3TH 你还有问题吗?
  • @mmlooloo 我刚刚测试过,它可以双向工作,但我正在使用你的方式,因为现在我了解了适配器的工作原理,它更有意义。
猜你喜欢
  • 2015-03-22
  • 1970-01-01
  • 1970-01-01
  • 2018-03-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-07-14
相关资源
最近更新 更多