scrolling collapsing collapsible collapsemode bar app android performance listview

collapsing - Android ListView Refresh Single Row



layout collapsemode parallax (6)

Después de obtener los datos para 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?


Como Romain Guy explicó hace un tiempo durante la sesión de Google I / O , la forma más eficiente de actualizar solo una vista en una vista de lista es algo como lo siguiente (esta información actualiza 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 examina las vistas mostradas actualmente, compara el elemento de target que estás buscando con cada elemento de vista que se muestra, y si tu objetivo está entre esos, obtén la vista getView y ejecuta el adaptador getView en esa vista para actualizar el monitor.

Como una nota al margen invalidate no funciona como algunas personas esperan y no actualizará la vista como lo hace getView, notifyDataSetChanged reconstruirá toda la lista y terminará llamando a getview para cada elemento mostrado 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 hace getView . En ese caso, el siguiente código puede reemplazar list.getAdapter().getView(i, view, list); (ejemplo para cambiar un texto de TextView ):

((TextView)view.findViewById(R.id.myid)).setText("some new text");

En el código confiamos.


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 ); } } } }


Este método más simple me funciona bien, y solo necesita 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); }


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

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 manera realmente fácil de hacerlo, creando una clase interna anónima en mi clase ListAdapter.getView() . En este ejemplo, tengo un TextView muestra un texto "nuevo" y esa vista se establece en GONE cuando se hace clic en el elemento de la 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 debe preocuparse por recuperarlo antes de llamar a getView .


Solo para el registro, ¿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!"); }


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