ViewHolder - BindView Prblem


I have a table:

id, code, LandName

items

----

----

----

Loading data into a ListView:

        Cursor c = myDb.SelectData();
        lisView1.setAdapter(new CountryAdapter(this, c));

the Query:

    public Cursor SelectData() {
        try {
            SQLiteDatabase db;
            db = this.getReadableDatabase(); // Read Data
            Cursor cursor = db.query(TABLE_COUNTRY, new String[] { "ID AS _id, *" },
                    null, null, null, null, null);
            if(cursor != null) {
                return cursor;
            }
            else{
                return null;
            }
        } catch (Exception e) {
            return null;
        }
    }

the Adapter:


    public class CountryAdapter extends CursorAdapter {
        private LayoutInflater _inflater;
        CountryHolder holder;
        public CountryAdapter(Context context, Cursor crs) {
            super(context, crs);
            _inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        }

        @Override
        public View newView(Context context, Cursor crs, ViewGroup parent) {

            View view = _inflater.inflate(R.layout.activit_column, parent, false);
            holder = new CountryHolder();
            txtID = view.findViewById(R.id.ColID);
            txtCode = view.findViewById(R.id.ColCode);
            txtCountry = view.findViewById(R.id.ColCountry);
            view.setTag(holder);
            return view;
        }

        @Override
        public void bindView(View view, Context context, Cursor crs) {

            holder = (CountryHolder) view.getTag();
            //  holder.text.setText(c.getString(4));
            txtID.setText(crs.getString(crs.getColumnIndexOrThrow("ID")));
            txtCode.setText(crs.getString(crs.getColumnIndexOrThrow("Code")));
            txtCountry.setText(crs.getString(crs.getColumnIndexOrThrow("Country")));

            //   s = cursor.getString(cursor.getColumnIndexOrThrow("Country"));
            //  if(s.equals("Italy")){

          //  Problem !!!!!
            if (txtCountry.getText().equals("Italy"))
                txtCountry.setTextColor(Color.RED);
            // }
        }
    }

    public class CountryHolder {
        TextView ID;
        TextView Code;
        TextView Country;
    }
}

Now my problem:

When i add the if condition

            if (txtCountry.getText().equals("Italy"))
                txtCountry.setTextColor(Color.RED);

The first row and the row it affects are colored, not just the affected row(s).

What is the reason for this?

I haven't any explanation for this.

How can I fix it?

Thanks

-1
Oct 21 at 4:04 PM
User AvatarIamBeginner
#android#sqlite

Accepted Answer

  1. In your newView() method, you're doing it like this:
holder = new CountryHolder();
txtID = view.findViewById(R.id.ColID);
txtCode = view.findViewById(R.id.ColCode);
txtCountry = view.findViewById(R.id.ColCountry);
view.setTag(holder);

txtID, txtCode, and txtCountry are getting saved as fields of the Adapter, not fields of the holder. Every time a new view is inflated, those global adapter variables get overwritten, causing bindView to reference the wrong views.

Solution: To make these, the fields of the Holder:

@Override
    public View newView(Context context, Cursor crs, ViewGroup parent) {
        View view = _inflater.inflate(R.layout.activit_column, parent, false);
        
        // Like this
        CountryHolder holder = new CountryHolder();
        holder.ID = view.findViewById(R.id.ColID);
        holder.Code = view.findViewById(R.id.ColCode);
        holder.Country = view.findViewById(R.id.ColCountry);
        
        view.setTag(holder);
        return view;
    }

2 . You should have else block for color:

if ("Italy".equalsIgnoreCase(countryName)) {
      holder.Country.setTextColor(Color.RED);
} else {
      holder.Country.setTextColor(Color.BLACK); // any color you want...
}

Corrected CountryAdapter:


public class CountryAdapter extends CursorAdapter {
    private LayoutInflater _inflater;

    public CountryAdapter(Context context, Cursor crs) {
        super(context, crs, 0);
        _inflater = LayoutInflater.from(context);
    }

    @Override
    public View newView(Context context, Cursor crs, ViewGroup parent) {
        View view = _inflater.inflate(R.layout.activit_column, parent, false);
        
        // Properly store the views inside the ViewHolder
        CountryHolder holder = new CountryHolder();
        holder.ID = view.findViewById(R.id.ColID);
        holder.Code = view.findViewById(R.id.ColCode);
        holder.Country = view.findViewById(R.id.ColCountry);
        
        view.setTag(holder);
        return view;
    }

    @Override
    public void bindView(View view, Context context, Cursor crs) {
        CountryHolder holder = (CountryHolder) view.getTag();

        holder.ID.setText(crs.getString(crs.getColumnIndexOrThrow("ID")));
        holder.Code.setText(crs.getString(crs.getColumnIndexOrThrow("Code")));

        String countryName = crs.getString(crs.getColumnIndexOrThrow("Country"));
        holder.Country.setText(countryName);

        // else block when styling recycled views
        if ("Italy".equalsIgnoreCase(countryName)) {
            holder.Country.setTextColor(Color.RED);
        } else {
            holder.Country.setTextColor(Color.BLACK); // any color
        }
    }

    static class CountryHolder {
        TextView ID;
        TextView Code;
        TextView Country;
    }
}
User AvatarCypher
Oct 21 at 4:28 PM
0