android listview displays false data after scrolling (custom adapter)

Viewed 11143

I've got a strange problem that drives me crazy. In my android application I customized my own adapter that extends from ArrayAdapter. The items of the ListView to which I added my adapter can either be labeled-text (not editable), editable text or a spinner. The crazy stuff is: when I scroll the ListView, there are two problems:

(1) the (selected) value that is shown in the spinner items changes sometimes although I only scrolled!! when I click on the spinner, the old selected value is still shown (the one, that should be shown by the spinner) (2) the order of the ListViewItems changes when I scroll!

=> BUT the data in the adapter doesn't change (neither the data itself nor the order) - so it must be a problem of the View itself?! maybe android caches in background and doesn't refresh the ListViewItems soon enough or sth like that?!

Can anybody help me please?

Thx a lot!

Ok, I have found a solution that is not very nice, but it works. I simply did not use convertView anymore although that is suboptimal regarding to memory and performance. In my case it should be ok because my ListView's maximal amount of items is 15. Here is my Adapter-Class:

 public class FinAdapter extends ArrayAdapter<Param>{
    public Param[] params;
    private boolean merkzettel;
    protected EditText pv;

    public FinAdapter(Context context, int textViewResourceId, Param[] items, boolean merkzettel) {
        super(context, textViewResourceId, items);
        this.params = items;
        this.merkzettel = merkzettel;
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        final Param p = params[position];
        if(p != null){
            if(merkzettel){
                if (convertView == null) {
                    LayoutInflater vi = (LayoutInflater)getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
                    convertView = vi.inflate(R.layout.merk_det_item, null);
                }
                TextView tvl = (TextView) convertView.findViewById(R.id.paramM);
                TextView edl = (TextView) convertView.findViewById(R.id.param_valueM);
                TextView pal = (TextView) convertView.findViewById(R.id.param_unitM);
                if (tvl != null) {
                    tvl.setText(p.getName());                            
                }
                if(pal != null){
                    pal.setText(p.getUnit());
                }
                if(edl != null){
                    edl.setText(p.getDefData());
                }
            }
            else{
                if(p.isSelect()){

                if (convertView == null) {
                    LayoutInflater vi = (LayoutInflater)getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
                    convertView = vi.inflate(R.layout.fin_prod_list_item_select, null);
                }            
                TextView tvs = (TextView) convertView.findViewById(R.id.paramS);
                Spinner sp = (Spinner) convertView.findViewById(R.id.spinner_kalk);
                TextView paU = (TextView) convertView.findViewById(R.id.param_unitS);


                if (tvs != null) {
                    tvs.setText(p.getName());                            
                }
                if(paU != null){
                    paU.setText(p.getUnit());
                }
                if(sp != null){
                    String[] values = new String[p.getData().size()];
                    for(int i=0; i<values.length; i++){
                        values[i] = p.getData().get(i);
                    }
                    ArrayAdapter<String> adapter = new ArrayAdapter<String>(this.getContext(), android.R.layout.simple_spinner_item, values);
                    adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
                    sp.setAdapter(adapter);
                    sp.setSelection(p.getData().indexOf(p.getDefData()));
                    sp.setOnItemSelectedListener(new OnItemSelectedListener(){
                        public void onItemSelected(AdapterView<?> parent,
                                View convertView, int pos, long id) {
                            p.setDefData(p.getData().get(pos));
                            p.setChanged(true);
                        }
                        public void onNothingSelected(AdapterView<?> arg0) {
                            // TODO Auto-generated method stub

                        }

                    });
                }
            }       
            else if(p.isEdit()){
                if (convertView == null) {
                    LayoutInflater vi = (LayoutInflater)getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
                    convertView = vi.inflate(R.layout.fin_prod_list_item_edit, null);
                }
                TextView pa = (TextView) convertView.findViewById(R.id.param);
                pv = (EditText) convertView.findViewById(R.id.param_value);
                TextView paE = (TextView) convertView.findViewById(R.id.param_unit);
                if (pa != null) {
                    pa.setText(p.getName());                            
                }
                if(paE != null){
                    paE.setText(p.getUnit());
                }
                if(pv != null){
                    pv.setText(p.getDefData());
                    pv.setOnEditorActionListener(new OnEditorActionListener(){
                        public boolean onEditorAction(TextView convertView, int actionId,
                                KeyEvent event) {
                            // TODO Auto-generated method stub
                            p.setDefData(pv.getText().toString());
                            p.setChanged(true);
                            return false;
                        }                   
                    }); 
                }

            }
            else if(p.isLabel()){
                if (convertView == null) {
                    LayoutInflater vi = (LayoutInflater)getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
                    convertView = vi.inflate(R.layout.fin_prod_list_item_label, null);
                }
                TextView tvl = (TextView) convertView.findViewById(R.id.paramL);
                TextView edl = (TextView) convertView.findViewById(R.id.param_valueL);
                TextView pal = (TextView) convertView.findViewById(R.id.param_unitL);
                if (tvl != null) {
                    tvl.setText(p.getName());                            
                }
                if(pal != null){
                    pal.setText(p.getUnit());
                }
                if(edl != null){
                    edl.setText(p.getDefData());
                }   
            }}
        }
        return convertView;
    }
}
3 Answers

As everyone says, Android recycle the views. What does that mean? Imagine you have 10 items in your list, but only 3 of them are displayed on the screen. When scrolling down, the first will disappear and the forth will appear. The fourth item was already in the Android system, but the fifth was created from the first item, using the same view. In my case, I had a TextView with a default background. But if some condition was met, I change the background.

@Override
public View getView(int position, View convertView, ViewGroup parent) {
    ...
    if (someCondition) {
        holder.textView.setBackground(R.drawable.different_background)
    }
    ...
}

The problem was that I don't set back the default background if the condition is not met (as I thought that the view was created for each item). The problem appeared when the first item had the condition true, so the recycled view was used with the different_background instead of the default background. To avoid the problem, I had to always set both branches of the condition and set the default values as follows:

@Override
public View getView(int position, View convertView, ViewGroup parent) {
    ...
    if (someCondition) {
        holder.textView.setBackground(R.drawable.different_background)
    } else {
        holder.textView.setBackground(R.drawable.default_background)
    }
    ...
}
Related