PMDM · Tema 2

Componentes y ciclo de vida

De qué está hecha una aplicación Android por dentro, cómo se declara en el Manifest, y cómo sobrevive (o no) a los cambios que le impone el sistema.

Mapa del tema

Cinco paradas hasta entender por qué Android manda

01

Componentes y Manifest

Las cuatro piezas de una app y la tarjeta de identidad que las declara.

02

Intents y Navigation Component

Cómo se comunican los componentes, y cómo se navega hoy entre pantallas: una Activity, varios destinos.

03

Recursos

Layouts, drawables, strings y cualificadores de configuración.

04

Ciclo de vida de la Activity

Los callbacks que deciden si tu app pierde datos al girar la pantalla.

05

App y control de versiones

El ciclo de vida de la app como producto, y Git como herramienta obligatoria.

01 · Componentes de una app Android

No hay un main()

  • →En Programación el programa arranca en un punto único y se ejecuta de arriba a abajo.
  • →En Android una app es un conjunto de piezas independientes que el sistema crea, destruye y combina según lo necesite.
  • →No decides tú cuándo se ejecuta tu código: es el sistema quien llama a tus componentes cuando hace falta.
Sistema Android Activity Service Receiver Content Provider
01 · Componentes de una app Android

Los cuatro tipos de componente

ComponentePara qué sirve
ActivityRepresenta una pantalla con la que interactúa el usuario. El más usado, con diferencia.
ServiceEjecuta trabajo en segundo plano, sin interfaz propia (música, sincronización, descargas).
Broadcast ReceiverEscucha anuncios del sistema u otras apps (batería baja, cambio de red, arranque).
Content ProviderGestiona acceso a datos compartidos entre aplicaciones. El menos usado de los cuatro.

Cualquier app está construida combinando algunos de estos cuatro bloques — no hace falta usarlos todos.

01 · Componentes de una app Android

Activity: una pantalla

  • →Una pantalla (login, listado, detalle, ajustes...). En este curso, todas conviven dentro de una única Activity como destinos de navegación.
  • →Ciclo de vida propio, gestionado por el sistema: se crea, se pausa, se reanuda, se destruye.
MainActivity.kt
class MainActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) } }
01 · Componentes de una app Android

Service y Broadcast Receiver

SERVICE

Trabajo en segundo plano

Sin interfaz propia. Sirve para operaciones que continúan aunque el usuario cambie de pantalla: reproducir música, sincronizar, descargar.

Ojo: no crea un hilo nuevo por defecto — corre en el hilo principal, igual que una Activity.

BROADCAST RECEIVER

Escucha anuncios del sistema

Batería baja, cambio de conectividad, SMS entrante, arranque del dispositivo. Sin interfaz, trabajo breve: recibe y delega.

BateriaBajaReceiver.kt
class BateriaBajaReceiver : BroadcastReceiver() { override fun onReceive(context: Context, intent: Intent) { // Reaccionar al evento del sistema } }
01 · Componentes de una app Android

Content Provider

  • →Acceso a datos compartidos entre aplicaciones, mediante una interfaz uniforme parecida a una base de datos.
  • →Ejemplo real: la app de Contactos deja que otras apps consulten (con permiso) los contactos del usuario.
  • →El menos usado de los cuatro en aplicaciones típicas; se retoma al trabajar almacenamiento compartido.

Confundir un Service con una Activity es un error típico de principiante: cada componente tiene ciclo de vida y reglas distintas.

01 · El AndroidManifest.xml

La tarjeta de identidad de la app

  • →Declaración obligatoria: todo componente que la app quiera usar debe estar en el Manifest, en la raíz de src/main/.
  • →Si no está declarado, el sistema no sabe que existe y la app falla al intentar usarlo.
AndroidManifest.xml
<activity android:name=".MainActivity" android:exported="true"> <intent-filter> <action android:name="...MAIN" /> <category android:name="...LAUNCHER" /> </intent-filter> </activity> <service android:name=".SincronizacionService" /> <receiver android:name=".BateriaBajaReceiver" />
01 · El AndroidManifest.xml

Preguntas que el Manifest responde

PreguntaDónde se responde
¿Qué componentes tiene la app?<activity>, <service>, <receiver>, <provider>
¿Por dónde se arranca?El <intent-filter> con MAIN y LAUNCHER
¿Qué permisos necesita?<uses-permission>
¿Qué versiones de Android soporta?minSdk, targetSdk
¿Qué icono y nombre muestra?android:icon, android:label
01 · El AndroidManifest.xml

El intent-filter de arranque y exported

intent-filter
<intent-filter> <action android:name= "android.intent.action.MAIN" /> <category android:name= "android.intent.category.LAUNCHER" /> </intent-filter>
  • →"Esta es la Activity" que se abre al tocar el icono. Sin ella, la app se instala pero no aparece en el launcher.
  • →android:exported indica si el componente puede ser invocado por otras apps. Obligatorio declararlo desde Android 12 si hay intent-filter.
  • →Por defecto, false salvo que exista una razón concreta para exponer el componente.
01 · Intents

Cómo se comunican los componentes

  • →Intent: un objeto que describe una intención de acción. Es el mecanismo para pasar de un componente a otro o pedirle algo al sistema.
Componente propio Intent Otro componente / Sistema
01 · Intents

Intent explícito vs. implícito

EXPLÍCITO

Se sabe qué componente

Indica exactamente qué componente se quiere lanzar: por ejemplo, un Service propio o una Activity de otra app conocida.

IMPLÍCITO

Se describe la acción

Describe una acción a realizar sin decir quién la hace. El sistema busca entre las apps instaladas cuál puede resolverla.

explícito
val intent = Intent(this, MiServicioDeSincronizacion::class.java) startService(intent)
implícito
val intent = Intent(Intent.ACTION_VIEW, Uri.parse("https://www.google.com")) startActivity(intent)

Extras: los datos que viajan con putExtra deben ser serializables (primitivos, String, Parcelable...).

01 · Intents

¿Y para moverse entre pantallas propias?

  • →Antes se lanzaba un Intent explícito hacia otra Activity para cambiar de pantalla dentro de la misma app.
  • →En este curso, no: cada app tendrá una única Activity, y las pantallas serán destinos de navegación dentro de ella.

Ese enfoque moderno se llama Navigation Component, y es lo que viene a continuación.

01 · Navigation Component

Una Activity, muchos destinos

  • →Grafo de navegación: describe de forma declarativa qué destinos existen y cómo se conectan.
  • →NavController: ejecuta ese grafo. Navegar sustituye a lanzar un Intent explícito y llamar a startActivity.
  • →Argumentos tipados: el equivalente a los extras de un Intent, pero sin depender de claves de texto.
Navegación
// navegar al destino "detalle" navController.navigate( R.id.detalleFragment, bundleOf("idElemento" to 42) )

Adelanto: el Navigation Component se trabajará en profundidad en la unidad 3, con su grafo visual y NavHost. De momento basta con la idea: una Activity, varios destinos.

02 · Recursos

Código y recursos, separados

  • →La carpeta res/ guarda todo lo que no es lógica en Kotlin, organizado por tipo.
  • →Clase R generada automáticamente: cada recurso recibe un identificador (R.layout.activity_main, R.string.app_name).
res/
res/ ├── layout/ ← diseños XML ├── drawable/ ← imágenes, iconos ├── mipmap/ ← iconos de la app ├── values/ │ ├── strings.xml │ ├── colors.xml │ └── styles.xml ├── menu/ ├── anim/ └── raw/
02 · Recursos

Layouts: diseño de pantalla en XML

activity_main.xml
<LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> <TextView android:id="@+id/tituloTextView" android:text="@string/titulo" /> <Button android:id="@+id/aceptarButton" /> </LinearLayout>
  • →@+id vs @id: crea un identificador nuevo vs. referencia uno existente. Nunca texto literal en el layout.
  • →match_parent / wrap_content: todo el espacio del padre vs. solo lo necesario.
  • →setContentView infla el layout; findViewById accede a sus vistas por id.
02 · Recursos

Drawables y strings.xml

DRAWABLES

Cualquier cosa dibujable

Imágenes (.png, .webp), iconos vectoriales y formas XML. Los VectorDrawable escalan sin perder calidad a cualquier densidad.

STRINGS.XML

Textos centralizados

Todo texto visible va aquí, nunca en el layout o el código: permite internacionalización (values-en/) y mantenimiento en un solo sitio.

res/drawable/fondo_boton.xml
<shape android:shape="rectangle"> <solid android:color="@color/primario" /> <corners android:radius="8dp" /> </shape>
02 · Recursos

Cualificadores de configuración

CualificadorEjemplo de carpetaSelecciona según...
Idiomavalues-en/Idioma del sistema
Orientaciónlayout-land/Orientación actual del dispositivo
Ancho mínimolayout-sw600dp/Tamaño de pantalla (tablets)
Densidaddrawable-xxhdpi/Densidad de píxeles
Temavalues-night/Modo claro u oscuro

El sistema resuelve automáticamente qué versión usar en tiempo de ejecución: no se escribe ningún if para esto.

03 · Ciclo de vida de la Activity

La idea más importante del tema

  • →Memoria limitada y compartida entre todas las apps abiertas: el sistema puede matar una app en segundo plano sin avisar.
  • →El ciclo de vida es la respuesta de Android: estados y callbacks para que la app se entere de lo que le pasa y reaccione a tiempo.
  • →Consecuencia: una Activity mal preparada pierde datos del usuario en cuanto gira la pantalla o cambia de app un momento.
03 · Ciclo de vida de la Activity

Los tres estados

EstadoQué significa
Activo (resumed)En primer plano, el usuario interactúa con ella.
Pausado (paused / stopped)Sigue viva pero sin foco: parcialmente visible o completamente oculta.
DestruidoHa dejado de existir. El sistema liberó sus recursos.

Estos tres estados se traducen en una secuencia más fina de callbacks que Android invoca sobre la Activity.

03 · Ciclo de vida de la Activity

Los callbacks del ciclo de vida

MainActivity.kt
class MainActivity : AppCompatActivity() { override fun onCreate(s: Bundle?) { /* inicializar vistas */ } override fun onStart() { /* se hace visible */ } override fun onResume() { /* gana el foco */ } override fun onPause() { /* pierde el foco */ } override fun onStop() { /* ya no es visible */ } override fun onDestroy() { /* se libera */ } }
03 · Ciclo de vida de la Activity

Flujo normal de arranque y cierre

onCreate onStart onResume en uso onPause onStop

Tras onStop vendría onDestroy si la Activity se destruye del todo.

03 · Ciclo de vida de la Activity

Cambiar de app un momento

Si el usuario pulsa inicio y vuelve enseguida, no se pasa por onCreate ni onDestroy:

onPause onStop usuario vuelve onStart onResume

La Activity sigue viva en memoria, simplemente detenida: por eso onStop/onStart son distintos de onCreate/onDestroy.

03 · Ciclo de vida de la Activity

El caso que rompe apps de principiante: rotar la pantalla

  • 1Cambio de configuración: girar el dispositivo cuenta como tal para Android (como los cualificadores layout-land/).
  • 2Destruye la Activity actual: onPause → onStop → onDestroy.
  • 3La recrea desde cero: onCreate → onStart → onResume, cargando el layout adecuado a la nueva orientación.

Cualquier variable en memoria se pierde si no se ha hecho nada para evitarlo: un formulario a medio rellenar desaparece con un simple giro.

03 · Ciclo de vida de la Activity

Guardar estado: onSaveInstanceState

MainActivity.kt
override fun onSaveInstanceState(outState: Bundle) { super.onSaveInstanceState(outState) outState.putString("texto_usuario", campoTexto.text.toString()) } override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) if (savedInstanceState != null) { val texto = savedInstanceState.getString("texto_usuario") } }

Se invoca antes de destruirse por cambio de configuración; el Bundle vuelve como parámetro de onCreate.

03 · Ciclo de vida de la Activity

Diagrama de transición de estados

onStop →

onRestart → onStart

El usuario vuelve a la app tras haberla dejado del todo en segundo plano.

onStop →

onDestroy

El sistema la mata definitivamente por falta de memoria o cierre completo.

Diagrama completo del ciclo de estados: apuntes del tema 2 · apartado C.

03 · Ciclo de vida de la Activity

Observarlo con Logcat

MainActivity.kt
private val TAG = "CicloVida" override fun onCreate(s: Bundle?) { super.onCreate(s) Log.d(TAG, "onCreate") setContentView(R.layout.activity_main) } override fun onStart() { super.onStart() Log.d(TAG, "onStart") } // ... resto de callbacks
  • →Logcat + filtro por la etiqueta CicloVida muestra el orden exacto de llamadas.
  • →Provoca y observa: girar la pantalla, pulsar inicio y volver, cerrar y reabrir.
  • →La mejor forma de convertir esta teoría en algo tangible.
04 · Ciclo de vida de la app y Git

El ciclo de vida de la app como producto

FaseQué ocurre
DescubrimientoTienda de apps, búsqueda, recomendación, enlace directo.
InstalaciónEl sistema descarga el paquete, verifica firma y permisos.
EjecuciónCombina internamente los ciclos de vida de Activities, Services y demás.
ActualizaciónSustituye el paquete, normalmente conservando los datos del usuario.
BorradoDesinstalación: libera el espacio ocupado.

versionCode / versionName existen para que el sistema sepa si un paquete nuevo es realmente más reciente.

04 · Ciclo de vida de la app y Git

Procesos en segundo plano

  • →"Cerrar" no es destruir: al pulsar inicio, el proceso normalmente sigue vivo en segundo plano una temporada.
  • →Jerarquía de prioridades: cuando el sistema necesita memoria, mata procesos en segundo plano empezando por los de menor prioridad.
  • →Conecta con onSaveInstanceState: ambos mecanismos existen para que ese cierre silencioso no se note al volver a abrir la app.
04 · Ciclo de vida de la app y Git

El administrador de aplicaciones

  • →Ajustes → Aplicaciones: inspecciona y actúa sobre el ciclo de vida de cualquier app instalada.
  • →Forzar detención simula que el sistema la ha matado — útil para depurar un arranque limpio.
  • →Borrar caché (recuperable) vs. borrar datos (como reinstalar desde cero).
→

Ver versión y espacio

App, datos y caché.

→

Revocar permisos

Y desinstalar.

04 · Ciclo de vida de la app y Git

Modificar una app existente

  • 1Lee el AndroidManifest.xml primero: mapa rápido de componentes y punto de entrada.
  • 2Localiza la Activity de arranque (el intent-filter con MAIN/LAUNCHER) y sigue el flujo desde ahí.
  • 3Identifica la estructura de paquetes: por capa (ui, data, model) o por característica.
  • 4Ejecuta la app antes de tocar nada, como punto de referencia.
  • 5Haz el cambio mínimo necesario y vuelve a probar.
04 · Ciclo de vida de la app y Git

Git: obligatorio desde este tema

  • →Historial de cambios: volver a un estado anterior sin depender de copias manuales de carpetas.
  • →Trazabilidad del trabajo: el seguimiento continuo del Proyecto A se apoya en commits regulares, no solo en la entrega final.
bash
$ git init $ git add . $ git commit -m "Esqueleto inicial del proyecto" # tras cada avance con sentido: $ git add . $ git commit -m "Añade pantalla de detalle"
04 · Ciclo de vida de la app y Git

Buenas prácticas de commit

  • →Commits pequeños y frecuentes, no un único commit gigante al final del tema.
  • →Mensajes que describan el qué y, si hace falta, el porqué — no "cambios" o "arreglos".
  • →El proyecto debe compilar tras cada commit, siempre que sea razonablemente posible.

Qué NO se sube: carpetas de compilación (build/) y ficheros locales del IDE. Revisa el .gitignore que trae el proyecto, no lo sustituyas por uno genérico.

Actividades del tema

De la teoría a la práctica

  • A2.1Análisis de una app de código abierto — Jetnews, dentro de android/compose-samples: Activities, destinos de navegación, componentes, Manifest y estructura de paquetes.
  • A2.2Modificación funcional de esa misma app: un cambio pequeño pero visible, documentado.
  • A2.3Experimento de ciclo de vida: trazas de Log.d en todos los callbacks, Logcat y onSaveInstanceState.
  • A2.4Hito de proyecto: esqueleto del Proyecto A, con Git desde el primer commit.
PMDM · Tema 2

El sistema manda, tu código reacciona

Entender el ciclo de vida no es un trámite: es la diferencia entre una app que respeta al usuario y una que le hace perder su trabajo con un simple giro de pantalla.

01 / 01
PMDM · Tema 2