98. La Actividad en Android (Activity)¶
Vamos a ver:
- Las Actividades
- Ciclo de vida de una aplicación
- Intent y filtros
- Intent Explícitos
- Intent Implícitos
- Iniciar otras Actividades
- Filtros
- PendingIntent
Terminos usados en este tema
Proceso, Aplicación, Activity, Intent, Parcelable, Bundle,intent implicito, intent explicito, ciclo de vida de la actividad.
98.1 Activity¶
Una Activity en Android representa una única pantalla con una interfaz de usuario. En el contexto de la programación, una Activity pasa por varios estados reflejados en su ciclo de vida, manejados a través de métodos de callback como onCreate(), onStart(), onResume(), onPause(), onStop() y onDestroy().
Por ejemplo, cuando se retoma una Activity ( cuando el usuario regresa a ella después de haber utilizado otra aplicación), el sistema invoca el métodoonResume()
. En este punto, la Activity entra en primer plano y el usuario puede interactuar con ella. Es aquí donde se debe reanudar cualquier operación suspendida que se haya pausado en onPause()
, como reanudar la reproducción de animaciones o música, o la ejecución de hilos suspendidos. Las operaciones que consumen recursos intensivos que no son necesarias cuando la Activity no está en primer plano deben ser pausadas o detenidas en onPause(), y típicamente se reanudarían o reiniciarían en onResume().
Con la llegada de Jetpack Compose no necesitamos tener una Activity por ventana. Usando esta librería podemos tener varias pantallas con la misma Activity.
En este caso la Activity sigue siendo útil para separar el código desde el punto de vista lógico y para exportar la Activity para ser usada en otras aplicaciones.
98.1.1 Ciclo de vida de la activity¶
(Seguir en AD)
Una activity pasa por una serie de estados que son controlador por Android:
Las transiciones entre estados se procesan en el código mediante llamadas (callback) en el programa.
- onCreate() : Sólo al crear la Activity. Es el momento de inicializar los componentes.
- onStart(): Al terminar onCreate se invoca onStart() y es el momento en el que la Activity se hace visible para el usuario.
-
onResume() Se invoca justo antes de que la app interactúe con el usuario. En este momento la Activity es la primera de la pila de ventanas. En esta función se implementa la mayor parte de la lógica de la Activity.
-
onPause() : El sistema llama onPause cuando la app pierde el foco o pasa al estado detenido.No debe usarse onPause() para guardar datos de la aplicación o del usuario, realizar llamadas de red o ejecutar transacciones de base de datos. Para obtener más información sobre cómo guardar datos, consulta Cómo guardar y restablecer el estado de la actividad.
-
onStop() : El sistema llama a onStop() cuando la actividad ya no es visible para el usuario, lo cual puede ocurrir porque se está eliminando la actividad, porque se inicia una nueva o porque una ya existente pasa al estado Reanudada y cubre la actividad que se detuvo. En todos estos casos, la actividad detenida ya no está visible en absoluto.
-
onRestart : El sistema invoca esta devolución de llamada cuando una actividad en estado Detenida está por volver a iniciarse. onRestart() restaura el estado de la actividad desde el momento en que esta se detuvo.
- onDestroy : El sistema invoca esta devolución de llamada antes de que se elimine una actividad. Suele implementarse a fin de garantizar que todos los recursos de una actividad se liberen cuando esta, o el proceso que la contiene, se elimina.
Detalles y ejemplos en la documentación Androids
98.1.2 Conservar el estado de una aplicación.¶
En Android, conservar el estado de una aplicación es crucial cuando se enfrentan cambios como rotaciones de pantalla, cambios de configuración o cuando el sistema destruye y recrea una Activity para reclamar recursos. Existen varias formas de conservar y restaurar el estado:
- Guardar estado de instancia
- Utilizar
onSaveInstanceState(Bundle)
para guardar datos temporales. -
Restaurar datos en
onCreate(Bundle)
oonRestoreInstanceState(Bundle)
. -
ViewModel
-
Mantener datos a través de
ViewModel
para sobrevivir a cambios de configuración. El ciclo de vida de la Activity y del ViewModel son independientes. -
Persistencia de datos
-
Almacenar datos más complejos o permanentes en bases de datos,
SharedPreferences
o en archivos. -
Estado de vista guardado
-
Guardar y restaurar el estado personalizado de vistas sobrescribiendo
onSaveInstanceState()
yonRestoreInstanceState(Parcelable)
. -
Jetpack DataStore
-
Almacenar pares clave-valor o datos tipados de manera asíncrona y segura.
-
Estado de navegación
-
Usar argumentos y estados guardados en la biblioteca de Navegación de Jetpack.
-
Procesos en segundo plano y servicios
- Utilizar servicios o WorkManager para ejecución de procesos largos y manejo de tareas en segundo plano.
98.1.3 Administrar los cambios de configuración¶
Los cambios de configuración suelen estar relacionados con interacciones del usuario.
Algunos cambios típicos:
- El tamaño de visualización de la app
- Orientación de la pantalla
- Tamaño y grosor de la fuente
- Configuración regional
- Diferencias entre el modo oscuro y el modo claro
- Disponibilidad del teclado
El sistema recrea una Activity cuando se produce un cambio de configuración. Para ello, el sistema llama a onDestroy()
y destruye la instancia de Activity existente. Luego, crea una instancia nueva con onCreate()
, y esta nueva instancia de Activity se inicializa con la configuración nueva y actualizada. Al recrearse se pueden cargar nuevos recuros y cabiar la IU.
98.1.3.1 Restringir la recreación automática de actividades.¶
Para inhabilitar la recreación de actividades por ciertos cambios de configuración, agrega el tipo de configuración a android:configChanges en la entrada <activity>
de tu archivo AndroidManifest.xml. Los valores posibles aparecen en la documentación del atributo android:configChanges
.
En el siguiente ejemplo se evita la recreación automática para el giro de pantalla y la disponibilidad del teclado
<activity
android:name=".MyActivity"
android:configChanges="orientation|screenSize|screenLayout|keyboardHidden"
android:label="@string/app_name">
98.1.3.2 Reacción a los cambios con Compose.¶
El objeto Configuration está disponible en la jerarquía de la IU de Compose con el elemento local de composición de LocalConfiguration. Cada vez que cambia, se vuelven a componer las funciones de componibilidad que leen de LocalConfiguration.current. Para obtener información sobre cómo funcionan los elementos locales de composición, consulta Datos de alcance local con CompositionLocal.
Ejemplo:
En el siguiente ejemplo, un elemento componible muestra una fecha con un formato específico. Este objeto componible reacciona a los cambios de configuración regional del sistema llamando a ConfigurationCompat.getLocales() con LocalConfiguration.current
.
@Composable
fun DateText(year: Int, dayOfYear: Int) {
val dateTimeFormatter = DateTimeFormatter.ofPattern(
"MMM dd",
ConfigurationCompat.getLocales(LocalConfiguration.current)[0]
)
Text(
dateTimeFormatter.format(LocalDate.ofYearDay(year, dayOfYear))
)
}
android:configChanges
como locale|layoutDirection
.
Practicas recomendadas para los cambios de configuración
98.2 INICIAR UNA NUEVA ACTIVITY¶
Para iniciar una nueva actividad desde la primera Activity se invoca:
startActivity(android.content.Intent)
para lo que necesitamos un Intent
como se explica en el siguiente apartado
98.3 Intent y filtros¶
En Android, un Intent (Intención) es una descripción abstracta de una operación a realizar ( que se implementa en una clase ). Actúa como un mensajero entre componentes de una aplicación (como actividades, servicios o receptores de difusión) o entre aplicaciones diferentes.
Para que usamos los Intent:
- Iniciar una actividad: Para iniciar una nueva Activity, se envía un Intent con el contexto y la clase de la Activity destino.
- Iniciar un servicio: Para iniciar o comunicarse con un Service, se utiliza un Intent para definir qué servicio se debe iniciar o vincular.
- Entregar un broadcast: Se utilizan para enviar un mensaje a través del sistema que cualquier BroadcastReceiver puede escuchar y responder.
- Comunicación de datos: Los Intent pueden llevar datos a través de "extras" (un Bundle de datos adicionales) donde se ponen pares clave-valor.
- Solicitar acciones: Pueden solicitar acciones de otros componentes, como tomar una foto, abrir una URL, o compartir contenido.
Los Intent también pueden incluir varias banderas (flags) que instruyen al sistema operativo sobre cómo lanzar una actividad y cómo relacionarla con la pila (stack) actual de actividades
Ver más sobre flags:
En general un Intent consta de dos partes:
- action: la acción que se va a realizar, ejemplo ACTION_VIEW, ACTION_EDIT, ACTION_MAIN,
- data: Los dato necesarios para realizar la acción.
Hay otros atributos secundarios posibles :
-
Category -- Indican información adicional sobre la operación. Por ejemplo, CATEGORY_LAUNCHER means it should appear in the Launcher as a top-level application, while CATEGORY_ALTERNATIVE means it should be included in a list of alternative actions the user can perform on a piece of data.
-
type -- Especifica un tipo explícito (un tipo MIME) de los datos del intent. Normalmente, el tipo se infiere de los propios datos. Al establecer este atributo, desactivas esa evaluación y fuerzas un tipo explícito.
-
component -- Especifica un nombre explícito de una clase de componente para usar en el intent. Normalmente, esto se determina al observar la otra información en el intent (la acción, los datos/tipo y las categorías) y hacer coincidir eso con un componente que pueda manejarlo. Si este atributo está establecido, entonces ninguna de las evaluaciones se realiza, y este componente se utiliza tal cual. Al especificar este atributo, todos los demás atributos del Intent se vuelven opcionales.
-
extras -- Este es un Bundle de cualquier información adicional. Se puede usar para proporcionar información extendida al componente. Por ejemplo, si tenemos una acción para enviar un mensaje de correo electrónico, también podríamos incluir piezas adicionales de datos aquí para proporcionar un asunto, cuerpo, etc.
Hay dos tipos de Intent en Android: explícitos y implícitos.
98.3.1 Intent explícitos¶
Se usan para iniciar un componente específico, proporcionando la clase Java o Kotlin directamente.
Se utilizan comúnmente para iniciar actividades dentro de la misma aplicación o para iniciar servicios que se ejecutan en segundo plano.
val intent = Intent(this, MiActividad::class.java)
startActivity(intent)
El primer argumento de Intent es el contexto, que si se inicia desde otra activity, será el contexto de esta activity.
98.3.2 Intent implícitos¶
No especifican directamente el componente; en su lugar declaran una acción general para ejecutar, esto permite que cualquier componente de cualquier aplicación que pueda manejar esa acción responda.
Se usan para realizar acciones con los componentes de otras aplicaciones, como abrir una URL en un navegador web o compartir datos.
val intent = Intent(Intent.ACTION_VIEW, Uri.parse("http://www.example.com"))
startActivity(intent)
val tomarFotoIntent = Intent(MediaStore.ACTION_IMAGE_CAPTURE)
startActivityForResult(tomarFotoIntent, REQUEST_IMAGE_CAPTURE)
98.4 Objetos "Parcelable" y "Bundle" (atillo, paquete)¶
Cuando necesitamos enviar datos a la segunda activity usamos Bundle
(atillo) o un Parcelable
98.4.1 Enviar datos entre actividades¶
Cuando una app crea un objeto Intent para usar en startActivity(android.content.Intent) al iniciar una nueva Actividad, la app puede pasar parámetros por medio del método putExtra(java.lang.String, java.lang.String)
.
val intent = Intent(this, MyActivity::class.java).apply {
putExtra("media_id", "a1b2c3")
// ...
}
startActivity(intent)
apply{}
es una función de extensión de Kotlin. En este ejemplo apply proporciona al bloque el objeto Intent recien creado. Todo el codigo del bloque actua sobre el objeto: intet.putExtra() )
Android empaqueta el Bundle
, crea la nueva actividad y desempaqueta el Bundle y se lo pasa a la nueva actividad.
Datos que puede contener el Bundle:
- Tipos Primitivos: Como int, long, short, float, double, byte, boolean, y char.
- Cadenas de Texto: Objetos de tipo String.
- Arreglos: Tanto de tipos primitivos (como int[], long[], etc.) como de objetos (como String[]).
- Serializable: Cualquier objeto que implemente la interfaz Serializable.
-
Parcelable: Objetos que implementan la interfaz Parcelable, que es una forma de serialización específica de Android.
-
ArrayLists: Pueden ser de tipos primitivos envueltos (como Integer, Long, etc.), String, CharSequence, o cualquier objeto que implemente Parcelable.
-
Otros tipos de datos complejos: Como SparseArray, Bundle, Size, SizeF, entre otros.
Cuando se envian datos mediante un intent, debes tener cuidado de limitar el tamaño de los datos a unos pocos KB, ya que, si se envían demasiados, es posible que el sistema arroje una excepción TransactionTooLargeException.
98.5 Filtros¶
Los filtros en programación Android, conocidos como Intent Filters, es la funcionalidad que permite definir cómo se puede acceder a una actividad o servicio dentro de una aplicación. Un Intent Filter se define en el archivo de manifiesto de la aplicación (AndroidManifest.xml) y declara las capacidades de un componente qué acciones puede realizar (como ver, editar, compartir) y qué tipos de datos puede manejar (como imágenes, texto, audio).
Cuando una aplicación emite un Intent (un mensaje asíncrono que permite solicitar una acción de otro componente de la aplicación o de otra aplicación), el sistema utiliza los filtros de intenciones para determinar qué componentes pueden responder a ese Intent. Esto incluye abrir una actividad, iniciar un servicio o entregar un mensaje a un receptor de emisión (BroadcastReceiver).
Los filtros de intención pueden especificar:
- Acciones (
<action>
): Las tareas generales que puede realizar un componente, como ACTION_VIEW, ACTION_EDIT. - Categorías (
<category>
): Proporcionan información adicional sobre cómo se debe ejecutar una acción, como CATEGORY_LAUNCHER que indica que la actividad es la entrada principal de la aplicación. - Datos (
<data>
): Especifican el tipo de datos que el componente puede manejar, incluyendo el tipo MIME y el esquema URI.
Ejemplo de definición de filtro de Intent
<activity android:name=".ExampleActivity" android:icon="@drawable/app_icon">
<intent-filter>
<action android:name="android.intent.action.SEND" />
<category android:name="android.intent.category.DEFAULT" />
<data android:mimeType="text/plain" />
</intent-filter>
</activity>
Más detalles sobre como Android decide que intent usar según los filtros (intent resolution)
98.6 Listado de intent implícitos¶
La referencia completa de filtros de intent e intent explicitos en AD
- Abrir una URL en un Navegador
- Acción:
Intent.ACTION_VIEW
-
Datos: URI de la página web (por ejemplo,
Uri.parse("http://www.ejemplo.com")
) -
Realizar una Llamada
- Acción:
Intent.ACTION_DIAL
-
Datos: URI con el número de teléfono (por ejemplo,
Uri.parse("tel:123456789")
) -
Enviar un SMS
- Acción:
Intent.ACTION_SENDTO
-
Datos: URI con el protocolo
sms:
y el número de teléfono -
Enviar un Email
- Acción:
Intent.ACTION_SENDTO
-
Datos: URI con el protocolo
mailto:
y la dirección de email -
Compartir Contenido
- Acción:
Intent.ACTION_SEND
-
Extras:
Intent.EXTRA_TEXT
para el texto a compartir -
Abrir una Ubicación en un Mapa
- Acción:
Intent.ACTION_VIEW
-
Datos: URI con la ubicación en formato
geo:
-
Tomar una Fotografía
-
Acción:
MediaStore.ACTION_IMAGE_CAPTURE
-
Elegir un Archivo
- Acción:
Intent.ACTION_GET_CONTENT
-
Tipo: Tipo de contenido a seleccionar (por ejemplo,
"image/*"
para imágenes) -
Reproducir un Video
- Acción:
Intent.ACTION_VIEW
- Datos: URI del video
-
Tipo:
"video/*"
-
Configuración del Sistema
- Acción:
android.provider.Settings.ACTION_SETTINGS
- Acción:
ver más:
* Intent comunes
98.7 Pending Intent¶
Los PendingIntent
son útiles porque permiten que la aplicación delegue operaciones a realizarse en el futuro, en un contexto donde la aplicación podría no estar ejecutándose activamente. Por ejemplo, podrías querer lanzar una actividad desde una notificación, o realizar una acción cuando el usuario hace clic en un widget.
Cuando se crea un PendingIntent, se especifica el Intent que se quiere ejecutar en el futuro. Este Intent puede ser para iniciar una actividad, un servicio, o enviar una transmisión. Una vez que el PendingIntent es creado, puedes pasárselo a otra aplicación o al sistema Android.
Características únicas:
- Inmutabilidad: Un PendingIntent tiene una naturaleza inmutable una vez creado, lo que significa que no puedes modificarlo después de su creación. Si necesitas modificarlo, tienes que crear uno nuevo.
- Identificación: Los PendingIntent son identificados por el sistema basándose en su intención y en los datos y componentes que contienen. Dos PendingIntent con la misma intención y datos serán considerados iguales por el sistema.
Usos comunes:
- Notificaciones: Para realizar acciones cuando el usuario toca una notificación.
- Alarmas: Con AlarmManager, para ejecutar un Intent en un momento específico.
- Widgets: Para manejar eventos de clic en los widgets de la pantalla de inicio.
- Geofencing: Para ejecutar acciones cuando el usuario entra o sale de una área geográfica específica.
Ejemplo: creaos un PendingIntent para usarlo en una notificación
// Suponiendo que este código está dentro de una Activity o un Context
val notificationManager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
// ID único para la notificación
val notificationId = 1
// Crear un Intent para abrir TargetActivity
val intent = Intent(this, TargetActivity::class.java)
// Crear un PendingIntent usando getActivities
val pendingIntent = PendingIntent.getActivity(
this,
0, // request code
intent,
PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE // flags
)
// Construir la notificación
val notification = NotificationCompat.Builder(this, "tu_canal_id")
.setSmallIcon(R.drawable.ic_notification) // reemplazar con tu propio icono
.setContentTitle("Título de la Notificación")
.setContentText("Descripción de la Notificación")
.setContentIntent(pendingIntent)
.setAutoCancel(true) // Cierra la notificación después de tocarla
.build()
// Mostrar la notificación
notificationManager.notify(notificationId, notification)
98.8 Filtrado de visibilidad de paquetes Android¶
Para Android 11 (API 30) y posteriores.
(En AD)
Algunos paquetes será visibles de forma automática:
Tipos de apps visibles automáticamente Los siguientes tipos de apps son siempre visibles para la tuya, incluso si tu app está diseñada para Android 11 (nivel de API 30) o versiones posteriores:
- Tu propia app
- Determinados paquetes del sistema que implementan la funcionalidad principal de Android, como el proveedor de contenido multimedia
- La app que instaló la tuya
- Cualquier app que inicie una actividad en la tuya mediante el método startActivityForResult(), como se describe en la guía sobre cómo obtener un resultado de una actividad
- Cualquier app que se inicie o se vincule a un servicio en la tuya
- Cualquier app que acceda a un proveedor de contenido en la tuya
- Cualquier app que tenga un proveedor de contenido al que tu app pueda acceder mediante los permisos de URI
- Cualquier app que reciba entradas de la tuya (este caso se aplica solo cuando tu app proporciona entradas como un editor de método de entrada)
98.8.1 Declarar necesidades de visibilidad de paquetes¶
Para Android 11 y posteriores las aplicaciones que no son visibles automáticamente pueden interartuar con nuestra aplicación añadiendo el elemento <queries>
en el manifiesto.
Dentro del elemento
Nombre de paquete específico
<manifest package="com.example.game">
<queries>
<package android:name="com.example.store" />
<package android:name="com.example.services" />
</queries>
...
</manifest>
<manifest package="com.example.game">
<queries>
<intent>
<action android:name="android.intent.action.SEND" />
<data android:mimeType="image/jpeg" />
</intent>
</queries>
...
</manifest>
El elemento
- Debes incluir exactamente un elemento `
``. - No puedes usar los atributos path, pathPrefix, pathPattern o port en un elemento
<data>
. El sistema se comporta como si configuraras el valor de cada atributo para el carácter comodín genérico (*). - No puedes usar el atributo mimeGroup de un elemento
<data>
. -
Dentro de los elementos
<data>
de un solo elemento<intent>
, puedes usar cada uno de los siguientes atributos una vez como máximo: -
mimeType
- scheme
- host
-
Puedes distribuir esos atributos en varios elementos
<data>
o usarlos en un elemento<data>
único. -
El elemento
<intent>
admite el carácter comodín genérico (*) como valor para algunos atributos: -
El atributo name del elemento
- El subtipo del atributo mimeType de un elemento (image/*)
- El tipo y el subtipo del atributo mimeType de un elemento (/)
- El atributo scheme de un elemento
- El atributo host de un elemento
A menos que se especifique lo contrario en la lista anterior, el sistema no admite una combinación de caracteres de texto y comodín, como prefix*
.
98.9 Ciclo de vida de procesos y aplicaciones¶
En AD
Cada aplicación para Android se ejecuta en su propio proceso de Linux. Se crea este proceso para la aplicación cuando es necesario ejecutar parte de su código, y seguirá ejecutándose hasta que ya no sea necesario y el sistema necesite recuperar su memoria a fin de que la usen otras aplicaciones.
En Android la duración del proceso de la aplicación no se controla desde la aplicación si no desde el Sistema Operativo.
A fin de determinar qué procesos deben eliminarse cuando hay poca memoria, Android coloca cada proceso en una "jerarquía de importancia" que se basa en los componentes que se ejecutan en ellos y el estado de esos componentes. Los tipos de procesos son los siguientes (en orden de importancia):
- Un proceso en primer plano es uno que se requiere para lo que el usuario está haciendo actualmente. Varios componentes de la aplicación pueden hacer que el proceso que los contiene se considere en primer plano de diferentes maneras. Un proceso se considera en primer plano si se cumple alguna de las sig uientes condiciones:
- Ejecuta una Activity en la parte superior de la pantalla con la que el usuario está interactuando (se llamó a su método onResume()).
- Tiene un BroadcastReceiver que actualmente está en ejecución (se está ejecutando su método BroadcastReceiver.onReceive()).
- Tiene un Service que actualmente está ejecutando código en una de sus devoluciones de llamadas (Service.onCreate(), Service.onStart() o Service.onDestroy()).
Solo habrá unos pocos procesos de este tipo en el sistema, y solo se eliminarán como último recurso si la memoria es tan baja que ni siquiera estos pueden continuar ejecutándose.
- Un proceso visible que realiza una tarea sobre la que el usuario tiene conocimiento, por lo que su eliminación tendría un impacto negativo notable en la experiencia del usuario. Un proceso se considera visible si cumple con las siguientes condiciones:
- Ejecuta una Activity que es visible para el usuario en pantalla, pero no en primer plano (se llamó a su método onPause()), lo cual puede ocurrir, por ejemplo, si la actividad en primer plano se muestra como un diálogo que permite ver la actividad anterior detrás de ella.
- Tiene un Service que se ejecuta como servicio en primer plano por medio de Service.
startForeground()
(que le pide al sistema que trate el servicio como algo que el usuario conoce o que es esencialmente visible para este). -
Aloja un servicio que el sistema usa para una función que el usuario conoce, como un fondo de pantalla animado, un servicio de método de entrada, etcétera. La cantidad de procesos que se ejecutan en el sistema es menos limitada que los procesos en primer plano, pero aún está relativamente controlada. Estos procesos se consideran sumamente importantes y no se eliminarán a menos que sea necesario para mantener en ejecución todos los procesos en primer plano.
-
Un proceso de servicio es aquel que contiene un Service que se inició con el método
startService()
. Si bien estos procesos no son directamente visibles para el usuario, generalmente están realizando tareas que le interesan (como la carga o descarga de datos de la red en segundo plano), por lo que el sistema siempre los mantendrá en ejecución a menos que no haya suficiente memoria para retener todos los que estén visibles y en primer plano.
Es posible que se descienda el nivel de importancia de los servicios que han estado ejecutándose por un tiempo prolongado (como 30 minutos o más) a fin de permitir que sus procesos se incluyan en la lista de LRU almacenada en caché que se describe a continuación. De esta manera, se evitan situaciones en las que los servicios de duración prolongada con pérdidas de memoria o algún otro problema consuman tanta memoria RAM que impidan que el sistema use los procesos almacenados en caché de manera eficaz.
- Un proceso **almacenado en caché **es uno que no se necesita actualmente, por lo que el sistema puede eliminarlo cuando lo desee si se necesita memoria en otra parte. En un sistema con comportamiento normal, estos son los únicos procesos involucrados en la administración de memoria: un sistema que funcione bien tendrá varios procesos almacenados en caché siempre disponibles (para que la alternancia entre aplicaciones sea más eficiente) y eliminará regularmente los más antiguos según sea necesario. Solo en situaciones muy críticas (y también indeseables) el sistema llegará a un punto en el que todos los procesos almacenados en caché se eliminarán y deberá comenzar a eliminar los procesos del servicio.
Estos procesos suelen contener una o varias instancias de una Activity que el usuario no puede ver en este momento (se llamó y se mostró el método
onStop()
). Siempre que implementen el ciclo de vida de su actividad correctamente (consulta Activity para obtener más detalles), cuando el sistema elimine dichos procesos, la experiencia del usuario no se verá afectada al volver a esa app: puede restaurar el estado guardado previamente cuando la actividad asociada vuelve a crearse en un nuevo proceso.
Estos procesos se mantienen en una lista de pseudo-LRU, donde el último proceso de la lista es el primero que se elimina a fin de recuperar memoria. La política exacta de orden en esta lista es un detalle de implementación de la plataforma, pero generalmente tratará de mantener los procesos más útiles (uno que aloje la aplicación de inicio del usuario, la última actividad que vio, etc.) encima de otros tipos de procesos. Es posible que también se apliquen otras políticas para eliminar procesos: límites más restrictivos en la cantidad de procesos permitidos, límites en la cantidad de tiempo que un proceso puede permanecer almacenado en caché de manera continua, etcétera.
98.10 Uso alternativo a startActivityForResult con Compose¶
Con Jetpack Compose el proceso es un poco diferente. Jetpack Compose no utiliza
startActivityForResult
de la misma manera que lo haría una Activity.
En su lugar, deberías usar el API de Activity Result.
Esto implica el uso de rememberLauncherForActivityResult
junto con ActivityResultContracts
.
- Se crea en la Activity un
ActivityResultLauncher<Intent>
que incluye una función lambda para procesar la respuesta - Se crea la Intent implicita
- Se llama a
tomarFotoLauncher.launch(tomarFotoIntent)
para iniciar la actividad.
Así se vería en Jetpack Compose:
import android.provider.MediaStore
import androidx.activity.compose.rememberLauncherForActivityResult
import androidx.activity.result.contract.ActivityResultContracts
import androidx.compose.material.Button
import androidx.compose.material.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.platform.LocalContext
// En el metodo onCreate:
val tomarFotoLauncher = rememberLauncherForActivityResult(
contract = ActivityResultContracts.StartActivityForResult()
) { resultado ->
// Maneja el resultado de la captura de imagen aquí
}
//...
CameraComposable(tomarFotoLauncher)
// ....
// En la función
@Composable
fun CameraComposable(tomarFotoLauncher: : ActivityResultLauncher<Intent> ) {
val contexto = LocalContext.current
Button(onClick = {
// creamos la intención
val tomarFotoIntent = Intent(MediaStore.ACTION_IMAGE_CAPTURE)
// comprobamos que hay una activity para esta acción
if (tomarFotoIntent.resolveActivity(contexto.packageManager) != null) {
tomarFotoLauncher.launch(tomarFotoIntent)
}
}) {
Text("Tomar Foto")
}
}
98.11 Ejemplos y ejercicios¶
En github UT3
98.12 Apéndice¶
Versión 0.5 (26-12-23)
Versión 1.1, 8-1-24