2010-01-23 41 views
72

Después de obtener los datos de una sola fila de ListView, deseo actualizar esa única fila.Android ListView Refresh Single Row

Actualmente estoy usando notifyDataSetChanged(); pero eso hace que el View reaccione muy lentamente. ¿Hay alguna otra solución?

Respuesta

29

Una opción es manipular el ListView directamente. Primero compruebe si el índice de la fila actualizada está entre getFirstVisiblePosition() y getLastVisiblePosition(), estas dos le dan las primeras y últimas posiciones en el adaptador que son visibles en la pantalla. Luego puede obtener la fila View con getChildAt(int index) y cambiarla.

+3

Gracias. Esto funcionaría si estoy ** editando ** el diseño actual del niño. Pero, ¿qué sucede si quiero ** cambiar el diseño por completo ** (inflando un xml diferente)? Si llamo a 'newView (...)' en el adaptador, me da una vista diferente que sin embargo no se pone en 'listView'. – hadi

+1

@hadi deberías echar un vistazo a esta respuesta: http://stackoverflow.com/a/11568271/858626 –

6

El siguiente código funcionó para mí. Tenga en cuenta que al llamar a GetChild() tiene que compensar con el primer elemento de la lista, ya que es relativo a 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); 
      } 
     } 
    } 
} 
87

Como Romain individuo explained a while back durante el Google I/O session, la forma más eficiente para actualizar un único punto de vista en una vista de lista es algo así como lo siguiente (éste actualizar el conjunto de datos de 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 target es un elemento del adaptador.

Este código de recuperar el ListView, a continuación, busque los puntos de vista que se muestran actualmente, comparar el elemento target que busca con cada muestra la vista elementos, y si su objetivo es entre aquellos, obtener la vista de cerramiento y ejecutar el adaptador getView en ese ver para actualizar la pantalla.

Como nota al margen invalidate no funciona igual que algunas personas que esperan y no actualizar la vista como getView hace, notifyDataSetChanged reconstruirá toda la lista y terminan llamando getview por cada elementos que se muestran y invalidateViews también afectará a un montón.

Una última cosa, uno también puede obtener un rendimiento adicional si solo necesita cambiar un elemento secundario de una vista de fila y no toda la fila como getView. 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.

+15

Probablemente deberías simplemente vincular tu otra respuesta http://stackoverflow.com/a/9987616/1026132 en lugar de copiar y pegar aquí. Esto ayudaría a reducir la cantidad de contenido duplicado en SO. –

+2

cómo implementar esto con diferentes tipos de vista? – Zyoo

+1

El enlace a "Google I/O session" en la respuesta está muerto. – Pang

26

Este método más simple funciona bien para mí, y sólo se necesita conocer el índice de posición a ponerme en contacto con 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); 
} 
+2

Funciona como un encanto, +1 – Rutger

+0

Voy a enviar los valores actualizados a detailview otra página si el usuario hace cambios en esa página de detalles cómo actualizar a la lista – Harsha

2

hay otra cosa mucho más eficiente que puede hacer, si se ajusta a su uso-caso que es.

Si está cambiando el estado y de alguna manera puede llamar al correcto (conociendo la posición) mListView.getAdapter().getView() será el más eficiente de todos.

Puedo demostrar una forma 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 que la vista se fija a 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 correcta position y usted tiene que preocuparse de ir a buscarlo nuevamente antes de llamar al getView.

-1

Para que quede constancia, ¿alguien consideró la 'Vista vista' 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!"); 

       } 
+0

La pregunta era cómo actualizar una sola fila en el ListView en cualquier dado momento. onItemClick solo se invoca cuando los usuarios hacen clic en un elemento y, por lo tanto, no es suficiente – Thys