Android: ListView not refreshing on notifyDataSetChanged();

15,744

It's normal that it doesn't refresh, you are adding an item to "lista" but the adapter keeps its own copy of that list, so or you set again the list in the adapter and then you call notifyDataChanged or you add the new item to the adapter.

Anyway I see couple of weird things, I thing you could semplify everything using an array adapter, you don't need to implement add,etc. I wrote some code simplyfing yours:

public class WeatherAppActivity extends ListActivity {

Button buton;
ItemsAdapter lista;

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);

    List<String> initialList = new ArrayList<String>();
    initialList.add("Bucuresti");
    initialList.add("Sibiu");

    lista=new ItemsAdapter(this, initialList);
    buton=(Button)findViewById(R.id.button1);
    buton.setOnClickListener(new OnClickListener() {
        @Override
        public void onClick(View v) {
             lista.add(""+System.currentTimeMillis()); // e chiar getText()
             lista.notifyDataSetChanged();

        }
    });

    setListAdapter(lista);

}

class ItemsAdapter extends ArrayAdapter<String> {

    public ItemsAdapter(Context context, List<String> list) {
        super(context, R.layout.lista, list);
    }

    @Override
    public View getView(final int position, View row, final ViewGroup parent) {
        final String item = getItem(position);

        ItemWrapper wrapper = null;
        if (row == null) {
            row = getLayoutInflater().inflate(R.layout.lista, parent, false);
            wrapper = new ItemWrapper(row);

            row.setTag(wrapper);
        } else {
            wrapper = (ItemWrapper) row.getTag();
        }
        wrapper.refreshData(item);

        return row;
    }

    class ItemWrapper {

        TextView text;

        public ItemWrapper(View row) {
            text = (TextView) row.findViewById(R.id.elementLista);
        }

        public void refreshData(String item) {
            text.setText(item);
        }

    }
    }    

}

These are the xml that I have used:

main.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent" >

<Button
    android:id="@+id/button1"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_alignParentBottom="true"
    android:layout_centerHorizontal="true"
    android:layout_marginBottom="63dp"
    android:text="Button" />

<ListView
    android:id="@id/android:list"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_alignParentTop="true"
    android:layout_centerHorizontal="true" >
</ListView>

</RelativeLayout>

lista.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >

<TextView
    android:id="@+id/elementLista"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="Medium Text"
    android:textAppearance="?android:attr/textAppearanceMedium" />

</LinearLayout>

This is the version of the adapter using a baseadapter:

class ItemsBaseAdapter extends BaseAdapter {

private List<String> items;
private Context mContext;

public ItemsBaseAdapter(Context context, List<String> list) {
    items = list;
    mContext = context;
}

public void addItem(String str) {
    items.add(str);
}

@Override
public View getView(final int position, View row, final ViewGroup parent) {
    final String item = (String) getItem(position);

    ItemWrapper wrapper = null;
    if (row == null) {
        row = getLayoutInflater().inflate(R.layout.lista, parent, false);
        wrapper = new ItemWrapper(row);

        row.setTag(wrapper);
    } else {
        wrapper = (ItemWrapper) row.getTag();
    }
    wrapper.refreshData(item);

    return row;
}

class ItemWrapper {

    TextView text;

    public ItemWrapper(View row) {
        text = (TextView) row.findViewById(R.id.elementLista);
    }

    public void refreshData(String item) {
        text.setText(item);
    }

}

@Override
public int getCount() {
    return items.size();
}

@Override
public Object getItem(int position) {
    return items.get(position);
}

@Override
public long getItemId(int position) {
    // TODO Auto-generated method stub
    return 0;
}
}

And this is the version of the list item wich also include an imageview on the left:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal" >

<ImageView 
    android:layout_height="wrap_content" 
    android:src="@android:drawable/btn_star_big_on" 
    android:scaleType="fitCenter" 
    android:layout_width="wrap_content" 
    />

<TextView
    android:id="@+id/elementLista"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="Medium Text"
    android:textAppearance="?android:attr/textAppearanceMedium" 
    />

</LinearLayout>    
Share:
15,744
FloIancu
Author by

FloIancu

Tech student from Bucharest, Romania. Into Java, C++, PHP, MySQL, Android and a little Objective C

Updated on July 02, 2022

Comments

  • FloIancu
    FloIancu almost 2 years

    I've got a custom BaseAdapter and an add button in the main activity. The button opens a dialog with a textbox and you can add new elements to the list that way. The problem is that the list is not refreshing. In the onActivityResult() function I print the number of elements in the list and each time I hit OK in the dialog box the number increases, so I know it's just the refreshing that doesn't work. My BaseAdapter and my activity:

    class ListaOrase extends BaseAdapter{
        private Activity context;
        ArrayList<String> orase;
    
        public ListaOrase(Activity context){
            this.context=context;
            orase=new ArrayList<String>();
        }
        public void add(String string){
            orase.add(string);
            this.notifyDataSetChanged();
        }
    
        public View getView (int position, View convertView, ViewGroup list)  {
            View element;
            if (convertView == null)
            {
             LayoutInflater inflater = context.getLayoutInflater();
             element = inflater.inflate(R.layout.lista, null);
            }
            else element = convertView;
            TextView elementLista=(TextView)element.findViewById(R.id.elementLista);    
            elementLista.setText(orase.get(position));
            return element;
        }
    
    }
    
    public class WeatherAppActivity extends ListActivity {
    
        Button buton;
        ListaOrase lista;
    
        @Override
        public void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.main);
            lista=new ListaOrase(this);
            buton=(Button)findViewById(R.id.buton);
    
    
            lista.add("Bucuresti");
            lista.add("Sibiu");
            setListAdapter(lista);
    
        }
    
        public void add(View view){
            Intent intent=new Intent();
            intent.setClass(this, Adauga.class);
            startActivityForResult(intent, 0);
        }
    
        public void onActivityResult (int requestCode, int responseCode, Intent data){
            System.out.println("Apelata");
            if(responseCode==1){
                lista.add(data.getStringExtra("oras")); // e chiar getText()
                System.out.println(lista.getCount());
                lista.notifyDataSetChanged();
            }
        }
    }
    

    As you can see, I'm trying to refresh (notifyDataSetChanged();) both when adding a new element (in the BaseAdapter extending class) and in method onActivityResult, after the dialog passes the new element to the main Activity. I repeat, the element IS added to the list because the count increases, it just doesn't refresh.

    Thanks for your answers!

  • FloIancu
    FloIancu over 12 years
    Abhi helped (see comment above) but it seems I have a problem with a SpannableString (see reply). Thank you for answering!
  • FloIancu
    FloIancu over 12 years
    Unfortunately the assignment requires the use of a BaseAdapter. What's more, I plan to add an icon to the left of each item, which can't be done with an ArrayAdapter. So what's with that SpannableString?
  • gwvatieri
    gwvatieri over 12 years
    You can build the list item in whatever way you want indipendently from which type of adapeter you are using. I edited my answer adding a baseadapter version and a list item which also include an icon on the left...
  • Sazzad Hissain Khan
    Sazzad Hissain Khan over 10 years
    Does adapter keep a copy of objects or reference of the source @gwa