PREGUNTAS Y RESPUESTAS
Flutter
¿Qué es Flutter y qué problema resuelve?
Flutter es un toolkit de UI multiplataforma basado en Dart que permite compartir gran parte del código entre móvil, web y escritorio, conservando opciones de integración con el sistema anfitrión. El alcance de plataformas y las capacidades disponibles dependen de la versión estable del SDK; consulta la descripción arquitectónica y la matriz de plataformas soportadas.
¿Qué diferencia hay entre Widget, Element y RenderObject?
Un Widget es una configuración inmutable que describe una parte de la interfaz. El Element representa su instancia y posición persistente en el árbol, coordina actualizaciones y puede conservar estado; los RenderObjects resuelven layout y pintura. Esta separación permite recrear objetos Widget sin reconstruir necesariamente toda la UI; se explica en la visión arquitectónica de Flutter.
¿Cuándo conviene StatelessWidget y cuándo StatefulWidget?
Usa StatelessWidget cuando la salida solo depende de la configuración recibida y del estado heredado; usa StatefulWidget cuando una parte de UI debe conservar estado mutable local entre reconstrucciones. El Widget sigue siendo inmutable: el objeto State separado guarda el estado y notifica cambios, normalmente mediante setState. Consulta la guía de widgets con estado.
¿Cuál es el ciclo de vida de un objeto State?
El framework crea State, llama initState una vez, puede llamar didChangeDependencies y didUpdateWidget cuando cambian dependencias o configuración, y ejecuta build cada vez que necesita representar la UI. En dispose se cancelan suscripciones, controladores y timers; después de dispose no se debe actualizar ese estado. La guía de interfaz y ciclo de vida describe estos callbacks.
¿Por qué build debe ser rápido y no tener efectos secundarios?
build puede ejecutarse muchas veces, incluso más de lo que el desarrollador espera; su responsabilidad es devolver la descripción de UI para el estado actual. Evita iniciar peticiones, cambiar estado o realizar cómputos costosos allí: ejecuta efectos en una acción o ciclo de vida apropiado, y prepara datos fuera de build. Consulta la visión arquitectónica y las prácticas de rendimiento.
¿Para qué sirven las Keys y cuándo evitar GlobalKey?
Las Keys ayudan al framework a identificar qué elemento lógico corresponde a cada Widget al cambiar el árbol; en listas dinámicas, una ValueKey estable evita asociar por error el estado de una fila con otro elemento. GlobalKey permite identificar un elemento globalmente y reubicar subárboles o acceder a State, pero puede ser costosa y debe ser persistente, no recrearse en cada build. Ver Keys y ciclo de vida y la referencia de GlobalKey.
¿Cómo funciona el layout de Flutter?
El padre impone restricciones al hijo; el hijo elige un tamaño dentro de ellas; y el padre determina la posición. Por eso, ante un overflow o un tamaño inesperado, identifica primero qué restricciones recibe cada widget en vez de añadir tamaños arbitrarios. La regla y ejemplos están en Understanding constraints.
¿Qué representa BuildContext y qué cuidado requiere después de await?
BuildContext representa la ubicación de un Widget dentro del árbol, por lo que permite buscar dependencias heredadas, tema, navegación o localización. No lo uses después de una operación asíncrona si el Widget pudo desmontarse: verifica que siga mounted antes de navegar o mostrar UI. Consulta la referencia de BuildContext y su propiedad mounted.
¿Cómo hacer una UI adaptable en Flutter?
Diseña según el espacio disponible y el tipo de interacción, no solo según el modelo físico del dispositivo. MediaQuery o LayoutBuilder permiten medir el área de la app; luego puedes cambiar distribución, navegación o controles para ventanas estrechas, tabletas, plegables, teclado y mouse. La guía de diseño adaptable y responsivo explica este enfoque.
¿Dónde debe vivir el estado: dentro del Widget o compartido por la app?
El estado efímero, como un campo expandido, puede permanecer en el Widget más cercano que lo usa. El estado compartido entre pantallas debe tener una única fuente de verdad y exponerse como datos observables; la UI envía eventos y presenta el estado resultante. La guía distingue estado efímero y estado de aplicación.
¿Qué responsabilidades separa la arquitectura recomendada?
Flutter recomienda separar UI y datos: la vista representa estado y remite acciones; el ViewModel transforma datos en estado para la pantalla; el repositorio actúa como fuente de verdad y centraliza caché, errores, reintentos y sincronización; el servicio encapsula una fuente externa, como HTTP, archivos o una API nativa. Son recomendaciones adaptables, no una arquitectura obligatoria; consulta la guía de arquitectura.
¿Cuándo añadir una capa de dominio y cómo inyectar dependencias?
Añade casos de uso si una operación de negocio es compleja o se reutiliza desde varios ViewModels; una capa extra para cada operación simple añade abstracciones sin valor. Pasa dependencias por constructores para poder reemplazar servicios y repositorios en pruebas, y reserva un contenedor de DI para cuando ayude a gestionar el grafo. Ver recomendaciones de arquitectura y comunicación entre capas.
¿Cuál es la diferencia entre Future y Stream?
Future representa una operación asíncrona que termina con un resultado o error; Stream representa una secuencia de eventos a lo largo del tiempo. La UI debe modelar explícitamente carga, éxito, vacío y error, cancelar o dejar de escuchar cuando ya no necesita la fuente, y evitar que una respuesta antigua sobrescriba datos más recientes. Los servicios y repositorios suelen exponer estas abstracciones según la fuente de datos; consulta la guía de arquitectura de Flutter.
¿Qué significa concurrencia en Flutter y cuándo usar un isolate?
El código Dart se ejecuta en isolates con memoria separada, que se comunican por mensajes. Las operaciones async de I/O no necesariamente bloquean la UI; mueve cómputo pesado a un isolate cuando las mediciones indiquen jank, y evita el coste de aislar trabajo pequeño sin evidencia. Los isolates no pueden manipular widgets ni compartir estado mutable directamente; ver Concurrency and isolates.
¿Cómo responder a cambios del ciclo de vida de la aplicación?
Una app puede perder foco, quedar en pausa, volver al primer plano o separarse del motor; no asumas que el proceso seguirá vivo para guardar datos al final. Observa los cambios mediante AppLifecycleListener o WidgetsBindingObserver y pausa o reanuda recursos que realmente dependan de visibilidad, como reproducción o sensores. Los estados y transiciones exactos varían según plataforma; consulta la referencia de AppLifecycleListener.
¿Cómo estructurar una petición HTTP y manejar sus fallos?
Aísla el transporte en un servicio, convierta JSON a modelos comprobables y deja al repositorio decidir caché, reintentos y política de errores. Representa en la UI estados de carga, datos y error; no trates una respuesta HTTP no exitosa como éxito solo porque la conexión terminó. Flutter documenta el paquete HTTP y solicitudes de red y el manejo de JSON.
¿Qué almacenamiento local elegir?
Usa preferencias clave-valor para ajustes simples; usa SQLite para datos estructurados consultables y relaciones; reserva una base remota para sincronizar información entre usuarios o dispositivos. No guardes tokens ni secretos como preferencias normales: el almacenamiento sensible requiere mecanismos protegidos del sistema y una revisión del paquete usado. La guía oficial compara opciones de bases de datos.
¿Qué significa diseñar una función offline-first?
La interfaz debe poder leer datos locales y seguir siendo útil sin red; el repositorio coordina el almacén local con el remoto y define cuándo sincronizar, cómo tratar reintentos y cómo resolver conflictos. Primero acuerda el contrato de consistencia con el producto: algunas funciones muestran datos almacenados, otras exigen actualización explícita. Consulta Offline-first support.
¿Cuándo usar un plugin, Platform Channel o FFI?
Evalúa primero un plugin mantenido que cubra la API nativa. Platform Channels intercambian mensajes asíncronos entre Dart y código de plataforma; FFI enlaza directamente con bibliotecas nativas, por ejemplo C. Decide según APIs disponibles, coste de mantenimiento por plataforma, requisitos de tiempo real y soporte de las plataformas objetivo; los detalles de integración pueden cambiar según SDK y versión. Ver platform channels y FFI.
¿Qué principios de accesibilidad deben acompañar el diseño visual?
Usa semántica y etiquetas comprensibles para lectores de pantalla, controles interactivos con áreas táctiles suficientes, contraste legible y layouts que sigan funcionando al aumentar el texto. Prueba navegación con TalkBack o VoiceOver y no comuniques información solo por color o iconos sin descripción. Consulta accesibilidad en Flutter y diseño y estilo accesibles.
¿Cómo comprobar accesibilidad automáticamente y manualmente?
Las pruebas de widgets pueden validar etiquetas, tamaño de objetivos táctiles y contraste mediante la Accessibility Guideline API. Compleméntalas con lectores de pantalla e inspectores de plataforma: una prueba automatizada no confirma por sí sola que el orden y los anuncios sean comprensibles. Ver Accessibility testing.
¿Qué cubren las pruebas unitarias, de widgets e integración?
La prueba unitaria verifica una función o clase aislada; la prueba de widgets valida UI y eventos con el entorno de Flutter; la de integración recorre un flujo amplio en dispositivo o emulador. Pon la mayoría de las comprobaciones rápidas cerca de la lógica, y cubre los recorridos críticos de extremo a extremo aunque sean más lentos. Consulta la visión general de pruebas.
¿Cómo diagnosticar jank o renderizado lento?
Reproduce el flujo en un dispositivo físico, activa modo profile y usa DevTools Performance para encontrar cuadros tardíos, trabajo costoso en build o pintura, y reconstrucciones innecesarias. Optimiza tras medir, no solo porque una clase parezca costosa; debug y emuladores no representan de forma fiable la experiencia de release. Ver perfilado de rendimiento y buenas prácticas.
¿Qué herramientas usar para investigar errores, red o memoria?
Usa el debugger de DevTools con breakpoints y stack trace para reproducir fallos; el Inspector para inspeccionar árbol, constraints y overflow; Network View para revisar solicitudes; y Memory View para buscar retención o asignaciones excesivas. Elige la herramienta según la hipótesis y registra un caso reproducible. La suite DevTools enlaza Inspector, Network View y Memory View.
¿Qué significa proteger una app Flutter frente a la extracción del cliente?
No incluyas credenciales privadas, secretos de servidor ni claves con privilegios en el binario: cualquier dato distribuido al dispositivo puede extraerse. El HTTPS y controles del backend son esenciales; la ofuscación puede dificultar la lectura del código, pero no cifra recursos ni evita ingeniería inversa. Consulta la advertencia oficial sobre ofuscación de Dart.
¿Qué revisar antes de crear una compilación de producción?
Separa configuración de desarrollo, prueba y producción con flavors; revisa identificadores, endpoints, permisos, firma y assets por variante, y prueba el artefacto release en dispositivos objetivo. Conserva mapas de símbolos si ofuscas para poder simbolizar fallos. La guía de publicación y la guía de flavors para Android describen pasos concretos, que varían por plataforma y versión.
En una entrevista, ¿cómo decidirías si Flutter es adecuado para un producto?
Relaciona la decisión con objetivos: porcentaje real de UI y lógica compartible, experiencia que esperan los usuarios por plataforma, integraciones nativas, rendimiento medido, capacidades del equipo y coste de mantener plugins. Un prototipo debe probar los riesgos principales en dispositivos representativos; que el código se comparta no elimina la necesidad de diseño, pruebas y revisión por plataforma. Consulta arquitectura de Flutter y adaptaciones de plataforma.