Android, List Adapter returns wrong position in getView Android, List Adapter returns wrong position in getView android android

Android, List Adapter returns wrong position in getView


Because the convertView and holder will be recycled to use, move your setOnClickListener out of the if else statement:

    if (convertView == null) {        convertView = myInflater.inflate(R.layout.list_add_friends_row, null);        holder = new ViewHolder();        Typeface font = Typeface.createFromAsset(context.getAssets(), "fonts/ITCAvantGardeStd-Demi.ttf");        holder.tvUserName = (TextView) convertView.findViewById(R.id.tvUserName);        holder.tvUserName.setTypeface(font);        holder.ivPicture = (ImageView) convertView.findViewById(R.id.ivPicture);        holder.btnAdd = (Button) convertView.findViewById(R.id.btnAdd);        convertView.setTag(holder);    } else {        holder = (ViewHolder) convertView.getTag();    }    holder.btnAdd.setOnClickListener(new View.OnClickListener() {         @Override         public void onClick(View v)                 Log.e(TAG, "Item: " + position);                listener.OnAddUserClicked(userList.get(position));            }        });

It is not the best solution for that,because there will be some performance issue. I suggest you create a Map for your view and create a new view for your item then just use the relative view for each view.

I think it will be a better solution with best performance:

@Overridepublic View getView(final int position, View convertView, ViewGroup parent) {    ViewHolder holder;    if (convertView == null) {        convertView = myInflater.inflate(R.layout.list_add_friends_row, null);        holder = new ViewHolder();        Typeface font = Typeface.createFromAsset(context.getAssets(), "fonts/ITCAvantGardeStd-Demi.ttf");        holder.tvUserName = (TextView) convertView.findViewById(R.id.tvUserName);        holder.tvUserName.setTypeface(font);        holder.ivPicture = (ImageView) convertView.findViewById(R.id.ivPicture);        holder.btnAdd = (Button) convertView.findViewById(R.id.btnAdd);        holder.btnAdd.setOnClickListener(new View.OnClickListener() {            @Override            public void onClick(View v) {                Integer pos = (Integer)v.getTag();                Log.e(TAG, "Item: " + pos);                listener.OnAddUserClicked(userList.get(pos));            }        });        convertView.setTag(holder);    } else {        holder = (ViewHolder) convertView.getTag();    }    holder.tvUserName.setText(userList.get(position).getName());    imageDownloader.displayImage(holder.ivPicture, userList.get(position).getPhotoUrl());    holder.btnAdd.setTag(position);    return convertView;}

You can also manage your view by yourself. Create every unique view for your item, don't recycle view.

//member variousprivate Map<Integer, View> myViews = new HashMap<Integer, View>(); @Overridepublic View getView(final int position, View convertView, ViewGroup parent) {    ViewHolder holder;    View view = myViews.get(position);    if (view == null) {        view = myInflater.inflate(R.layout.list_add_friends_row, null);        //don't need use the holder anymore.        Typeface font = Typeface.createFromAsset(context.getAssets(), "fonts/ITCAvantGardeStd-Demi.ttf");        holder.tvUserName = (TextView) convertView.findViewById(R.id.tvUserName);        holder.tvUserName.setTypeface(font);        holder.ivPicture = (ImageView) convertView.findViewById(R.id.ivPicture);        holder.btnAdd = (Button) convertView.findViewById(R.id.btnAdd);        holder.btnAdd.setOnClickListener(new View.OnClickListener() {            @Override            public void onClick(View v) {                Integer pos = (Integer)v.getTag();                Log.e(TAG, "Item: " + pos);                listener.OnAddUserClicked(userList.get(pos));            }        });       holder.tvUserName.setText(userList.get(position).getName());       imageDownloader.displayImage(holder.ivPicture,                  userList.get(position).getPhotoUrl());       myViews.put(position, view);    }    return view;}


Did you tried doing something like this:

holder.btnAdd.setTag(Integer.valueOf(position));

And then retrieve wich row was clicked in the callback for the button, like this:

public void btnAddClickListener(View view)    {        position = (Integer)view.getTag();        Foo foo = (Foo)foos_adapter.getItem(position);  //get data of row(position)        //do some    }


Another approach I found useful (if you are using the ViewHolder pattern of course) is to set the index on a separate attribute whenever getView() is called, then inside your onClickListener you just have to reference your holder's position attribute, something like this:

@Overridepublic View getView(int position, View convertView, ViewGroup parent) {    final ViewHolder holder;    if(convertView == null){        convertView = View.inflate(mContext, R.layout.contact_picker_row,null);        holder = new ViewHolder();        holder.body = (RelativeLayout)convertView.findViewById(R.id.numberBody);        convertView.setTag(holder);    }else{        holder = (ViewHolder)convertView.getTag();    }    holder.position = position;    holder.body.setOnClickListener(new View.OnClickListener() {        @Override        public void onClick(View v) {            Toast.makeText(mContext,"Clicked on: "+holder.position,Toast.LENGTH_LONG).show();        }    });    return convertView;}private class ViewHolder{    RelativeLayout body;    int position;}