Android ListView Actualizar una sola fila
Después de haber obtenido los datos de una sola fila de un ListView
, quiero actualizar esa única fila.
Actualmente estoy usando notifyDataSetChanged();
Pero eso hace que la View
reaccione muy lentamente. ¿Hay alguna otra solución?
- Android: Mejora de la frecuencia de muestreo del sensor mediante el uso de NDK y de sondeo
- Cómo utilizar Viewport Marker Management en Android
- Cambiar el tamaño de las imágenes según la resolución de pantalla Android
- Facebook SDK para Android - el primer inicio de sesión es muy lento / lleva mucho tiempo
- Buenas prácticas para ordenar una lista con una de las cuatro reglas
- Corona rendimiento?
- ¿Cómo puedo evitar los retrasos de recolección de basura en juegos Java? (Mejores Prácticas)
- Rendimiento en Android Juego
- ¿Por qué se crea un FrameLayout extra para fragmentos?
- Alto uso de la CPU con el emulador de Android (qemu-system-i386.exe)
- Android drawBitmap rendimiento de lotes de mapas de bits?
- ¿Cómo funciona un Android Studio con las funciones de System.out.print al hacer una versión final de una aplicación?
- Rendimiento del dispositivo virtual Android
Una opción es manipular el ListView
directamente. Primero verifique si el índice de la fila actualizada está entre getFirstVisiblePosition()
y getLastVisiblePosition()
, estos dos le dan la primera y la última posición en el adaptador que son visibles en la pantalla. A continuación, puede obtener la fila View
con getChildAt(int index)
y cambiarlo.
Como explicó Romain Guy hace un tiempo durante la sesión de E / S de Google , la forma más eficiente de actualizar una vista en una vista de lista es algo como lo siguiente (esto actualiza los datos de toda la vista):
ListView list = getListView(); int start = list.getFirstVisiblePosition(); for(int i=start, j=list.getLastVisiblePosition();i<=j;i++) if(target==list.getItemAtPosition(i)){ View view = list.getChildAt(i-start); list.getAdapter().getView(i, view, list); break; }
Suponiendo que el target
es un elemento del adaptador.
Este código recupera el ListView
, luego navega por las vistas mostradas actualmente, compara el elemento de target
que buscas con cada elemento de vista visualizado y si el destino está entre esos, obtén la vista getView
y ejecuta el adaptador getView
en esa vista para actualizar la vista. monitor.
Como una nota de lado invalidate
no funciona como algunas personas esperan y no refrescar la vista como getView hace, notifyDataSetChanged
reconstruirá la lista completa y terminará llamando a getview
para cada elementos mostrados y invalidateViews
también afectará a un montón.
Una última cosa, uno también puede obtener un rendimiento extra si sólo necesita cambiar un niño de una vista de fila y no toda la fila como getView
hace. En ese caso, el siguiente código puede reemplazar list.getAdapter().getView(i, view, list);
(Ejemplo para cambiar un texto TextView
):
((TextView)view.findViewById(R.id.myid)).setText("some new text");
En código confiamos en.
Este método más sencillo funciona bien para mí, y solo necesitas conocer el índice de posición para obtener la vista:
// mListView is an instance variable private void updateItemAtPosition(int position) { int visiblePosition = mListView.getFirstVisiblePosition(); View view = mListView.getChildAt(position - visiblePosition); mListView.getAdapter().getView(position, view, mListView); }
El siguiente código funcionó para mí. Tenga en cuenta al llamar a GetChild () tiene que compensar por el primer elemento de la lista ya que su relación con eso.
int iFirst = getFirstVisiblePosition(); int iLast = getLastVisiblePosition(); if ( indexToChange >= numberOfRowsInSection() ) { Log.i( "MyApp", "Invalid index. Row Count = " + numberOfRowsInSection() ); } else { if ( ( index >= iFirst ) && ( index <= iLast ) ) { // get the view at the position being updated - need to adjust index based on first in the list View vw = getChildAt( sysvar_index - iFirst ); if ( null != vw ) { // get the text view for the view TextView tv = (TextView) vw.findViewById(com.android.myapp.R.id.scrollingListRowTextView ); if ( tv != null ) { // update the text, invalidation seems to be automatic tv.setText( "Item = " + myAppGetItem( index ) + ". Index = " + index + ". First = " + iFirst + ". Last = " + iLast ); } } } }
Hay otra cosa mucho más eficiente que puede hacer, si se ajusta a su caso de uso que es.
Si está cambiando el estado y puede de alguna manera llamar a la adecuada (conociendo la posición) mListView.getAdapter().getView()
será el más eficiente de todos.
Puedo demostrar una manera realmente fácil de hacerlo creando una clase interna anónima en mi clase ListAdapter.getView()
. En este ejemplo, tengo un TextView
mostrando un texto "nuevo" y esa vista se establece en GONE
cuando se hace clic en el elemento de lista:
@Override public View getView(int position, View convertView, ViewGroup parent) { // assign the view we are converting to a local variable View view = convertView; Object quotation = getItem(position); // first check to see if the view is null. if so, we have to inflate it. if (view == null) view = mInflater.inflate(R.layout.list_item_quotation, parent, false); final TextView newTextView = (TextView) view.findViewById(R.id.newTextView); view.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { if (mCallbacks != null) mCallbacks.onItemSelected(quotation.id); if (!quotation.isRead()) { servicesSingleton.setQuotationStatusReadRequest(quotation.id); quotation.setStatusRead(); newTextView.setVisibility(View.GONE); } } }); if(quotation.isRead()) newTextView.setVisibility(View.GONE); else newTextView.setVisibility(View.VISIBLE); return view; }
El marco utiliza automáticamente la position
correcta y tiene que preocuparse por volver a getView
antes de llamar a getView
.
Sólo para que conste, ¿alguien consideró la vista 'Ver' en el método de anulación?
public void onItemClick(AdapterView<?> parent, View view, int position, long id) { //Update the selected item ((TextView)view.findViewById(R.id.cardText2)).setText("done!"); }