Android: ¿cómo refrescar los contenidos de ListView?

My ListView está utilizando una extensión de BaseAdapter , no puedo hacer que se actualice correctamente. Cuando actualizo, parece que los datos antiguos se basan en los nuevos datos, hasta que ocurre un evento de desplazamiento. Las filas anteriores dibujan sobre las nuevas filas, pero las filas anteriores desaparecen cuando comienzo a desplazarme.

Intenté llamar a invalidateViews() , notifyDataSetChanged() y notifyDataSetInvalidated() . Mi código se ve algo así como:

 private void updateData() { List newList = getNewList(); MyAdapter adapter = new MyAdapter(getContext()); //my adapter holds an internal list of DataItems adapter.setList(newList); mList.setAdapter(adapter); adapter.notifyDataSetChanged(); mList.invalidateViews(); } 

Para aquellos que todavía tienen problemas, lo resolví de esta manera:

 List newItems = databaseHandler.getItems(); ListArrayAdapter.clear(); ListArrayAdapter.addAll(newItems); ListArrayAdapter.notifyDataSetChanged(); databaseHandler.close(); 

Primero borré los datos del adaptador, luego agregué la nueva colección de elementos y solo luego configuré notifyDataSetChanged(); Esto no estaba claro para mí al principio, así que quería señalarlo. Tenga en cuenta que sin llamar a notifyDataSetChanged() la vista no se actualizará.

Según entiendo, si desea actualizar ListView inmediatamente cuando los datos han cambiado, debe llamar a notifyDataSetChanged() en RunOnUiThread() .

 private void updateData() { List newData = getYourNewData(); mAdapter.setList(yourNewList); runOnUiThread(new Runnable() { @Override public void run() { mAdapter.notifyDataSetChanged(); } }); } 

No es necesario crear un nuevo adaptador para actualizar los contenidos de su ListView. Simplemente almacene su adaptador en un campo y actualice su lista con el siguiente código:

 mAdapter.setList(yourNewList); mAdapter.notifyDataSetChanged(); 

Para aclarar eso, tu actividad debería verse así:

 private YourAdapter mAdapter; protected void onCreate(...) { ... mAdapter = new YourAdapter(this); setListAdapter(mAdapter); updateData(); } private void updateData() { List newData = getYourNewData(); mAdapter.setList(yourNewList); mAdapter.notifyDataSetChanged(); } 

Yo también he probado invalidate (), invalidateViews (), notifyDataSetChanged (). Todos podrían funcionar en algunos contextos particulares, pero no funcionó en mi caso.

En mi caso, tuve que agregar algunas filas nuevas a la lista y simplemente no funciona. Crear un nuevo adaptador resolvió el problema.

Mientras realizaba la depuración, me di cuenta de que los datos estaban allí, pero no se procesaron. Si invalidate () o invalidateViews () no se procesa (lo que se supone que debe), no sé qué haría.

Crear un nuevo objeto Adapter para actualizar los datos modificados no parece ser una mala idea. Definitivamente funciona El único inconveniente podría ser el tiempo consumido en la asignación de nueva memoria para su adaptador, pero eso debería estar bien, suponiendo que el sistema Android sea lo suficientemente inteligente y se encargue de eso para mantener su eficiencia.

Si quita esto de la ecuación, el flujo es casi igual a invocar notifyDataSetChanged. En este sentido, se llama el mismo conjunto de funciones de adaptador en cualquier caso.

Así que no estamos perdiendo mucho, sino ganando mucho.

Creo que rellenar el mismo adaptador con diferentes datos sería más o mejor técnica. Coloque este método en su clase de Adaptador con el argumento correcto (la lista de datos que desea mostrar como nombres en mi caso) Llámelo donde actualiza los datos de la lista con la lista actualizada (nombres en mi caso)

 public void refill(ArrayList names) { list.clear(); list.addAll(names); list.notifyDataSetChanged(); } 

Si cambia el adaptador o establece el adaptador una y otra vez cuando la lista se actualice, entonces forzar el error de cierre seguramente causaría problemas en algún momento. (Error: los datos de la lista se actualizaron, pero el adaptador no notifica a la vista de lista)

Estoy haciendo lo mismo usando invalidateViews () y eso funciona para mí. Si quieres que se invalide inmediatamente, puedes intentar llamar a postInvalidate después de llamar a invalidateViews.

Actualice los contenidos de ListView por el siguiente código:

 private ListView listViewBuddy; private BuddyAdapter mBuddyAdapter; private ArrayList buddyList = new ArrayList(); 

onCreate () :

 listViewBuddy = (ListView)findViewById(R.id.listViewBuddy); mBuddyAdapter = new BuddyAdapter(); listViewBuddy.setAdapter(mBuddyAdapter); 

onDataGet (Después de la llamada al servicio web o de la base de datos local u otro):

 mBuddyAdapter.setData(buddyList); mBuddyAdapter.notifyDataSetChanged(); 

BaseAdapter :

 private class BuddyAdapter extends BaseAdapter { private ArrayList mArrayList = new ArrayList(); private LayoutInflater mLayoutInflater= (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE); private ViewHolder holder; public void setData(ArrayList list){ mArrayList = list; } @Override public int getCount() { return mArrayList.size(); } @Override public BuddyModel getItem(int position) { return mArrayList.get(position); } @Override public long getItemId(int pos) { return pos; } private class ViewHolder { private TextView txtBuddyName, txtBuddyBadge; } @SuppressLint("InflateParams") @Override public View getView(final int position, View convertView, ViewGroup parent) { if (convertView == null) { holder = new ViewHolder(); convertView = mLayoutInflater.inflate(R.layout.row_buddy, null); // bind views holder.txtBuddyName = (TextView) convertView.findViewById(R.id.txtBuddyName); holder.txtBuddyBadge = (TextView) convertView.findViewById(R.id.txtBuddyBadge); // set tag convertView.setTag(holder); } else { // get tag holder = (ViewHolder) convertView.getTag(); } holder.txtBuddyName.setText(mArrayList.get(position).getFriendId()); int badge = mArrayList.get(position).getCount(); if(badge!=0){ holder.txtBuddyBadge.setVisibility(View.VISIBLE); holder.txtBuddyBadge.setText(""+badge); }else{ holder.txtBuddyBadge.setVisibility(View.GONE); } return convertView; } } 

Siempre que desee actualizar Listview, simplemente llame al siguiente código de dos líneas:

  mBuddyAdapter.setData(Your_Updated_ArrayList); mBuddyAdapter.notifyDataSetChanged(); 

Hecho

Solo esto funciona para mí cada vez, tenga en cuenta que no sé si causa otras complicaciones o problemas de rendimiento:

 private void updateListView(){ listview.setAdapter(adapter); } 

Otra manera fácil:

 //In your ListViewActivity: public void refreshListView() { listAdapter = new ListAdapter(this); setListAdapter(listAdapter); }