Repositorio clase 2:
https://github.com/csolorzanof/DispMovilesClase2
Ciclo de vida de actividades
Cuando una actividad es desplegada en nuestra aplicación ocurren una serie de pasos que la llevan
desde la inicialización hasta los estados de preparada para presentar, parcialmente presentada y
completamente presentada. También existen pasos que corresponden a cuando su aplicación se
oculta, se envía al fondo y finalmente destruida. A esto se le conoce como el ciclo de vida de una
actividad, para cada uno de los pasos existen funciones que categorizaremos como callback que
podemos utilizar para realizar acciones como crear, cambiar y mostrar datos después que nuestra
aplicación ha sido enviada al fondo y luego se a restaurado como la aplicación en uso.
*Un callback es un patrón de diseño en programación, donde existen funciones definidas por el
usuario y que el programa invocara de forma automática cuando se cumpla una serie de
condiciones. Son utilizadas principalmente en procesos asíncronos donde la invocación de la función
puede ocurrir en cualquier momento y sirven como mecanismos para recibir notificación o datos
cuando otro proceso ha finalizado.
Podemos considerar estos callbacks como hooks hacia como el sistema interactúa con su actividad y
la pantalla.
Todas las actividades tienes una clase padre la cual extienden, estos callbacks son definidos en la
clase padre y depende de cada clase heredada si implementa o no los callbacks. Cada una de estas
actividades utiliza la palabra clave override, esta palabra clave en Kotlin significa que la clase esta
proveyendo una implementación de una interfaz o un método abstracto o en el caso de las
actividades un método que se esta sobre escribiendo sobre la clase padre.
Los callbacks principales del ciclo de vida de una actividad son los siguientes:
• override fun onCreate(savedInstanceState: Bundle?): Este es el callback que utilizaremos
más en aquellas actividades que dibujan pantallas completas. Aquí es donde se prepara el
layout de la actividad a ser utilizado. En este punto cuando el método finaliza, la actividad
todavía no es mostrada al usuario aun y cuando en código aparentará hacerlo. Normalmente
establecemos la interfaz de usuario de nuestra actividad llamando a setContentView al cual
le suministramos el layout a utilizar para luego realizar cualquier inicialización que sea
requerida. Este método se llama una vez en el ciclo de vida de la actividad a menos que la
actividad sea recreada, esto puede suceder de forma automática en respuesta a algunas
acciones del usuario como cuando se cambia la orientación del celular de vertical a
horizontal. El parámetro savedInstanceState del tipo Bundle es un mapa de pares de llaves
optimizado para almacenar y restaurar datos, este parámetro es nulo la primera vez que la
actividad es iniciada o si se recreó sin haber almacenado valores en su estado. Puede
contener información si datos son salvados en el método de callback
onSaveInstanceState(outState: Bundle?) previo a que la actividad sea recreada.
• override fun onRestart(): Cuando una actividad es reiniciada, este callback se ejecuta
inmediatamente antes que el callback onStart(). Es muy importante que tengamos claro la
diferencia entre reiniciar una actividad y recrearla. Cuando una actividad se envía a segundo
plano, por ejemplo cuando le presionamos el botón de inicio en nuestro celular, y luego
volvemos a nuestra aplicación es en este momento que se llama al callback onRestart(). Una
actividad es recreada cuando sucede algo que modifica su configuración como rotar la
orientación de la pantalla.
• override fun onStart(): Este callback se ejecuta cuando la actividad se visualiza por primera
vez. También se ejecuta cuando la aplicación se restaura de estar en segundo plano. Es el
primer método del ciclo de vida que se ejecuta cuando la aplicación esta visible.
• override fun onRestoreInstanceState(savedInstanceState: Bundle?): Si hemos almacenado
un estado de la actividad mediante el callback onSaveInstanceState(outState: Bundle?) este
es el método que se ejecuta de forma automática después del onStart() y es aquí donde
podemos hacer uso del estado almacenado en lugar de utilizarlo en el método onCreate.
• override fun onResume(): Este callback se ejecuta como la etapa final al crear la actividad
por primera vez y cuando la aplicación se restaura desde segundo plano. Cuando este
método finaliza la pantalla/actividad esta lista para ser utilizada y recibir interacción del
usuario.
• override fun onSaveInstanceState(outState: Bundle?): Si queremos almacenar información
sobre el estado de la actividad lo realizamos en este método. Agregamos pares de llave* al
outState utilizando uno de los múltiples métodos que tenemos a nuestra disposición
dependiendo el tipo de dato a almacenar. La información almacenada en el outState la
podemos recuperar en los callback onCreate y onRestoreInstanceState.
• override fun onPause(): Este callback se ejecuta cuando una actividad esta a punto de ser
enviada a segundo plano o cuando un dialogo o otra actividad pasa a primer plano.
• override fun onStop(): Este callback se ejecuta cuando la actividad se oculta ya sea porque la
actividad paso a segundo plano o porque otra actividad se despliega encima de esta.
• override fun onDestroy(): Este callback es ejecutado de forma automática por el sistema
cuando los recursos se encuentran bajos, cuando llamamos explícitamente al método
finish() de la actividad o más comúnmente cuando la actividad se finaliza ya que el usuario
cerro la aplicación.
*El estado de una actividad es compuesto por una o más variables que juntas sirven para definir la
funcionalidad de la actividad, no es obligatorio que todas las actividades mantengan un estado si no
aportan a la funcionalidad de esta. Existen actividades que son meramente de visualización y no
necesitan restaurar información de variables cada vez que la actividad sufre un cambio de
configuración.
*Un par de llave es una estructura de datos que contiene dos propiedades llamadas key y value. La
propiedad key almacena una cadena de texto la cual debe ser única en el mapa de llaves, la
propiedad value es un objeto universal el cual puede recibir cualquier valor. Podemos almacenar
valores de tipos primitivos como ser int, byte, double, string, etc… o podemos almacenar objetos
complejos también por lo que necesitaríamos utilizar operaciones de casteo.
Logs
La forma para generar logs de actividades en una aplicación de Android es mediante una clase
estática utilitaria de Android de nombre Log, mediante esta clase podemos hacer entradas en el log
de la aplicación móvil el cual podemos observar mediante LogCat en el AndroidStudio. Para utilizar
correctamente el Log es necesario utilizar un valor que nos sirva para identificar nuestras entradas
en el LogCat, podemos utilizar una cadena de texto como identificación. Para poder asegurar
consistencia y reducir el error humano al momento de hacer los Logs podemos definir una variable
constante. Las variables constantes pueden ser definidas a nivel global fuera de las clases lo que las
hace publicas o de forma privada en las clases utilizando un objeto acompañante.
Puede leer más sobre los objetos acompañantes en este link: https://www.develou.com/objetos-
companeros-en-kotlin/
Cambios de configuración
Existen acciones que son considerados como un cambio de configuración en Android como rotar la
orientación de la pantalla. Podemos obligar a que estas acciones no sean tomadas como un cambio
de configuración y por consecuencia no se tenga que recrear la actividad. Para esto hacemos
modificaciones en el AndroidManifest.xml, sin embargo siempre se nos notificaran estas acciones y
podemos manejarlas en un nuevo callback:
override fun onConfigurationChanged(newConfig: Configuration)
Guardando y recuperando el estado de la actividad
Para los EditText Android preservara el contenido de los mismos cuando una actividad es recreada
siempre y cuando estos tengan un id especificado.
Intents
Un intent en Android es un mecanismo de comunicación entre componentes dentro de la misma
aplicación, muchas veces querremos iniciar una nueva actividad en respuesta a una acción en la
actividad que estamos utilizando actualmente. Especificar qué actividad va a ser llamada son intents
explícitos (explicit intent). En otras ocasiones querremos acceder a un componente del sistema
como ser la cámara. No podemos utilizar la cámara del sistema de forma directa por lo que debemos
enviar un intent al sistema operativo para que esta abra la cámara del celular, a estos intents se les
llama intents implícitos (implicit intent). Se debe configurar un filtro de intents para poder
responder a estos eventos en el AndroidManifest.xml.
Para nuestra actividad principal Android Studio crea dos filtros por defecto:
“androdi.intent.action.Main” indica que esta actividad es el punto de entrada principal para la
aplicación, “Android.intent.category.LAUNCHER” define que la aplicación debe aparecer en el
launcher del celular. Cuando combinamos los dos intents para una actividad le estamos definiendo al
sistema operativo con que actividad debe iniciar la aplicación al ejecutarse. Si removemos alguno de
los dos resulta en un error al correr la aplicación.
also es una función que podemos utilizar para poder ejecutar acciones sobre el objeto que se acaba
de crear sin tener que recurrir a la asignación de este a una variable mediante una expresión
lambda. Puede leer mas acerca de expresiones lambda en Kotlin aquí:
https://www.develou.com/lambdas-en-kotlin/
intent?.let: intent por si solo es una referencia al intent que lanzo la actividad actual el uso del ?.let
nos permite ejecutar bloques de código siempre y cuando el intent no sea nulo. Dentro del bloque
de código podemos hacer referencia al intent utilizando la palabra clave it.
Los extras de un intent son pares de llaves y valores que podemos podemos almacenar y recuperar
utilizando el putExtra y el get[Tipo]Extra para este segundo la función cambia de nombre según el
tipo de datos a recuperar.
Muchas veces iniciamos una actividad con el objetivo de recibir una respuesta como ser un dialogo
de permisos por ejemplo, esto es un patrón de diseño muy común. Para poder lazar una actividad
con este objetivo utilizamos el registerForActivityResult con un contrato de
ActivityResultContracts.StartActivityForResult(), en el contexto del register tenemos un resultCode
podemos ver el estado de la operación, podemos definir nuestros propios valores pero por defecto
se utilizan Activity.RESULT_OK o Activity.RESULT_CANCELED y existe una propiedad data contiene
el intent que se utilizo para iniciar la actividad, y obtenemos el resultado desde los extras del intent.
Launch Modes
Existen diferentes formas de desplegar una actividad la forma Standard apila las actividades una
sobre otra de forma que al apretar el botón de regreso en el celular lo que se hace es regresar a la
actividad anterior en la pila de actividades. Este es el comportamiento por defecto y no requiere
mayor modificación al AndroidManifest.xml.
Puede que se tenga el caso donde no queremos que esto sea lo que pase por ejemplo si tenemos
una actividad que hace de menú principal y donde hay noticias que el usuario puede seleccionar
para ver sus detalles y si selecciona otra noticia al finalizarla y presionar el botón de regreso en el
celular el esperaría regresar el menú principal y no a la noticia anterior. El launch mode que nos
serviría para esto es el singleTop, al utilizar este launch mode solo existe una instancia de la
actividad y se reutiliza entre cada llamado lo que permite que siempre esta este en el tope de la pila
de actividades. Cada vez que se lanza la actividad si esta ya existía en el stack se reutiliza y se ejecuta
el callback onNewIntent aquí podemos realizar el mismo proceso de inicialización que haríamos en
el onCreate.
Existen otros modos de lanzamiento y puedes leer más al respecto en este enlace:
https://programmerclick.com/article/3112446010/
Misceláneos
En los EditText podemos restringir y validar el contenido hasta cierto punto haciendo uso de la
propiedad inputType en la cual podemos especificar diferentes valores como ser number o
textEmailAddress este último no va enforzar el uso de la “@” pero si mostrara un énfasis en ella en
el teclado.
get(): El get() es un mecanismo de acceso personalizable para propiedades
%s: Es un comodín que podemos especificar en recursos de cadenas de texto para que sea
reemplazado por un valor al momento que recuperamos la cadena de texto con el getString