Ciclo de vida de Flutter para desarrolladores Android e iOS

René Sandoval
5 min readSep 18, 2019

Este artículo es una traducción de un artículo publicado originalmente en inglés por Mariano Zorrilla en Medium. Por favor, visita el siguiente enlace y recomienda el artículo original si te gusta el contenido.

Una de las ideas más confusas para los desarrolladores que pasan de Android e/o iOS es entender cómo Flutter maneja su ciclo de vida.

¿Dónde está mi onCreate()? viewDidLoad()? ¿Cómo sé dónde poner mi lógica de negocios? ¿Por qué solo tengo un método de compilación? ¿Porque el cielo es azul?

¡En este post encontrarás las respuestas para todas esas preguntas!

Android

Si vienes desarrollando con el robot verde, el ciclo de vida de la actividad es algo que tuvimos que recordar tantas veces para cada entrevista de trabajo:

  • onCreate.
  • onStart
  • onResume
  • onPause
  • onStop
  • onRestart
  • onDestroy

La mayor parte de nuestro inicio de sesión terminó dentro del método onCreate: Inicio de Vistas, Base de Datos, Listeners, etc. Los ciclos de vida como onResume y onPause tienen un gran uso para saber si el usuario está abandonando o volviendo a una pantalla.

iOS

Si estas con la manzana mordida esta lógica suena tan familiar y ya conoce el ciclo de vida de un UIViewController:

  • viewDidLoad
  • viewWillAppear
  • viewDidAppear
  • viewWillDisappear
  • viewDidDisappear
  • viewDidUnload

Como puede ver, ambas plataformas utilizan (casi) la misma cantidad de pasos para crear y destruir una pantalla. viewDidLoad() mantendrá una gran parte de nuestra lógica de negocios y los Will/Did Appear/Disappear son excelentes para guardar información, saber cuándo el usuario abandona la pantalla, etc.

Flutter 💙

¿Pero qué hay de nosotros? ¿Un Widget sigue esta lógica? Si volvemos a nuestro primer conjunto de preguntas, onCreate y viewDidLoad ya han respondido en cada sistema operativo móvil, ahora necesitamos saber el equivalente para Flutter.

Si has estado trabajando con Flutter, notarás 2 widgets principales: StatelessWidget y StatefulWidget. Con el fin de hacer que este post sea válido nos centraremos en StatefulWidget ya que uno tiene una lógica similar como Android e iOS.

StatefulWidget

Este es uno de los Widgets más importantes porque tiene un Widget de Estado, este sabe cuando algo cambió y vuelve a dibujar todo lo necesario sobre nuestra pantalla. El ciclo de vida de este es el siguiente:

  • createState
  • initState
  • didChangeDependencies
  • build
  • (didUpdateWidget)
  • deactivate
  • dispose

Notarás muchos más “states” para la creación que la destrucción, esto se debe a la construcción y reconstrucción de los Widgets y su Estado.

createState()

Cuando construimos un nuevo StatefulWidget, éste llama a createState() de inmediato y este método de invalidación DEBE existir:

class MyScreen extends StatefulWidget {
@override
_MyScreenState createState() => _MyScreenState();
}

initState()

Tendrás que escribir este y también notarás lo útil que es. Es el primer método llamado después de crear el Widget. Este es nuestro equivalente a onCreate() y viewDidLoad(). Durante este ciclo de vida también podemos comprobar algunos aspectos del widget como: ¿se representó? ¿está montada actualmente?

mounted

Todos los widgets tienen estos valores y se convierten en true cuando se asigna buildContext y se encuentra actualmente en un árbol. Mantendrá esos valores hasta que se llame a dispose.

addPostFrameCallback

Este necesita ser llamado dentro de su initState() haciendo lo siguiente:

import 'package:flutter/scheduler.dart';@override
void initState() {
super.initState();
SchedulerBinding.instance.addPostFrameCallback((_) => {});
}

Esta es una devolución de llamada para el final del marco, sólo se llama una vez y sabemos con seguridad que la compilación del widget se ha completado.

didChangeDependencies()

Este método se llama inmediatamente después de initState() la primera vez que se compila el widget. Si su StatefulWidgets depende de un InheritedWidget se llamará de nuevo si es necesario un cambio.

build()

Podemos decir con seguridad que este método es el más “importante”. Aquí se retransmite todo el árbol de Widgets para ser renderizado y se llama justo después de didChangeDependencies(). Toda la interfaz gráfica de usuario se representa aquí y se llamará cada vez que la interfaz de usuario necesita ser renderizada porque dibujar de nuevo es una operación barata.

didUpdateWidget()

Tal vez esto no es un ciclo de vida que se encontrará muy a menudo, pero, como el nombre dice, se llamará una vez que el widget principal haya hecho un cambio y necesite volver a dibujar la interfaz de usuario. Obtendrá el parámetro oldWidget y podrá compararlo con el widget actual para hacer un poco de lógica adicional allí.

deactivate()

Una vez más, como didUpdateWidget, este no es común. Estamos llegando al punto en que nuestro widget empieza a “morir”.

El marco llama a este método siempre que elimina el estado del objeto State del árbol. En algunos casos, el marco reinsertará el objeto State en otra parte del árbol.

dispose()

Este es muy importante y se llama cuando este objeto y su estado se eliminan del árbol de forma permanente y nunca se volverán a construir.

Este ciclo de vida es el que necesita para cancelar la suscripción de secuencias, eliminar animaciones, etc. Es el opuesto equivalente de initState.

WidgetsBindingObserver

¿Qué pasa si necesitamos saber cuándo nuestra aplicación fue enviada a fondo? y cuando se trata de primer plano? ¿Hay alguna forma de detectar eso? Bueno … es tu día de suerte como te voy a explicar ahora.

Necesitamos hacer un pequeño cambio dentro de nuestro StatefulWidget y en particular a nuestra clase de estado:

class _MyScreenState extends State<MyScreen> with WidgetsBindingObserver

Una vez que implementamos la clase abstracta WidgetsBindingObserver, necesitamos “observar” los cambios de nuestro estado del ciclo de vida de la aplicación. Para hacerlo, necesitamos agregar lo siguiente dentro de nuestro initState:

WidgetsBinding.instance.addObserver(this);

y esta línea dentro de dispose:

WidgetsBinding.instance.removeObserver(this);

¡Excelente! ¿Pero dónde “escucho” esos cambios? didChangeAppLifecycleState será:

@override
void didChangeAppLifecycleState(AppLifecycleState state) {
super.didChangeAppLifecycleState(state);
if (state == AppLifecycleState.paused) {
// went to Background
}
if (state == AppLifecycleState.resumed) {
// came back to Foreground
}
}

¡Este truco es muy útil! Si su aplicación necesita mostrar una notificación cuando pasa a segundo plano, si necesita guardar datos en ese momento, si necesita mostrar una ventana emergente cuando el usuario está de regreso, etc. ¡hay tantos casos de uso para esta lógica!

Realmente espero que esta información sea útil para muchos desarrolladores de Android e iOS que se están mudando a Flutter. Los primeros pasos en este increíble marco pueden parecer confusos al principio, pero tener estos trucos de vida hará que tu vida sea más fácil.

Oh! ¡Casi lo olvido! “¿Porque el cielo es azul?”

La luz azul se dispersa en todas las direcciones por las pequeñas moléculas de aire en la atmósfera de la Tierra. El azul se dispersa más que otros colores porque viaja como ondas más cortas y más pequeñas. Es por eso que vemos un cielo azul la mayor parte del tiempo.

O tal vez porque se inspiró en los colores del logotipo de Flutter 💙

ENLACES INCREÍBLES

Sígueme en Twitter: https://twitter.com/resand91
Github: https://github.com/resand
Sitio Web: https://resand.gitlab.io/web

Comunidad Flutter: https://medium.com/flutter-community
Flutter en Español: https://twitter.com/EsFlutter

--

--