Question

I'm having some problems with ListView and my custom adapter whereby the wrong position is obtained when an item is clicked.

Basically, the name of the item in the adapter is sent to a different activity when the item is clicked, and it works fine before scrolling. However, any items that are only revealed when scrolling do not send the correct positions; it seems as if they send the corresponding position for the item in the view before scrolling (which makes sense with view recycling).

This ListView probably won't have many items in, so if it's possible to disable view recycling it shouldn't be a huge problem, however I'd rather fix the problem so I can scroll and get the correct positions sent.

I'm a pretty new android developer and this was the first app I made, so I got this custom adapter from an online tutorial, so apologies if it looks a bit weird.

public View getView(final int position, View convertView, ViewGroup parent) {

    ViewHolder holder = null;
    Log.v("ConvertView", String.valueOf(position));

    if (convertView == null) {
        LayoutInflater vi = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        convertView = vi.inflate(R.layout.country_info, null);

        holder = new ViewHolder();
        holder.item = ((TextView)convertView.findViewById(R.id.infoBox));
        convertView.setTag(holder);

                holder.item.setOnClickListener(new View.OnClickListener() {

                    @Override
                    public void onClick(View v) {
                        Country country = countryList.get(position);                        
                        String s = (String)(country.getName());
                        Intent i = new Intent(SecondScreenActivity.this, ThirdScreenActivity.class);
                        i.putExtra("position", s);
                        startActivity(i);
                    }
                });

            } else {
                holder = (ViewHolder) convertView.getTag();
            }

            Country country = countryList.get(position);
            holder.item.setText(country.getName());
            holder.favourite.setChecked(country.isSelected());
            holder.favourite.setTag(country);

            return convertView;

        }

Note: This code might be missing/have a couple of extra brackets here and there because this method also checks if the items have checked/unchecked checkboxes and I removed that code to make it easier to solve this problem.

Thanks for helping!

Was it helpful?

Solution

The views in the adapter are being reused for different items in the list so they aren't reliable enough to accomplish what you are trying to do. Try to set the listener on the listView in your activity that you are using like so.

    listView.setOnItemClickListener(new OnItemClickListener()
    {
        public void onItemClick(AdapterView<?> parent, View view, int position, long id)
        {
                  Country country = (Country) listView.getAdapter().getItem(position);                        
                    String s = (String)(country.getName());
                    Intent i = new Intent(SecondScreenActivity.this, ThirdScreenActivity.class);
                    i.putExtra("position", s);
                    startActivity(i);
        }
    });

OTHER TIPS

My two cents are that since you are only setting the OnClickListener when the convertView is null it only remembers the initial bound final int position for said view, only when it was initially created from the layout, not after it was recycled.

Try setting it outside the if{} block so that it binds the current position of the view, whether it was recycled or not.

if (convertView == null) {
    LayoutInflater vi = (LayoutInflater)
                        getSystemService(Context.LAYOUT_INFLATER_SERVICE);
    convertView = vi.inflate(R.layout.country_info, null);

    holder = new ViewHolder();
    holder.item = ((TextView)convertView.findViewById(R.id.infoBox));
    convertView.setTag(holder);
} else {
    holder = (ViewHolder) convertView.getTag();
}
holder.item.setOnClickListener(new View.OnClickListener() {

    @Override
    public void onClick(View v) {
        Country country = countryList.get(position);                        
        String s = (String)(country.getName());
        Intent i = new Intent(SecondScreenActivity.this, 
                              ThirdScreenActivity.class);
        i.putExtra("position", s);
        startActivity(i);
    }
});

This, pretty much.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top