¿Cómo actualizar las vistas de texto de Android de manera eficiente?

Estoy trabajando en una aplicación de Android que encuentra problemas de rendimiento. Mi objetivo es recibir cadenas de un AsyncTask y mostrarlos en un TextView. El TextView está inicialmente vacío y cada vez que el otro proceso envía una cadena concatena el contenido actual de la vista de texto. Actualmente utilizo StringBuilder para almacenar la cadena principal y cada vez que recibo una nueva cadena, la añado al StringBuilder y llamo

myTextView.setText(myStringBuilder.toString()) 

El problema es que el proceso de fondo puede enviar hasta 100 cadenas por segundo, y mi método no es lo suficientemente eficiente.

Redibujar todo el TextView cada vez es, obviamente, una mala idea (complejidad de tiempo O (N²)), pero no estoy viendo otra solución …

¿Conoces una alternativa a TextView que podría hacer estas concatenaciones en O (N)?

Siempre y cuando haya una nueva línea entre las cadenas, podría usar un ListView para anexar las cadenas y mantener las propias cadenas en un ArrayList o LinkedList a la que se agrega como AsyncTask recibe las cadenas.

También podría considerar simplemente invalidar el TextField con menos frecuencia; Digamos 10 veces por segundo. Esto sin duda mejorará la capacidad de respuesta. Algo como lo siguiente podría funcionar:

 static long lastTimeUpdated = 0; if( receivedString.size() > 0 ) { myStringBuilder.append( receivedString ); } if( (System.currentTimeMillis() - lastTimeUpdated) > 100 ) { myTextView.setText( myStringBuilder.getChars( 0, myStringBuilder.length() ); } 

Si las cadenas vienen en ráfagas, de tal manera que tiene un retraso entre ráfagas mayor que, digamos, un segundo, restablezca un temporizador cada actualización que disparará este código para que se ejecute de nuevo para captar la parte posterior de la última ráfaga.

Finalmente encontré una respuesta con la ayuda de havexz y Greyson aquí, y algo de código aquí . Como las cadenas estaban llegando en ráfagas, he decidido actualizar la interfaz de usuario cada 100ms. Para que conste, aquí está el aspecto de mi código:

 private static boolean output_upToDate = true; /* Handles the refresh */ private Handler outputUpdater = new Handler(); /* Adjust this value for your purpose */ public static final long REFRESH_INTERVAL = 100; // in milliseconds /* This object is used as a lock to avoid data loss in the last refresh */ private static final Object lock = new Object(); private Runnable outputUpdaterTask = new Runnable() { public void run() { // takes the lock synchronized(lock){ if(!output_upToDate){ // updates the outview outView.setText(new_text); // notifies that the output is up-to-date output_upToDate = true; } } outputUpdater.postDelayed(this, REFRESH_INTERVAL); } }; 

Y lo puse en mi método onCreate() :

 outputUpdater.post(outputUpdaterTask); 

Algunas explicaciones: cuando mi aplicación llama a su método onCreate() , mi outputUpdater recibe una solicitud para actualizar. Pero esta tarea ( outputUpdaterTask ) se pone una petición de actualización 100ms más tarde. El lock se comparte con el proceso que envía las nuevas cadenas y establece output_upToDate en false.

Trate de limitar la actualización. Así que en lugar de actualizar 100 veces por segundo, ya que es la tasa de generación. Mantenga las 100 cadenas en el constructor de cadenas y luego actualice una vez por segundo.

El código debe gustar:

 StringBuilder completeStr = new StringBuilder(); StringBuilder new100Str = new StringBuilder(); int counter = 0; if(counter < 100) { new100Str.append(newString); counter++; } else { counter = 0; completeStr.append(new100Str); new100Str = new StringBuilder(); myTextView.setText(completeStr.toString()); } 

NOTA: El código de arriba es sólo para ilustración, así que puede que tenga que modificarlo según sus necesidades.

  • Una forma más eficiente de actualizar la interfaz de usuario del servicio que las intenciones?
  • Desplazamiento rápido personalizado pulgar
  • Api de rendimiento de Android nivel 11 y superior
  • ¿Qué indica sf_frame_dur en los registros de Logcat de Android?
  • Por qué getSpeed ​​() siempre devuelve 0 en android
  • Falta el puerto reenviado en el Visor de jerarquía: Uso de Android Studio
  • Android.os.MessageQueue.next ocupando la pluralidad de tiempo exclusivo - ¿es este comportamiento normal?
  • Mi aplicación tarda tanto en lanzar la pantalla Primera actividad
  • Vista web de Android lenta
  • Buenas prácticas para ordenar una lista con una de las cuatro reglas
  • Android Studio tarda demasiado tiempo en ejecutar una aplicación
  • FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.