Todo el que haya trabajado con una aplicación con un tamaño
considerable se da cuenta en algún momento de que ciertas acciones provocan cierto "
stress" en el sistema, es decir, hay acciones que sobrecargan el sistema y tardan mucho en ejecutarse. Este hecho no sólo provoca una pérdida de tiempo productivo para el usuario, sino que ve mermada seriamente la experiencia de usuario (del ingles
User Experience). Por tanto es necesario optimizar nuestro código para que no sólo funcione sino que lo haga de forma óptima.
A continuación desglosaremos unos cuantos aspectos que pueden ayudar a mejorar el rendimiento de nuestra aplicación :
1) Limpiar todo lo que dejemos a nuestro paso. Siempre es buena idea mantener nuestro código limpio y no
tan solo en el sentido de mantenerlo legible y
formateado. Todos los objetos que creemos
deberán ser destruidos cuando dejemos de utilizarlos, de no ser así podremos crear "fugas de memoria" (
memory leaks) importantes.
En lenguajes antiguos como C++
existían los destructores (en
contraposición a los
Constructores que instancian un objeto), que se encargaban de liberar la memoria., en Java podemos sobreescribir el método
finalize (pero este depende de cuando se ejecute el
garbage collector), como norma general podemos decir que
deberíamos limpiar manualmente tras finalizar el uso de un objeto, para ello podemos poner las instancias a nulo.
Asimismo, es importante eliminar los
listeners de eventos que tengamos una vez que no se vayan a usar. En sistemas que usen
garbage collector como
Flex y Java, si mantenemos un
listener de un evento que ya no existe puede provocar que el
garbage collector no elimine ciertos objetos, dado que su contador de referencias no está a cero (pueden leer un poco más sobre el
garbage collecctor en un post anterior "
Introducción a Flex Profiler"). Como nota práctica decir que en
Flex podemos definir los
listener con "
weak references" lo cuál aliviará este problema.
En el caso de
Flex,cada vez que usemos los cargadores (
loaders), para cargar un fichero
SWF, una imagen, etc. es altamente recomendable descargar el objeto una vez que ya
no se use, para ello podemos usar la función
unloadAndStop.
2) Evitar acciones innecesarias.
¿Para que vamos a hacer acciones que no se usan para nada?.
a)Tener mucho cuidado con el manejo de las colecciones:
- Tener mucho cuidado al iterar en las colecciones (ya hablé de esto en otro post).
- Si tenemos la colección bindada o asociada a un evento, y se ejecuta cierto código cada vez añadimos, eliminamos o actualizamos un elemento, quizás sea recomendable realizar todas las operaciones que deseemos y luego lanzar el evento o ejecutar el binding. Supongamos que tenemos una colección en la que insertamos 1000 objetos, y cada vez que se inserte un objeto se ejecuta un binding para mostrar los datos en una tabla, el código para mostrar se ejecutará 1000 veces, cuando s. En Flex podemos usar la función disableAutoUpdate para que no se lancen los bindings mientras iteramos.
b) Podemos usar la instanciación aplazada (deferred instantiation), que consiste en no instanciar los objetos (como contenedores, tabNavigators, etc), hasta que realmente sean necesarios. En Flex podemos usar la propiedad creationPolicy para que los hijos se creen en diferentes momentos, pero esto es muy delicado. Otra opción es no crear los hijos en el constructor y sobreescribir el método createChildren() para que nuestros componentes creándose de forma aplazada.
c) Reciclar objetos. Es menos costoso reusar un objeto ya instanciado que crear uno nuevo.
d) No invalidar y revalidar los objetos si nada ha cambiado, es decir ¿para que repintamos una pantalla que se va a mantener igual?. En flex, podemos hacer uso de los métodos para invalidar (invalidateProperties, invalidateSize e InvalidateDisplayList), para forzar una invalidación y que tenga que revalidarse el componente, esto es útil en algunas circunstancias, como cuando cambia de tamaño.
En Flex, cada vez que se invalida un componente debemos realizar el proceso de validación en el cuál debemos realizar tres pasadas sobre la jerarquía de componentes, esto supone que para una jerarquía muy grande el tiempo de computo es considerable, en estos casos debemos ser muy cuidadoso y tener en cuenta los aspectos antes mencionaos (a,b y c), asimismo debemos eliminar los objetos y contenedores intermedios que realmente no se estén usando, ya que muchas veces se anidan Box, VBox y HBox, para simplificar la forma en la que escribimos nuestros componentes, de esta forma podemos eliminar complejidad de la jerarquía de objetos.
3) Consideraciones sobre las propiedades
Otro factor a tener en cuenta es usar las propiedades correctas, a la hora de ocultar/visualizar objetos, ya que una práctica común poco acertada es establecer el valor alfa para que no sea visible, pero esto no deshabilita la interacción del componente, en mi opinión lo más acertado es hacer uso de las propiedades visible e includeInLayout, la primera aparte de no visualizar el objeto deshabilita la interacción con el usuario, y la segunda hace que el componente no este en el displayList (la jerarquía de objetos en pantalla), y por tanto no se tendrá en cuenta al recorre dicha jerarquía.
Bueno espero que estos consejos les sirvan, y no haberme liado mucho al explicarlos, ya que he tratado de separarlos un poco pero están íntimamente relacionados.