2

My code expands the LinearLayout that is clicked. It works fine when there are 14 items or less in the list. Once there are more than 14 items it repeats the reference. What happens is clicking on the first item in the list expands both the 1st and the 15th item. It even seems randomized when there are 300 or more items. I've been trouble shooting this for a while with no luck

Here is my custom adapter

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);
    }
}

Here is the implement override begin called on each click. I display the id and it seems that it is duplicating ids. All the data is unique.

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

This is the animation that expands the view

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);
    }
}

UPDATED ADAPTER

@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;
 }
K3NN3TH
  • 1,458
  • 2
  • 19
  • 31
  • What is the purpose of `i = i+1; vi.setId(i);`? getView may be called much more times than the number of items in the list... – Salem Aug 13 '14 at 19:44

2 Answers2

3

try this man : just pull out the click assignment from all of your if - else statement thats it, something

like the below code. So what is the problem and what is the solution of it?

you said that when i click on item 1 in list after populating the list with 14 items every thing works well but when the list populates with more items when i click on item 1, item 15th also responds. so why?

this is because of convertView. convertView is a view thats created and recycled through scrolling the list. this view makes GC be called less and also save memory for you. it first assigned by your earliest items of list after you scroll the list, for example item one of list disappears and you see item 15 the convertView of item one is passed again to you. in this time it is not null so you skip click assignment to it and it holdes the reference of last click assignment that is the assignment of item one. so when you click on item 1 it means you also click on item 15 because the click assignment for both of them is the same. so each row must be assigned by new event listener .

@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;
    }
mmlooloo
  • 18,937
  • 5
  • 45
  • 64
  • just to explain what the problem is here is that you are only creating a listener for a button when convertView is null but when the view is not null (view is recycled) you dont have a listener set for anything – tyczj Aug 13 '14 at 19:56
  • @K3NN3TH i added some explanation to my answer. it may help you! – mmlooloo Aug 13 '14 at 20:17
  • thanks man, im almost there, right now i have the list but no clicks attached to it – K3NN3TH Aug 13 '14 at 20:20
  • @K3NN3TH still do you have problems? – mmlooloo Aug 13 '14 at 20:23
  • ya, ive added all but dups still opening, ill post new code – K3NN3TH Aug 13 '14 at 20:38
  • @mmlooloo ive updated the adapter, im wondering if i should take a different approach in identifying the view before sending it to the animation? – K3NN3TH Aug 13 '14 at 20:42
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/59303/discussion-between-mmlooloo-and-k3nn3th). – mmlooloo Aug 13 '14 at 20:43
  • @K3NN3TH i ask this question just to update my personal knowledge, do you use my answer and the accepted answer to get the result or just use your old adapter and the selected answer. – mmlooloo Aug 14 '14 at 08:22
  • @K3NN3TH i had helped you but you have refused to answer my question to help me learn something new! – mmlooloo Aug 14 '14 at 17:02
  • @mmlooloo I just had to add those two overrides and it worked, your solution still had the same behavior but you did help me understand why this was happening and I am very thankful for that – K3NN3TH Aug 14 '14 at 18:01
  • @K3NN3TH okay i want to know do you use my adapter or your old adapter, i do not want to ask you vote me and anything just want to get more information for myself. do my adapter and the accepted answer make result or just the accepted answer alone worked. – mmlooloo Aug 14 '14 at 18:04
  • 1
    @mmlooloo I just tested and it works both ways but I am using your way cause it makes more sense now that I understand how the adapter works. – K3NN3TH Aug 14 '14 at 18:22
  • @K3NN3TH thank you for your reply i just want to learn ! good luck! – mmlooloo Aug 14 '14 at 18:24
3

Add this to Adapter

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

@Override
public int getItemViewType(int position) {
    return position;
}
AssemblyX
  • 1,841
  • 1
  • 13
  • 15
  • according to this post http://stackoverflow.com/questions/5300962/getviewtypecount-and-getitemviewtype-methods-of-arrayadapter this solution gives no performance and it actually makes convertView always be null so you can delete viewholder. i think this dose not address the problem correctly although it is accepted. – mmlooloo Sep 06 '14 at 19:45