Programacion multimedia dispositivos.pdf

Full Transcript

www.mheducation.esProhibida la reproducción total o parcial sin el permiso adecuado. Uso exclusivo para el contenido de los cursos FPActiva® de McGraw-Hill. CFGS INFORMÁTICA Programación multimedia...

www.mheducation.esProhibida la reproducción total o parcial sin el permiso adecuado. Uso exclusivo para el contenido de los cursos FPActiva® de McGraw-Hill. CFGS INFORMÁTICA Programación multimedia y dispositivos móviles José Alfredo Múrcia Andrés Prohibida la reproducción total o parcial sin el permiso adecuado. Uso exclusivo para el contenido de los cursos FPActiva® de McGraw-Hill. Programación multimedia y dispositivos móviles No está permitida la reproducción total o parcial de este libro, ni su tratamiento informático, ni la transmisión de ninguna forma o por cualquier medio, ya sea electrónico, mecánico, por fotocopia, por registro u otros métodos, sin el permiso previo y por escrito de los titulares del copyright. Diríjase a CEDRO (Centro Español de Derechos Reprográficos, www.cedro.org) si necesita fotocopiar o escanear algún fragmento de esta obra. Nota: Este libro se atiene al artículo 32 del derecho de cita de la Ley de Propiedad Intelectual de 1996 (R. D. Leg. 1/1996 de 12 de abril). Derechos reservados © 2022, respecto a la primera edición en español, por: McGraw Hill/Interamericana de España, S. L. Basauri, 17 Edificio A, 1ª planta 28023 Aravaca (Madrid) ISBN digital: 9788448626754 © José A. Múrcia Andrés Corrección técnica: Vicent Selfa García Equipo editorial: Cristina García Sánchez y Silvia García Olaya Corrección de estilo y ortotipográfica: Ester Jiménez Domínguez Ilustración: Pablo Vázquez Rodríguez, Archivo McGraw-Hill, 123rf Fotografías: Archivo McGraw-Hill, 123rf Prohibida la reproducción total o parcial sin el permiso adecuado. Uso exclusivo para el contenido de los cursos FPActiva® de McGraw-Hill. Unidad 1. Tecnologías para aplicaciones en dispositivos móviles Prohibida la reproducción total o parcial sin el permiso adecuado. Uso exclusivo para el contenido de los cursos FPActiva® de McGraw-Hill. 1 UNIDAD 1. Dispositivos móviles. Hardware y tecnologías de desarrollo 1.1. Dispositivos móviles Cuando pensamos en dispositivos móviles, generalmente pensamos en un smartphone. Sin embargo, hoy en día existe una gran diversidad de dispositivos móviles con características muy dispares entre ellos: netbooks, tabletas, relojes inteligentes, y evidentemente, smartphones. En líneas generales, podemos definir un dispositivo móvil como aquel que posee las características siguientes: Movilidad: un dispositivo móvil puede ser transportado fácilmente y ser utilizado durante su trans- porte. Tamaño reducido: un dispositivo móvil debe ser lo suficientemente pequeño como para facilitar su movilidad y, además, posibilitar la interacción de forma simple, mediante una o las dos manos, sin ne- cesidad de ningún dispositivo externo. Conexión inalámbrica a una red para poder enviar y recibir datos sin cables, ya sea a través de redes de telefonía móvil o wifi. Suelen ser dispositivos unipersonales, es decir, asociados a un único usuario. Además, no debemos olvidar que se trata de dispositivos con capacidad de procesamiento y memoria. En los apartados siguientes vamos a analizar el hardware y el software propios de estos dispositivos. 1.2. Hardware de un dispositivo móvil A. EL PROCESADOR Y EL SOC Un dispositivo móvil contiene básicamente el mismo hardware que un ordenador, aunque tiene una arquitec- tura diferente, ya que están condicionados a un menor tamaño del dispositivo. Así pues, cuando hablamos del procesador en un dispositivo móvil, debemos hablar del SoC o System on a Chip, un circuito integrado con diferentes partes del sistema, como la propia CPU, la GPU (procesador gráfico), la RAM, la ROM, o los contro- ladores USB o wifi. Cabe destacar la importancia en el mundo de los procesadores móviles de la empresa británica ARM Hol- dings, la creadora de la arquitectura con su propio nombre, ARM (Advanced Risc Machines), una arquitectura RISC (Reduced Instruction Set Computer, o Conjunto Reducido de Instrucciones) de 32 y 64 bits que está presente en la mayoría de dispositivos móviles. En la actualidad, cabe destacar la familia de SoC Snapdragon, de Qualcomm, basada en el conjunto de ins- trucciones ARM y presente en dispositivos de Motorola (Moto G100), Xiaomi (Redmi Note 10 Pro), Samsung (Galaxy S20 FE) o Vivo (V20). B. LA MEMORIA RAM El tipo de memoria RAM que se encuentra dentro del SoC es de tipo dinámica (DRAM), requiere refrescarse periódicamente y es muy rápida. Con la finalidad de reducir el consumo de energía y conseguir un menor calentamiento, esta se ubica cerca de la CPU y la GPU. Esta RAM es compartida por ambas unidades. C. PANTALLAS EN DISPOSITIVOS MÓVILES Una de las características determinantes de los smartphones es la pantalla, a través de la cual se realiza la mayor parte de la interacción con el dispositivo. Existen principalmente dos tipos de tecnologías, con diferentes variaciones y generaciones: LCD o inorgánicas. De cristal líquido, dejan pasar luz en función de su polaridad, igual que los monito- res. Para ello, cuentan con un panel de iluminación situado tras el panel, ya sea de lámparas fluorescen- tes o LED. Dentro de este tipo encontramos pantallas TFT, de tipo LED, IPS, PLS, o las Retina de Apple. OLED u orgánicas. Cuentan con materiales orgánicos que emiten luz por sí mismos cuando se les aplica electricidad, de modo que no necesitan un panel de iluminación y pueden apagar o encender los Propiedad de McGraw-Hill®. Prohibida la reproducción total o parcial sin el permiso adecuado. Uso exclusivo para el contenido de los cursos FPActiva® de McGraw-Hill. Prohibida la reproducción total o parcial sin el permiso adecuado. Uso exclusivo para el contenido de los cursos FPActiva® de McGraw-Hill. 1 UNIDAD píxeles de manera independiente. Se trata de pantallas más delgadas que las LCD, al tener menos ca- pas, con un menor consumo, y que muestran mayor contraste y son más brillantes que estas. Además, esta tecnología de fabricación permite que los paneles sean flexibles, dando lugar a teléfonos móviles con pantallas plegables o enrollables. Dentro de esta familia encontramos las pantallas AMOLED, las Super AMOLED y las Dynamic AMOLED. Aparte de la tecnología de fabricación de pantallas, es importante conocer algunas características más de estas: Resolución y densidad. La resolución de la pantalla hace referencia al número de píxeles que se muestran en esta, y viene determinada por la cantidad de píxeles en horizontal y en vertical. A partir de la resolución podemos conocer la relación de aspecto y la densidad de píxeles por pulgada (ppi). La densidad es una medida que relaciona el tamaño de la pantalla con la resolución. Dos pantallas de distintos tamaños con la misma resolución tendrán densidades diferentes, y, por tanto, diferente calidad de imagen. Lo ideal es que esta densidad sea mayor de 300 o 400 ppi. Relación de aspecto. Se trata de la relación entre el ancho y el alto de la pantalla. Tradicionalmente, esta relación ha seguido el formato panorámico 16:9, o lo que es lo mismo, tamaños proporcionales a 16 píxeles de ancho por 9 de alto. Por ejemplo, el formato 1920x1080 cumple esta proporción. Sin embargo, hace unos años empezó a popularizarse la relación 18:9 (e incluso la 19:9), orientada a paneles de mayor tamaño y apenas sin marcos. Esta relación permite que un dispositivo sea menos ancho que otro con la misma diagonal en formato 16:9, con lo que su ergonomía mejora. D. CÁMARAS Uno de los componentes a los que más se le suele exigir en un dispositivo móvil es la cámara o cámaras foto- gráficas. Estas se componen, principalmente, de: Un bloque óptico, relativamente limitado, aunque algunos dispositivos permiten la conexión de un objetivo. Un sensor, compuesto por una matriz de fotorreceptores que traducen las señales luminosas en eléc- tricas, obteniendo así el valor para cada punto de la imagen. Con el tiempo, además, los dispositivos móviles han ido incorporando más cámaras, aparte de la frontal y la trasera, de modo que actualmente podemos encontrar tres, cuatro o hasta cinco cámaras (teleobjetivo, de gran angular, monocromáticas o incluso infrarrojas). E. SENSORES Los dispositivos móviles pueden incorporar una gran variedad de sensores con los que podemos obtener información muy variada de nuestro entorno. Entre los sensores que podemos encontrar en un dispositivo móvil destacan: GPS (sistema de posicionamiento global). Proporciona servicios de ubicación, utilizando una señal continua, a los satélites GPS, con lo que permite mostrar en qué lugar del planeta nos encontramos. Este dispositivo da pie a todo un abanico de posibilidades como son los servicios LBS o servicios basados en la localización. Acelerómetro y giroscopio. El giroscopio mide los movimientos del dispositivo, gracias a la aceleración angular, e incluso permite detectar pequeños giros, lo que lo hace muy apropiado para aplicaciones de realidad aumentada. Por su parte, el acelerómetro es menos preciso y permite detectar la posición del dispositivo respecto a los tres ejes, X, Y y Z. Con ello, podemos conocer, por ejemplo, si el dispositivo se encuentra en horizontal o vertical, así como detectar giros, vibraciones, la inclinación o colisiones. Sensor de luz. Permite detectar la luz ambiental, de modo que el dispositivo es capaz de ajustar el brillo de la pantalla para adaptarse a las diferentes circunstancias lumínicas. Sensor de proximidad. Permite detectar la distancia del dispositivo respecto de otros objetos a través de un LED infrarrojo, y permite, por ejemplo, apagar la pantalla cuando nos lo acercamos al oído en una llamada. Además de estos, podemos encontrar muchos otros, como sensores biométricos (lectores de huella o iris), magnetómetros, barómetros, sensores capacitivos, sensores de infrarrojos, sensores del ritmo cardíaco o de espectro de color, o podómetros. Propiedad de McGraw-Hill®. Prohibida la reproducción total o parcial sin el permiso adecuado. Uso exclusivo para el contenido de los cursos FPActiva® de McGraw-Hill. Prohibida la reproducción total o parcial sin el permiso adecuado. Uso exclusivo para el contenido de los cursos FPActiva® de McGraw-Hill. 1 UNIDAD 1.3. Sistemas operativos para dispositivos móviles El sistema operativo es una pieza fundamental en cualquier sistema informático. Desde la aparición de los primeros dispositivos móviles hasta la actualidad han existido una serie de sistemas operativos, con mayor o menor relevancia, dedicados a estos dispositivos: PalmOS, Symbian, Windows Mobile y Windows Phone, Maemo, Firefox OS, MeeGo, Bada OS, Ubuntu Touch, Tizen o Blackberry OS. Pero sobre todos ellos, han sido Android e iOS los sistemas que se han erigido predominantes en el panorama actual. A. ANDROID Android es un sistema operativo, desarrollado por Google y basado en el núcleo de Linux, fabricado específi- camente para dispositivos móviles con pantalla táctil: smartphones, tabletas, relojes inteligentes, televisores o incluso algunos coches. La base del sistema se organiza en diversas librerías en C y el Android Runtime (ART), la máquina virtual de Java sobre la que se ejecutan las aplicaciones. Aunque en su origen el lenguaje de pro- gramación para el desarrollo en Android ha sido Java, Google adoptó Kotlin como lenguaje de programación oficial en Android, que es más potente, expresivo y capaz de generar bytecode ejecutable directamente en ART. B. IOS iOS es el sistema operativo más vendido por detrás de Android, y es propiedad de la multinacional Apple. Fue creado para el iPhone y, posteriormente, adoptado en el iPod touch y el iPad. La base de iOS es MacOS, deriva- do de Darwin BSD, un sistema operativo de tipo Unix. Aun así, se trata de un sistema cerrado que no permite su instalación en hardware de otros fabricantes. Los lenguajes con los que podremos desarrollar aplicaciones de forma nativa para iOS son Objective-C y Swift. 1.4. Tecnologías para el desarrollo de aplicaciones móviles El desarrollo de una aplicación que funcione de forma nativa en un determinado sistema operativo pasa por el desarrollo mediante sus propias tecnologías. Sin embargo, existen varias tecnologías que con sus ventajas e inconvenientes pretenden abarcar el desarrollo multiplataforma en su sentido más amplio, desde aplicaciones web de tipo responsivo hasta aplicaciones compiladas, pasando por las aplicaciones web híbridas o progresi- vas (PWA). Las aplicaciones nativas son las que se desarrollan específicamente para el sistema en que se van a ejecutar y aprovechan mejor todos sus recursos. Además, permiten acceder a todas las funcionalidades de las plataformas y disponen de cualquier novedad en el sistema de forma inmediata. Para el desarrollo nativo en Android utilizaremos Java o Kotlin, mientras que para iOS utilizaremos Obje- tive-C y Swift, generando así código nativo de cada plataforma. Todo ello da como resultado aplicaciones fluidas y con la mejor experiencia de usuario. Como desventa- ja, suponen un incremento del coste de producción y de mantenimiento cuando deseamos que estén disponibles en múltiples plataformas, ya que debemos llevar un desarrollo paralelo. Con tal de minimizar el desarrollo específico para una plataforma, disponemos de varias tecnologías alterna- tivas basadas principalmente en tecnologías web. Vamos a ver cada una de ellas, según su lejanía o acerca- miento al código nativo. A. WEBAPPS O APLICACIONES WEB RESPONSIVAS Se trata de aplicaciones basadas en tecnología web: HTML + CSS + JavaScript, y que para ejecutarse necesi- tan únicamente un navegador web. El hecho de ser responsivas implica que su interfaz se adapte a cualquier dispositivo. Para este tipo de aplicaciones no es necesario desarrollar nada en código nativo, y son totalmente multiplataforma, puesto que para ejecutarse lo hacen sobre el propio navegador web del sistema operativo. Disponemos, pues, de un único código para ejecutarse en todas las plataformas, con la principal desventaja de que no ofrecen una experiencia de usuario tan buena como las apps nativas ni permiten el acceso a todos los componentes del sistema. Propiedad de McGraw-Hill®. Prohibida la reproducción total o parcial sin el permiso adecuado. Uso exclusivo para el contenido de los cursos FPActiva® de McGraw-Hill. Prohibida la reproducción total o parcial sin el permiso adecuado. Uso exclusivo para el contenido de los cursos FPActiva® de McGraw-Hill. 1 UNIDAD B. APLICACIONES HÍBRIDAS Utilizan la terna HTML + CSS + JavaScript para construir un sitio web que se carga dentro de un componente de tipo WebView, que no es más que un navegador sin la barra de navegación ni otras opciones, por lo que presentan la apariencia de una aplicación nativa. Este tipo de aplicaciones ya pueden acceder, a través de este componente, a algunas características del dispositivo, como la ubicación o el acelerómetro. Actualmente, el framework para el desarrollo de aplicaciones híbridas más popular es Ionic, que permite el desarrollo en otros frameworks web como React, Angular o Vue. Otro framework muy popular en su momento fue Adobe Phone- gap, pero Adobe abandonó su desarrollo en 2020, en favor de las aplicaciones web progresivas. C. APLICACIONES WEB PROGRESIVAS (PWA) Un poco más cerca de las aplicaciones nativas tenemos las aplicaciones web progresivas, que están revolu- cionando el panorama actual. Estas aplicaciones incrementan y avanzan en las funcionalidades según el dis- positivo móvil en que vayan a ejecutarse, para sacar mayor potencial, y pueden acceder al hardware, trabajar sin conexión o con mala conexión u ofrecer notificaciones del sistema. Existen multitud de frameworks para el desarrollo de PWA, entre los que se encuentran React PWA Library, Angular PWA Framework, Vue PWA Fra- mework, Ionic PWA Framework, Svelte, PWA Builder o Polymer. D. APLICACIONES COMPILADAS Se trata de tecnologías que pretenden utilizar solamente un lenguaje de programación para generar aplica- ciones móviles en el código nativo de cada plataforma. Algunas de las tecnologías más utilizadas en este tipo de aplicaciones son las siguientes: React Native y Native Script. Utilizan como base el lenguaje de programación JavaScript, pero en lugar de construir las interfaces mediante HTML utilizan componentes propios del framework que son compilados a código nativo, haciendo innecesario utilizar un WebView como intermediario. Flutter. Desarrollado y mantenido por Google, permite el desarrollo de aplicaciones multiplataforma mediante el lenguaje Dart, compilando a código nativo que se ejecuta completamente en el dispositivo. La forma de trabajar de Flutter consiste en diseñar interfaces de usuario mediante widgets integrados en el propio código. Flutter ya cuenta con una serie de widgets predeterminados como botones, barras de navegación, etc. Propiedad de McGraw-Hill®. Prohibida la reproducción total o parcial sin el permiso adecuado. Uso exclusivo para el contenido de los cursos FPActiva® de McGraw-Hill. Prohibida la reproducción total o parcial sin el permiso adecuado. Uso exclusivo para el contenido de los cursos FPActiva® de McGraw-Hill. 1 UNIDAD 2. El sistema operativo Android. Herramientas de desarrollo y gestión de dispositivos 2.1. El sistema operativo Android Android es el sistema operativo para dispositivos móviles más utilizado en la actualidad. Como ya sabemos, se trata de un sistema operativo para dispositivos con pantalla táctil y basado en el kernel de Linux, así como en otros estándares de software abierto. Los orígenes de Android se encuentran en la empresa de Palo Alto (California) Android Inc, fundada en 2003 por Andy Rubin. Esta empresa empezó con el desarrollo de un sistema operativo para cámaras fotográficas, pero ante la escasa rentabilidad del sector decidieron dar el salto a los dispositivos móviles, dominado en aquel momento por Symbian y Windows Mobile. En 2005 Google adquirió Android Inc; dos años después, jun- to con la creación de la Open Handset Alliance, un consorcio de varias compañías tecnológicas cuyo objetivo era el desarrollo de estándares abiertos para dispositivos móviles, se anunció la primera versión de Android, Apple Pie. Esta versión empezó a incorporarse en terminales en 2008, y dos años después alcanzó práctica- mente la mitad de la cuota de mercado. A diferencia de otros sistemas, Android se desarrolla de forma abierta, de modo que se puede acceder tanto al código fuente como a la lista de incidencias. El proyecto Android Open Source Project contiene el código fuente de Android, liberado bajo una licencia Apache. En octubre de 2021 se lanzó la última versión de Android, Android 12, y desde la primera versión se han ido in- corporando actualizaciones y funcionalidades al sistema. Además, las facilidades que aporta para el desarrollo de aplicaciones han hecho que actualmente cuente con una gran comunidad de desarrolladores cuyo fruto son más de tres millones de apps en la Google Play Store, el repositorio de aplicaciones oficial de Android. A. CARACTERÍSTICAS Algunas de las características más relevantes de Android son las siguientes: Adaptable a pantallas y resoluciones muy variadas, con soporte a librerías gráficas 2D y 3D basadas en OpenGL. Soporta pantallas multitáctiles de forma nativa. Ofrece almacenamiento local a través de una base de datos ligera, como SQLite. Soporta un gran abanico de tecnologías de conectividad. Incluye un navegador web basado en el motor de renderizado Webkit y el motor JavaScript V8, de Goo- gle Chrome. Las aplicaciones se programan en Java o Kotlin, y son compiladas a la máquina virtual ART (Android Runtime). Incorpora soporte para una gran diversidad de formatos multimedia y streaming. Da soporte para una gran cantidad de dispositivos hardware y sensores. Dispone de un catálogo muy extenso de aplicaciones a través del servicio Google Play. B. VERSIONES DE ANDROID Android ha sufrido una gran transformación desde sus primeras versiones. A modo de resumen, vamos a ver algunas características de las actualizaciones más relevantes. El sistema inició su camino en 2008, con las versiones 1.0 y 1.1, que incluían apps como Gmail, Maps, Calendar y YouTube. Fue en la versión 1.5, Cupcake, cuando se introdujo un nombre de versión y se incluyó una gran cantidad de mejoras en la interfaz, como el teclado en la pantalla, lo que permitió deshacerse de los teclados físicos en el dispositivo. Posteriormente, con la versión 1.6, Donut, el sistema comenzó a adaptarse a diferen- tes tamaños y resoluciones de pantalla. Propiedad de McGraw-Hill®. Prohibida la reproducción total o parcial sin el permiso adecuado. Uso exclusivo para el contenido de los cursos FPActiva® de McGraw-Hill. Prohibida la reproducción total o parcial sin el permiso adecuado. Uso exclusivo para el contenido de los cursos FPActiva® de McGraw-Hill. 1 UNIDAD Las versiones 2.0 y 2.2 (Eclair y Froyo) introdujeron aspectos como la navegación guiada por voz y la infor- mación de tráfico en tiempo real y el dock inferior. La versión 3.0, Honeycomb, se lanzó específicamente para dispositivos de mayor tamaño, como las tabletas, y en la versión 4.0, Ice Cream Sandwich de 2011, la nueva interfaz, Holo, se unificó para tabletas y smartphones, entrando así en la era del diseño moderno. Pero el mayor cambio estaba por venir con las versiones 5.0 y 5.1, Lollipop, en 2014. Google reinventa Android en la que quizá sea la actualización más importante del sistema, introduciendo el estándar Material Design, un conjunto de especificaciones de diseño que afectaban tanto al sistema operativo como a la web o las apps. Con Material se introducen los diseños con colores planos para dar peso y profundidad a diferentes elemen- tos de la interfaz utilizando sombras, capas o animaciones. Las versiones posteriores incluyeron algunas mejoras en la interfaz, como el modo de pantalla dividida en Android 7.0/7.1 (Nougat) y la pantalla flotante en Android 8/8.1 (Oreo). Con Android 10 se abandonaron los nombres clave de versión basados en dulces y se reinventaron algunos aspectos de la interfaz con relación a los gestos y al sistema de navegación. En Android 11, en 2020, llegaron cambios sustanciales en la privacidad, que permiten al usuario dar permisos a las aplicaciones para acceder a la localización, la cámara o el micrófono de forma temporal y cuando se requieran, en lugar de hacerlo permanentemente durante la instalación. Y en 2021 llegó Android 12, que supone la mayor actualización desde Android 5.0, con la introducción de Material You, que supone una personalización del diseño del sistema para ajustarse automáticamente a la configuración del usuario. Esto implica, por ejemplo, que la paleta de colores del tema se adapte al fondo de pantalla elegido por el usuario. Además, internamente ofrece una forma más simple y granular de controlar el modo en que las apps acceden a nuestros datos, a través del nuevo panel de privacidad. C. ARQUITECTURA DE ANDROID La arquitectura de Android está compuesta por una pila de capas que toma su base en el kernel de Linux y que se adapta a una gran variedad de dispositivos. Los diferentes componentes del sistema se muestran en la figura siguiente: Dialer Email Calendar Camera … Managers Content Providers Activity Location Notification System Telephony Window Runtime Webkit OpenMAX AL Libc Android Runtime (ART) Media Framework OpenGL ES … Libraries Hardware Abstraction Layer (HAL) Propiedad de McGraw-Hill®. Prohibida la reproducción total o parcial sin el permiso adecuado. Uso exclusivo para el contenido de los cursos FPActiva® de McGraw-Hill. Prohibida la reproducción total o parcial sin el permiso adecuado. Uso exclusivo para el contenido de los cursos FPActiva® de McGraw-Hill. 1 UNIDAD Audio Bluetooth Camera Sensors … Propiedad de McGraw-Hill®. Prohibida la reproducción total o parcial sin el permiso adecuado. Uso exclusivo para el contenido de los cursos FPActiva® de McGraw-Hill. Prohibida la reproducción total o parcial sin el permiso adecuado. Uso exclusivo para el contenido de los cursos FPActiva® de McGraw-Hill. 1 UNIDAD Linux Drivers Audio Binder (IPC) Display Keypad Bluetooth Camera Shared Memory USB WIFI Management Fuente: Android Open Source Project, imagen utilizada conforme a los términos de la licencia Creative Commons 2.5. Attribution: https://developer.android.com/guide/platform?hl=es-419. [COMPONER EN MAQUETA]. En ella, podemos ver los componentes siguientes: Aplicaciones del sistema. Forman el sistema base y se componen del cliente de correo electrónico, el calendario, la aplicación de SMS, los mapas, la aplicación de cámara, el navegador y la aplicación de contactos o el dialer, entre otras. Framework de aplicaciones (Java API Framework). Ofrece a las aplicaciones acceso a todas las fun- ciones de Android, así como la posibilidad de publicar y ofrecer sus funcionalidades a otras aplicaciones de forma segura. Todo ello, pensando en la simplificación de la reutilización de componentes del siste- ma y servicios modulares. Entre estos servicios podemos encontrar: – Un sistema de vista enriquecido, para compilar la interfaz de usuario, – Un administrador de recursos, para acceder a los recursos de nuestras aplicaciones, tales como las traducciones, las imágenes o los archivos de diseño, – Un administrador de notificaciones, para poder mostrar alertas en la barra de estado, – Un administrador de actividad, para administrar el ciclo de vida de las aplicaciones y gestionar la navegación, – Proveedores de contenidos, para que las aplicaciones puedan acceder a datos facilitados por otras aplicaciones. Bibliotecas de C/C++. Son bibliotecas que utilizan algunos componentes del sistema y que se ofrecen a los desarrolladores a través del framework de aplicaciones. Algunas de estas son las bibliotecas de C estándar, las bibliotecas gráficas 3D, las multimedia o la base de datos SQLite. Runtime de Android. Incluye la propia máquina virtual ART y las bibliotecas base de Java. Las apps ejecutan sus propios procesos como instancias de la propia máquina virtual ART, bajo el paradigma de virtualización de proceso (como la JVM para PC). Los ejecutables para esta máquina virtual se encuen- tran en formato DEX, un bytecode diseñado específicamente para Android y optimizado para ocupar un espacio de memoria mínimo. Capa de abstracción de Hardware. Consta de una serie de módulos de biblioteca para los diferentes componentes hardware del dispositivo, como la cámara o los sensores, y ofrece una interfaz a las capas superiores para facilitar el acceso a estos. Kernel de Linux. Es la base de la plataforma Android, a la que proporciona funcionalidades básicas del sistema como la gestión de procesos, la administración de memoria o de la red, los controladores o la seguridad. Propiedad de McGraw-Hill®. Prohibida la reproducción total o parcial sin el permiso adecuado. Uso exclusivo para el contenido de los cursos FPActiva® de McGraw-Hill. Prohibida la reproducción total o parcial sin el permiso adecuado. Uso exclusivo para el contenido de los cursos FPActiva® de McGraw-Hill. 1 UNIDAD D. APLICACIONES ANDROID Las aplicaciones Android se programan en Kotlin, Java o C++, y son compiladas por el Android SDK, junto con ficheros con datos y recursos (interfaces, imágenes, etcétera) para generar un fichero.apk, que incluya la aplicación en sí y la información que necesita Android para su instalación. Android implementa el principio del mínimo privilegio en las aplicaciones, con el que aporta cierta seguridad a estas. Este principio se fundamenta en: Android es un sistema operativo multiusuario, puesto que se basa en Linux. La peculiaridad es que para Android cada aplicación será un usuario diferente. Cada app tiene un ID de usuario conocido solamente por el sistema, y establece los permisos necesarios para que esta pueda acceder a sus recursos. Cada proceso tiene su máquina virtual, de forma que su código se ejecuta de forma independiente. En principio, cada app tendrá su propio proceso. Con esto, cada aplicación tiene únicamente acceso a los componentes que necesita. De todas maneras, una aplicación puede compartir datos con otras aplicaciones y acceder a servicios del sistema, bien haciendo que dos aplicaciones compartan el ID de usuario bien solicitando permiso al usuario para acceder a datos y recur- sos del dispositivo (la cámara, el micrófono, la conexión bluetooth, la tarjeta SD, los contactos, etc.). E. LOS NIVELES DE LA API, LAS BIBLIOTECAS DE COMPATIBILIDAD Y JETPACK Hemos visto cómo las diferentes versiones de Android introducen cambios sustanciales en cuanto a funcio- namiento y prestaciones. A nivel de desarrolladores, más que la versión, nos interesan los niveles de la API. Estos determinan la compatibilidad de las aplicaciones con las versiones de Android. Con cada nueva versión del sistema, se introduce uno o varios niveles de la API, en función de los cuales dicha API nos ofrecerá unas u otras funcionalidades del dispositivo. Cuando empecemos con el desarrollo de una aplicación Android, deberemos tener en cuenta qué funciona- lidades de la API vamos a necesitar y establecer cuál será el nivel mínimo que requerirá nuestra aplicación. Por ejemplo, si vamos a desarrollar una aplicación que queremos que siga los estándares de Material Design, deberemos utilizar un nivel mínimo de API 21, que es la que se introdujo en Android 5.0, o si deseamos funcio- nalidades presentes en Android 11 o 12, deberemos utilizar los niveles de API 30 y 31, respectivamente. Con la finalidad de proporcionar funcionalidades nuevas o utilizar funcionalidades equivalentes en versiones anteriores de Android, Google lanzó una capa de compatibilidad mediante las support libraries (bibliotecas de compatibilidad). Actualmente esas bibliotecas se integran en Android Jetpack, un conjunto de bibliotecas que permite a los desarrolladores centrarse en la lógica de la aplicación y seguir las prácticas recomendadas, reduciendo código estándar y produciendo código coherente en las diferentes versiones del sistema. 2.2. Android Studio Android Studio es el IDE oficial para el desarrollo en Android, y está basado en el IDE IntelliJ de JetBrains. Hasta 2014 se utilizaba Eclipse con el plugin de Herramientas de Desarrollo de Android (ADT). Las principales características de Android Studio son las siguientes: Es un IDE multiplataforma (Windows, Linux y macOS). Se distribuye bajo licencia Apache 2.0 (libre). Utiliza Gradle para la construcción de paquetes. Incorpora un diseñador de interfaces de tipo WYSIWYG (What you see is what you get) que permite la creación de interfaces mediante arrastrar y soltar (drag and drop) sus componentes. Incluye una serie de plantillas de diseños comunes para las aplicaciones. Permite refactorización de código específica para Android. Ofrece soporte al desarrollo para diferentes dispositivos: smartphones, tabletas, televisores o wereables (tecnología incorporada en cosas que se pueden llevar puestas, con las que uno se puede vestir). Propiedad de McGraw-Hill®. Prohibida la reproducción total o parcial sin el permiso adecuado. Uso exclusivo para el contenido de los cursos FPActiva® de McGraw-Hill. Prohibida la reproducción total o parcial sin el permiso adecuado. Uso exclusivo para el contenido de los cursos FPActiva® de McGraw-Hill. 1 UNIDAD Incorpora un emulador de dispositivos virtuales (Device Manager) para ejecutar, depurar aplicaciones o analizar el rendimiento. Incluye soporte para Google Cloud Platform, que permite la integración con varios servicios de Google. A. DEVICE MANAGER El administrador de dispositivos incorporado en Android Studio, Device Manager, nos permitirá crear y admi- nistrar dispositivos virtuales con Android y también vincular dispositivos físicos reales. Debemos tener en cuenta que la arquitectura y el sistema para los que vamos a desarrollar nuestras aplicacio- nes son diferentes de los de nuestro equipo de desarrollo, sin contar que, además, podemos crear aplicaciones para una amplia gama de dispositivos. Para la depuración de aplicaciones podemos, o bien conectar directamente un dispositivo al equipo y activar el modo desarrollador, o bien utilizar dispositivos virtualizados. La ventaja de la virtualización es que podremos probar nuestras aplicaciones en un gran abanico de dispositivos y configuraciones diferentes. La desventaja es que vamos a tener que crear una máquina virtual para cada uno de los dispositivos que deseemos probar, con el consumo de espacio y memoria que ello implica. En los siguientes casos prácticos vamos a ver cómo realizar la instalación de Android Studio y cómo gestionar dispositivos en el Device Manager. B. LA INTERFAZ DE ANDROID STUDIO Cuando trabajamos en un proyecto, la vista que presenta Android Studio es similar a la siguiente: Propiedad de McGraw-Hill®. Prohibida la reproducción total o parcial sin el permiso adecuado. Uso exclusivo para el contenido de los cursos FPActiva® de McGraw-Hill. Prohibida la reproducción total o parcial sin el permiso adecuado. Uso exclusivo para el contenido de los cursos FPActiva® de McGraw-Hill. 1 UNIDAD Poco a poco iremos descubriendo detalles de esta interfaz, pero, como vemos, no dista mucho de los IDE que ya conocemos. A primera vista, podemos distinguir: La barra de herramientas, para guardar, abrir, construir o ejecutar el programa, entre otras opciones. La barra de navegación, para explorar el proyecto. La ventana del editor, donde tenemos el código o el diseño de la aplicación. La barra de la ventana de herramientas, que rodea todo el IDE y contiene botones para expandir o contraer ventanas de herramientas individuales. Las ventanas de herramientas, con varias utilidades como la administración de proyectos, la búsque- da de texto, el control de versiones, la ventana de depuración, etc. En la ventana de la izquierda de Administración del proyecto (Pestaña Project), aparecen varias vistas de nuestro proyecto, que nos mostrarán este desde diferentes perspectivas. Las que más utilizaremos será la propia del proyecto (Project), la de ficheros (Project Files) y, sobre todo, la vista Android. Disponéis de más información sobre la interfaz en la documentación de desarrolladores de Android. Propiedad de McGraw-Hill®. Prohibida la reproducción total o parcial sin el permiso adecuado. Uso exclusivo para el contenido de los cursos FPActiva® de McGraw-Hill. Prohibida la reproducción total o parcial sin el permiso adecuado. Uso exclusivo para el contenido de los cursos FPActiva® de McGraw-Hill. 1 UNIDAD 3. Estructura y componentes de una aplicación Android 3.1. Estructura de un proyecto en Android Android Studio utiliza Gradle como herramienta de construcción de proyectos. Estos proyectos Android se organizan en módulos, de manera que cada uno de estos módulos será una aplicación diferente. Así, pode- mos tener bajo un mismo proyecto varias versiones de nuestra aplicación para diferentes tipos de dispositivos (tabletas, wereables, etcétera). A continuación, vamos a ver la estructura que se genera en un proyecto Android, desde la vista de los ficheros del proyecto (Project Files) en la ventana lateral de herramientas, y desde la vista de Android. fuente Descriptor En la vista de ficheros del proyecto podemos apreciar la estructura de ficheros típica de un proyecto Gradle, con archivos generales de la aplicación en la carpeta raíz, así como la carpeta propia del módulo de aplicación app. Sin embargo, la vista de Android presenta una perspectiva más compacta y práctica de esta información, organizada en cuatro carpetas lógicas: manifests, java, res y Gradle Scripts. Veamos algunos de los elementos más importantes de esta organización: Los scripts Gradle de construcción del proyecto (build.gradle), tanto el general, situado en la raíz, con información común a todos los módulos, como el propio del módulo de la aplicación (app/build.gradle). En la vista de Android, se muestran ambos scripts dentro de Gradle Scripts y se indica si el script co- rresponde al proyecto o al módulo. Dentro de la carpeta del módulo (app) encontramos la carpeta src, que contiene el código fuente de la aplicación (app/src/main). En la vista Android, este se encuentra en la carpeta java y, como vemos, se muestra en formato de nombre de paquete, en lugar de mostrar la estructura de directorios. La carpeta app/src/res, que contiene los recursos de la aplicación (imágenes, diseños, cadenas de texto, etc.). Si nos fijamos en el detalle, esta carpeta incluye bastantes subcarpetas, para los diferentes tipos de recursos. En la vista de Android, este contenido se muestra de forma más compacta y organi- zada, según el tipo de recurso. El fichero descriptor de la aplicación, app/src/main/AndroidManifest.xml, con información asociada a esta. Como veremos, se trata de uno de los ficheros más importantes de nuestro proyecto, ya que define aspectos como el nombre de la aplicación y el paquete, el icono y sus diferentes componentes. Propiedad de McGraw-Hill®. Prohibida la reproducción total o parcial sin el permiso adecuado. Uso exclusivo para el contenido de los cursos FPActiva® de McGraw-Hill. Prohibida la reproducción total o parcial sin el permiso adecuado. Uso exclusivo para el contenido de los cursos FPActiva® de McGraw-Hill. 1 UNIDAD A. SCRIPTS DE GRADLE Como hemos comentado, un proyecto Android define un script de configuración build.gradle general al pro- yecto, ubicado en la carpeta raíz, y otro ubicado en la carpeta app, que hace referencia al propio módulo de la aplicación. El contenido del script de construcción general tendrá la estructura siguiente: buildscript { repositories { google() mavenCentral() } dependencies {...} } task clean(type: Delete) { delete rootProject.buildDir } Como podemos apreciar, simplemente especifica los repositorios generales para descargar paquetes y define la tarea para limpiar el proyecto. El fichero de construcción que más nos interesará es, pues, el del propio módulo de la aplicación. De forma simplificada, este fichero tiene la estructura siguiente: plugins { id ‘com.android.application’ id ‘kotlin-android’ } android { compileSdk 31 defaultConfig { applicationId “com.mgh.pmdm.holamundo” minSdk 21 targetSdk 31... } buildTypes {... } compileOptions {... } kotlinOptions {... } } dependencies { implementation ‘androidx.core:core-ktx:1.7.0’ implementation ‘androidx.appcompat:appcompat:1.4.0’ implementation ‘com.google.android.material:material:1.4.0’... } Propiedad de McGraw-Hill®. Prohibida la reproducción total o parcial sin el permiso adecuado. Uso exclusivo para el contenido de los cursos FPActiva® de McGraw-Hill. Prohibida la reproducción total o parcial sin el permiso adecuado. Uso exclusivo para el contenido de los cursos FPActiva® de McGraw-Hill. 1 UNIDAD En primer lugar, el script carga un par de plugins para generar una aplicación Android (com.android.applica- tion) en Kotlin (kotlin-android). En segundo lugar, observamos que aparece una sección android, en la que vamos a definir los aspectos prin- cipales de construcción para Android, entre ellos: La versión del SDK con la que compilamos la aplicación (compileSdk). La configuración de esta (defaultConfig), con el ID, el SDK mínimo que soportará (minSdk) o la versión más alta con la que se ha probado la aplicación (targetSdk), entre otros. Estas opciones se configurarán cuando creemos la aplicación. Algunos detalles para la construcción y la compilación del proyecto (versiones release o debug en buildtypes, o la versión del bytecode que se generará con compileOptions). Las dependencias (dependencies) del proyecto, entre las que destacan las bibliotecas de Jetpack (an- droidx.*), que incluyen las bibliotecas de compatibilidad (androidx.appcompat) y las bibliotecas de componentes Material Design (com.google.android.material). En este punto, debemos hacer una observación respecto a otro tipo de aplicaciones Gradle con las que haya- mos trabajado previamente, y es que no se ha especificado la clase principal (mainClass) y ni siquiera existe la sección application. Como veremos a continuación, el punto de entrada lo especificaremos en el fichero AndroidManifest.xml. B. EL FICHERO ANDROIDMANIFEST.XML Y LOS COMPONENTES DE LA APLICACIÓN El fichero de Manifest es un fichero propio de cada aplicación que contiene información sobre esta. La infor- mación se utiliza tanto por las herramientas de creación de Android como por el propio sistema y por Google Play. Entre la información que vamos a poder encontrar en él, podemos destacar: El nombre del paquete de la aplicación, que generalmente coincide con el paquete de Java de las entidades de programación que componen nuestra aplicación, de modo que el sistema sepa dónde encontrarlas. Los diferentes componentes de la aplicación y sus propiedades: las actividades (), los ser- vicios, () los receptores de emisiones () y los proveedores de contenidos (). Trataremos estos componentes más adelante. Los permisos de la aplicación para acceder a recursos protegidos del sistema o a otras aplicaciones, así como los permisos que deben poseer otras aplicaciones para acceder al contenido de esta. Las diferentes funcionalidades hardware y software que va a necesitar nuestra aplicación, de modo que Google Play impida su instalación en dispositivos que no posean dichas funcionalidades. A modo de ejemplo, veamos el AndroidManifest.xml de una aplicación tipo Hola Mundo como la que creare- mos en el Caso práctico 1. La estructura general del fichero es la siguiente:... Como vemos, el elemento raíz manifest define: El espacio de nombres android, con xmlns:andrioid, lo que nos permite utilizar posteriormente atribu- tos de tipo android:. Propiedad de McGraw-Hill®. Prohibida la reproducción total o parcial sin el permiso adecuado. Uso exclusivo para el contenido de los cursos FPActiva® de McGraw-Hill. Prohibida la reproducción total o parcial sin el permiso adecuado. Uso exclusivo para el contenido de los cursos FPActiva® de McGraw-Hill. 1 UNIDAD El paquete com.pmdm.holamundo de la aplicación. Este nombre de paquete será usado por el sistema para nombrar tanto los recursos como los diferentes elementos declarados en el manifest. Pasamos ahora al elemento application, que contiene toda la información sobre la aplicación:... Como podemos apreciar, en él se definen varios atributos específicos de Android, como el icono, la etiqueta o el tema que determina el aspecto de la aplicación. Muchos de estos elementos aparecen precedidos por el símbolo @, lo que indica que hacen referencia a recursos de la aplicación. Como ya hemos comentado, dentro de application se definen los diferentes componentes de esta, en este caso con una única actividad: Con esto indicamos que la aplicación lleva por nombre.MainActivity (realmente es com.mgh.pmdm.MainAc- tivity), y que esta va a poder recibir mensajes desde fuera de la aplicación (android:exported=”true”) o puede ser llamada por otros componentes de esta. Por otra parte, también se define un elemento intent-filter, donde se especifican las acciones a las que va a responder esta actividad. En este caso, se define la acción android.intent.action.MAIN, con categoría android. intent.category.LAUNCHER. Con MAIN indicamos que este es el punto de entrada a la aplicación, y especi- ficando la categoría LAUNCHER indicamos que esta actividad debe aparecer en el lanzador de aplicaciones. Dentro del mismo elemento application definiremos el resto de componentes de la aplicación. Los compo- nentes que no se incluyan no serán visibles para el sistema. C. RECURSOS DE LA APLICACIÓN La carpeta de recursos de la aplicación (res) contiene, organizados en subcarpetas, los diferentes tipos de recursos que son utilizados por esta. Cuando programamos cualquier aplicación, es conveniente mantener los recursos de forma externa a la aplicación, para facilitar su mantenimiento de forma independiente. Aunque existen varias carpetas físicas para los diferentes tipos de recursos, en la vista de Android se presenta una organización lógica de todos estos. Entre estas carpetas lógicas encontramos: drawable/: Contiene elementos de diseño gráfico que podemos dibujar en la pantalla del dispositivo: no solo imágenes, sino también listas de capas, estados o niveles, entre muchos otros. mipmap/: Contiene los diferentes iconos de la aplicación, en diferentes densidades (ppp). layout/: Contiene los diseños de diferentes partes de la interfaz de usuario, en formato XML. Propiedad de McGraw-Hill®. Prohibida la reproducción total o parcial sin el permiso adecuado. Uso exclusivo para el contenido de los cursos FPActiva® de McGraw-Hill. Prohibida la reproducción total o parcial sin el permiso adecuado. Uso exclusivo para el contenido de los cursos FPActiva® de McGraw-Hill. 1 UNIDAD values/: Contiene ficheros en formato XML con valores simples, como cadenas de caracteres, valores enteros o colores. menu/: Con archivos XML que definen diferentes tipos de menú de la aplicación. animator/ y anim/: Archivos XML con diferentes tipos de animaciones. color/: Archivos XML con listas de estados de color para aplicar sobre diferentes elementos de interfaz y que estos cambien de color según su estado. xml/: Archivos XML que podemos leer en tiempo de ejecución, con algunas configuraciones especiales. font/: Carpeta para almacenar tipografías específicas de la aplicación. raw/: Contiene archivos sin procesar, que deberemos tratar como streams. IMPORTANTE Esta clase estará dentro del espacio de nombres de nuestra aplicación. Por ejemplo, si una aplicación tiene como nombre de paquete de la aplicación com.mgh.pmdm, la clase con los recursos será com. mgh.pmdm.R. Por otra parte, además de la clase R de recursos de nuestra aplicación, disponemos de una clase R con los recursos proporcionados por Android, que lleva por nombre android.R. 3.2. Componentes de una aplicación Como hemos comentado en el punto anterior, las aplicaciones Android tienen principalmente cuatro tipos de componentes que podemos especificar en el archivo de manifiesto: actividades, servicios, receptores de anuncios y proveedores de contenidos. A. ACTIVIDADES (ACTIVITIES) Representan las diferentes pantallas de la aplicación y recogen la interacción con el usuario. Cada actividad puede ser un punto de entrada a la aplicación y puede ser requerida por otras aplicaciones, lo que permite reutilizar funcionalidades. Por ejemplo, si queremos enviar una foto mediante una aplicación de mensajería, se utiliza directamente la actividad correspondiente de la aplicación de la cámara en lugar de implementar esta funcionalidad en la aplicación. B. SERVICIOS (SERVICES) Los servicios son puntos de entrada general que nos permiten mantener la ejecución de la aplicación en segundo plano y que no proporcionan interfaz de usuario, como pudiera ser un servicio de reproducción de audio o la sincronización de datos desde la red, lo cual permite que el usuario se encuentre interactuando con otra actividad. C. RECEPTORES DE ANUNCIOS (BROADCAST RECEIVERS) Se trata de componentes que recogen ciertos eventos del sistema fuera del flujo habitual de las aplicaciones y permiten incluso enviar notificaciones a aplicaciones que no están en ejecución. Algunos ejemplos pueden ser lanzados por el propio sistema, como el aviso de apagado de la pantalla, el de batería baja o el de que se ha hecho una captura de pantalla. Estos componentes tampoco tienen interfaz gráfica, pero pueden crear notificaciones en la barra de estado o servir como puerta de entrada a otros componentes. D. PROVEEDORES DE CONTENIDOS (CONTENT PROVIDERS) Permiten compartir contenidos entre aplicaciones de forma segura. Ejemplos de ello son los contactos del usuario o el almacenamiento en el dispositivo. Propiedad de McGraw-Hill®. Prohibida la reproducción total o parcial sin el permiso adecuado. Uso exclusivo para el contenido de los cursos FPActiva® de McGraw-Hill. Prohibida la reproducción total o parcial sin el permiso adecuado. Uso exclusivo para el contenido de los cursos FPActiva® de McGraw-Hill. 1 UNIDAD E. OTROS COMPONENTES DE LA APLICACIÓN Además de los anteriores componentes, que podemos incluir en el archivo de manifiesto, existen otros com- ponentes clave en el desarrollo de aplicaciones Android. Estos componentes son los siguientes: Vistas (View). Se conoce como vista a cada uno de los componentes de la interfaz de usuario: botones, textos, etcétera. Todos estos elementos serán subclases de la clase View, y, aunque pueden crearse dinámicamente desde el código, lo más habitual será definirlos directamente en los archivos de diseño (Layout) y dejar que Android los cree por nosotros. Diseños (Layout). Ya hemos comentado que en la carpeta layout se encuentran los diferentes diseños de la interfaz de nuestra aplicación, en formato XML. Estos diseños contendrán las diferentes vistas o elementos de interfaz, tanto de una actividad como de un fragmento (Fragment). Pese a que se pue- dan crear directamente (ya que también son objetos de tipo View), lo habitual es generarlos en formato XML dentro de esta carpeta. Fragmentos (Fragment). Se introdujeron en Android 3.0, con la interfaz Holo, para aprovechar el mayor tamaño de las pantallas de las tabletas. Un fragmento consiste en una agrupación de vistas (elementos de la interfaz) que funcionan como un bloque. De este modo, en función del tamaño de la pantalla, una actividad puede constar de uno o varios fragmentos. Además, los fragmentos permiten una navegación entre ellos más ligera que las actividades, y por ello su uso es bastante habitual en las aplicaciones modernas. Intenciones (Intents). Las actividades, los servicios y los receptores de emisión se activan mediante mensajes asíncronos conocidos como Intenciones (Intents), que vinculan en tiempo de ejecución di- ferentes componentes. Estos mensajes pueden servir para activar un componente específico (intento explícito) o un tipo de componente más genérico (intento implícito), que puede ser tanto interno como externo a nuestra aplicación. Propiedad de McGraw-Hill®. Prohibida la reproducción total o parcial sin el permiso adecuado. Uso exclusivo para el contenido de los cursos FPActiva® de McGraw-Hill. Prohibida la reproducción total o parcial sin el permiso adecuado. Uso exclusivo para el contenido de los cursos FPActiva® de McGraw-Hill. 1 UNIDAD 4. El lenguaje Kotlin 4.1. Kotlin. Generalidades del lenguaje Kotlin es un lenguaje de programación creado por JetBrains en 2011, y en la actualidad desarrollado conjunta- mente por JetBrains y Google a través de la Kotlin Foundation. Actualmente es el lenguaje recomendado por Google para el desarrollo de aplicaciones para la plataforma Android. Algunas de las características más interesantes de Kotlin son las siguientes: Es un lenguaje multiplataforma en el sentido más amplio del término, ya que soporta la generación de código para diferentes plataformas, entre las que se encuentra la máquina virtual de Java (JVM), el runtime de Android ART e incluso JavaScript. Además, actualmente JetBrains está trabajando en KMM (Kotlin Multiplatform Mobile), lo que permitirá el desarrollo de aplicaciones iOS con prácticamente la misma base de código. El hecho de compilar directamente sobre JVM hace que sea totalmente compatible con Java y, por tanto, con sus librerías. Es un lenguaje orientado a objetos, con tipado estático e inferencia de tipos. Es un lenguaje más conciso, evita código innecesario y repetitivo. Es un lenguaje Null Safety, lo que significa que gestiona los valores nulos de forma segura y evita erro- res de tipo NullPointerException. En este apartado vamos a ver los aspectos más relevantes del lenguaje para empezar a entender el código, y poco a poco iremos ampliando nuestros conocimientos de Kotlin para la programación en Android. Para el desarrollo de Kotlin en nuestro escritorio necesitaremos el compilador de Kotlin, así como algún IDE que lo soporte, como IntelliJ o VSCode con el plugin de Kotlin. En nuestro caso, seguiremos utilizando Android Studio, ya que desarrollaremos para esta plataforma, aunque los ejemplos que son puramente de Kotlin los podemos probar en el Playground que nos ofrece Jetbrains. HOLA MUNDO! GENERALIDADES DE KOTLIN A modo de ejemplo, veamos la estructura de un típico «Hola Mundo!» en Kotlin: fun main() { // Esta función escribe Hola Mundo por la salida estándar println(“Hola Mundo!”) } Como podemos ver, se trata de un código bastante sencillo, pero del que ya podemos extraer algunas ideas: La función principal (main) se declara como una función de primer nivel, sin necesidad de que esté dentro de una clase. Por lo tanto, Kotlin soporta la programación orientada a objetos, pero no requiere, a diferencia de Java, que todo sean clases. La función main puede recibir argumentos, aunque no es necesario indicarlo. Tampoco hay que indicar la visibilidad de la función (public), ni si esta es estática (static). La función println está disponible directamente, sin pasar por System.out. Los signos de punto y coma (;) de final de línea son opcionales, y suelen evitarse por convención. Los comentarios, tanto de una línea como de varias, se expresan igual que en Java. Propiedad de McGraw-Hill®. Prohibida la reproducción total o parcial sin el permiso adecuado. Uso exclusivo para el contenido de los cursos FPActiva® de McGraw-Hill. Prohibida la reproducción total o parcial sin el permiso adecuado. Uso exclusivo para el contenido de los cursos FPActiva® de McGraw-Hill. 1 UNIDAD 4.2. Variables y operadores en Kotlin En Kotlin todos los tipos de datos son clases, de forma que podemos acceder directamente a sus propieda- des y funciones miembro. Recordemos que para esto en Java necesitábamos clases envoltorio para los tipos básicos. Para definir variables en Kotlin usaremos las palabras reservadas var o val, de modo que: Utilizaremos var para definir variables mutables, es decir, que pueden cambiar de valor. Utilizaremos val para definir variables inmutables o lo que en Java serían valores constantes. En general, y por temas de rendimiento, se recomienda utilizar valores constantes siempre que sepamos que no van a ser modificados. Por otro lado, hay que mencionar que, aunque Kotlin posea tipado estático, no obliga a definir el tipo de las variables, siempre y cuando este se pueda inferir a partir de su contexto. Por ejemplo: val pi = 3.14 // Variable inmutable, con tipo inferido a Float val modulo modulo=”PMDM” // Variable inmutable, inferida a tipo String. Aunque // aparezca en dos líneas, se trata de una única asignación No obstante, si deseamos indicar el tipo de dato en la asignación, podemos hacerlo utilizando las sintaxis siguientes: val nombreVariable: Tipo val nombreVariable: Tipo = Valor A. TIPOS DE DATOS Kotlin posee prácticamente los mismos tipos de datos que Java: Tipos numéricos: Byte, Short, Int, Long, Float y Double. Caracteres: Char. Los caracteres especiales utilizan secuencias de escape mediante la barra invertida: `’\t’`, `’\b’`, `’\ `, `’\r’`, `’\’’`, `’\”’`, `’\\’`, `’\S’`. Cadenas de caracteres: String. Soporta también String Templates, o literales de cadena, que pueden contener expresiones que serán evaluadas y su resultado, concatenado a la cadena. Por ejemplo: fun main(){ val valor=”Mundo!” println(“Hola ${valor}”) println(“$valor té ${valor.length} caracteres”) val temperatura = 27 println(“Con ${temperatura}º hace ${if (temperatura > 24) “calor” else “frío”}”) } Clases y objetos: Como veremos más adelante, Kotlin, aparte de definir clases, nos va a permitir definir objetos directamente. Todas las clases de Kotlin, incluidas las clases que representan tipos básicos, son descendientes directa o indirectamente de la clase Any, que sería el equivalente a la clase Object de Java. Para trabajar con estos tipos de datos utilizamos los diferentes operadores (de asignación, aritméticos, lógicos, etcétera), que son prácticamente los que ya conocemos de Java. B. VALORES NULOS O NULLABLE TYPES Hemos comentado que Kotlin es un lenguaje seguro (null safety), de modo que, entre otras cosas, evita errores del tipo NullPointerException. Esto se traduce en que, por defecto, todas las variables en Kotlin van a tener un valor no nulo. Propiedad de McGraw-Hill®. Prohibida la reproducción total o parcial sin el permiso adecuado. Uso exclusivo para el contenido de los cursos FPActiva® de McGraw-Hill. Prohibida la reproducción total o parcial sin el permiso adecuado. Uso exclusivo para el contenido de los cursos FPActiva® de McGraw-Hill. 1 UNIDAD De todos modos, es posible que en ocasiones necesitemos poder especificar que una variable pueda contener explícitamente un valor nulo. En este caso, deberemos definir dicha variable como nullable añadiendo un in- terrogante al tipo, del modo siguiente: val variable: Tipo?=null Estos son los operadores a utilizar: El operador Safe Call Operator ‘?.’ Para aportar más seguridad a las variables nullables y poder acceder a propiedades o métodos de un objeto de este tipo, Kotlin nos ofrece el operador Safe Call Operator, compuesto por un interrogante y un punto (?.). Este operador nos permitirá acceder a atributos o méto- dos de un objeto solamente si tiene un valor no nulo. En caso de que este sea nulo, se ignorará, evitando así una excepción de tipo NullPointerException. Por ejemplo: println (objeto?.valor) // Si objeto es nulo, se evitará la excepción El operador *Elvis* ‘?:’ Kotlin también nos proporciona el operador (?:), conocido como el operador Elvis y compuesto por un interrogante y los dos puntos. Este operador sirve para especificar un valor alternativo cuando la variable es nula. Por ejemplo: val variable2=variable?:0 // variable2 tendrá el contenido de variable o 0 Operador de aserción no-nula ‘!!’ Este operador convierte cualquier valor de tipo nullable a un tipo no nulo, y se utiliza para poder forzar que se lance una excepción NullPointerException cuando ac- cedemos a dicho valor nulo. Este operador será necesario en algunas ocasiones en que no podremos asegurar que una variable tenga o no valor. Veamos un pequeño ejemplo del uso de estos operadores: fun main(){ val nombre:String?=”Android” // nombre puede ser nulo println(nombre?.length) // muestra 7 val nombre2:String?=null // nombre2 puede ser nulo println(nombre2?.length) // muestra null // Si no utilizamos el operador safe call, provocamos el error: // Only safe (?.) or non-null asserted (!!.) calls are allowed // on a nullable receiver of type String? // println(nombre2.length) // -> Error // Ejemplos con el operador Elvis println(nombre?.length ?: -1) // Muestra 7 println(nombre2?.length ?: -1) // Muestra -1 // Ejemplo que fuerza una excepción de tipo NullPointerException println(nombre2!!.length) } Podéis ver este código en funcionamiento en el enlace siguiente: https://pl.kotl.in/gV3A-AfD6 Propiedad de McGraw-Hill®. Prohibida la reproducción total o parcial sin el permiso adecuado. Uso exclusivo para el contenido de los cursos FPActiva® de McGraw-Hill. Prohibida la reproducción total o parcial sin el permiso adecuado. Uso exclusivo para el contenido de los cursos FPActiva® de McGraw-Hill. 1 UNIDAD 4.3. Funciones y expresiones lambda Kotlin contempla que puedan existir funciones que no estén vinculadas como métodos a ningún objeto. Estas funciones se conocen como funciones de primer orden o Top Level Functions, y pueden ser utilizadas sin la necesidad de obtenerse como instancias de algún objeto. La definición de una función en Kotlin sigue la sintaxis siguiente: fun nombreFuncion(parámetro1:Tipo1, parámetro2:Tipo2...):TipoRetorno{ // Cuerpo de la función } Observad que, del mismo modo que para definir variables invertimos el orden del tipo y el valor, aquí también lo invertimos para los argumentos y para el tipo de retorno de la función. EXPRESIONES LAMBDA Las expresiones lambda o funciones literales tampoco están asociadas a clases, objetos o interfaces. Su utili- dad radica en que pueden pasarse como argumentos a otras funciones, conocidas como funciones de orden superior, Higher-Order functions (no confundir con las funciones de primer orden), y supone una simplificación del bloque de código de una función. Aunque Java soporta expresiones lambda desde Java 8, en Kotlin son ligeramente distintas. Las principales características de una expresión lambda son las siguientes: Se expresa entre llaves { }. No tiene la palabra clave fun. No tiene modificadores de acceso (private, public, protected), ya que no pertenece a ninguna clase. Es una función anónima, es decir, sin nombre. No especifica el tipo de retorno, ya que este es inferido por el compilador. Los parámetros no se expresan entre paréntesis. Podemos asignar una expresión lambda a una variable y ejecutarla. Veamos algunas formas de crear expresiones lambda. Expresión lambda sin parámetros y asignada a una variable Declaración: val msg = { println(“Hola Mundo! Soy una función lambda”) } Invocación: msg() Expresión lambda con parámetros y asignada a una variable Declaración: Se utiliza una flecha (->), de modo que en la parte izquierda se indican los argumentos y en la derecha, el cuerpo de la función. val msg = { cadena: String -> println(cadena) } Invocación: msg(“Hola Kotlin!”) Paso de expresiones lambda a funciones Las expresiones lambda pueden usarse como argumentos de otras funciones, conocidas como funciones de orden superior (Higher-Order functions). Propiedad de McGraw-Hill®. Prohibida la reproducción total o parcial sin el permiso adecuado. Uso exclusivo para el contenido de los cursos FPActiva® de McGraw-Hill. Prohibida la reproducción total o parcial sin el permiso adecuado. Uso exclusivo para el contenido de los cursos FPActiva® de McGraw-Hill. 1 UNIDAD Esto tiene varias utilidades, pero quizás la más habitual sea su uso en la gestión de eventos de la interfaz de usuario, como veremos más adelante. Aquí vemos un pequeño ejemplo de uso de expresiones lambda: fun operacion(x: Int, y: Int, lambda:(Int, Int)->Int):Int{ return lambda(x, y) } fun main(){ val x=5 val y=3 val suma = { x: Int, y:Int -> x + y } val resta = {x: Int, y:Int -> x - y } println(operacion(x, y, suma)) println(operacion(x, y, resta)) } Observamos que hemos definido una función llamada operacion, que recibe dos enteros, X e Y, y una expre- sión lambda, y devuelve un entero. Dicha expresión también recibirá dos enteros y devolverá un valor entero. Fijaos en la forma de declarar que un argumento es una función lambda: lambda:(Int, Int)->Int En la función principal definimos las variables x e y, y las expresiones lambda suma y resta, que reciben dos números enteros y devuelven, respectivamente, su suma y su resta. Posteriormente, se muestra el resultado de invocar a la función operacion pasándole x e y como argumentos y una u otra expresión lambda. El resultado es que se muestra el resultado de la suma por una parte (8), y por otra el resultado de la resta (2). Observad cómo, mediante estas expresiones, tenemos la capacidad de proporcionar funciones a otras funciones para modificar su comportamiento. Podéis ver este código en funcionamiento en el enlace siguiente: https://pl.kotl.in/iV_3kCKNL El nombre de argumento it Cuando una función recibe un único argumento y su tipo puede ser inferido, se genera automáticamente un argumento por defecto que lleva por nombre it. Este argumento puede utilizarse para simplificar más las expresiones. Veamos un ejemplo simple: fun operacion(x: Int, lambda:(Int)-> Boolean):Boolean{ return lambda(x) } fun main(){ val x=5 // Muestra true o false en función // De si el número es par o impar println(operacion(x, { it%2==0 } )) } Vemos que la expresión lambda { it%2==0 } se indica directamente como argumento de la función opera- cion. Dicha expresión tiene un único argumento, por lo que dentro podemos utilizar it para trabajar con él. Propiedad de McGraw-Hill®. Prohibida la reproducción total o parcial sin el permiso adecuado. Uso exclusivo para el contenido de los cursos FPActiva® de McGraw-Hill. Prohibida la reproducción total o parcial sin el permiso adecuado. Uso exclusivo para el contenido de los cursos FPActiva® de McGraw-Hill. 1 UNIDAD 4.4. Clases y objetos en Kotlin La forma de declarar clases en Kotlin es bastante similar a la de Java, aunque con una sintaxis más compacta y versátil. De hecho, aunque no tendría demasiada utilidad, Kotlin permite declarar una clase de la manera más simple posible con: class nombreClasse Para crear una instancia de esta clase, simplemente deberíamos declarar una variable del siguiente modo: val miObjeto=nombreClasse() Observad que en Kotlin no utilizamos el operador new para crear instancias, sino el nombre de la clase como si invocásemos directamente a una función. En Kotlin existen varias formas de crear una clase que encapsule propiedades y métodos, y diferentes formas de definir el constructor. Vamos a ver una de estas formas, que es utilizando lo que se conoce como cons- tructor primario, la forma que utiliza Android para crear clases: class nombreClase constructor(parametro1: Tipo1,...,parametroN: TipoN) { [nivelAcceso] [var | val] propiedad1: Tipo1.. [nivelAcceso] [var | val] propiedadN: TipoN init { this.propiedad1=parametro1;... this.propiedadN=parametroN; } [nivelAcceso] fun metodoX(lista_de_parametros): TipoRetorno { // Cuerpo del método } } Como vemos, Kotlin permite declarar un constructor en la misma cabecera de la clase, conocido como el constructor primario. Además, se define un bloque init que se corresponde a la inicialización de parámetros de este constructor. Asimismo, Kotlin permite simplificar esta construcción declarando las propiedades directamente en el cons- tructor primario, precedidas de var o val según sean mutables o inmutables: class nombreClase constructor([var | val ] propiedad1: Tpo1,..., [var | val ] propiedadN: TipoN) { [nivelAcceso] fun metodoX(lista_de_parametros): TipoRetorno { // Cuerpo del método } } Propiedad de McGraw-Hill®. Prohibida la reproducción total o parcial sin el permiso adecuado. Uso exclusivo para el contenido de los cursos FPActiva® de McGraw-Hill. Prohibida la reproducción total o parcial sin el permiso adecuado. Uso exclusivo para el contenido de los cursos FPActiva® de McGraw-Hill. 1 UNIDAD En esta misma construcción también podemos indicar valores por defecto siguiendo la sintaxis propiedad1:Tipo1=Valor_por_defecto. En caso que la clase no tenga modificadores de acceso o anotaciones, incluso puede omitirse la palabra clave constructor. Veamos algunos detalles más acerca de la definición de clases en Kotlin: Las propiedades de la clase pueden ser mutables (var) o inmutables (val), y podemos indicar modifica- dores de acceso como public, private o protected. Esta construcción admite otros constructores secundarios, con diferentes bloques de tipo constructor, y así permite la sobrecarga de constructores. En Kotlin no necesitamos definir métodos consultores y modificadores (getters y setters), ya que estos son generados directamente por el compilador para las propiedades públicas. Además, se simplifica su acceso, puesto que se utilizan de forma transparente a través del nombre de cada propiedad. Si la propiedad es mutable, se generará un getter y un setter, mientras que, si es inmutable, únicamente se generará el getter. Los métodos se declaran con la misma sintaxis que una función, pero de manera interna a la clase. Para crear una instancia de la clase anterior y acceder a sus propiedades, lo haríamos de este modo: [ val | var ] objeto=Clase(Valor1,... , ValorN) println(objeto.propiedad1) // Realmente accedemos al getter de propiedad1 objeto.propiedad2 = valorX // Accedemos al setter, si propiedad2 es mutable A. HERENCIA Los conceptos de herencia y polimorfismo en Kotlin son prácticamente los mismos que en Java, salvo algunos detalles que mencionaremos a continuación, así como la sintaxis, que varía ligeramente. La diferencia más importante con respecto a Java es que las clases se definen como final de forma predeter- minada. Es decir, si no se especifica nada una clase se considera final y no se podrán crear clases derivadas de ella. Esto sigue una de las buenas prácticas de la ingeniería del software, que promueve que las clases se definan siempre como finales y únicamente se deje como abiertas aquellas que sí tendrán herencia de forma explícita. Para definir una clase abierta, en Kotlin la declararemos precedida de la palabra clave open. También debemos tener en cuenta que los métodos definidos en una superclase se consideran finales, de modo que para que se puedan sobrescribir necesitan definirse explícitamente como open. open class nombreSuperclase {... open fun f1(Parametros:Tipos):TipoRetorno{...} open fun f2(Parametros:Tipos):TipoRetorno{...}... } Para indicar que una clase desciende de otra se utilizan los dos puntos. Si deseamos sobrescribir los métodos, utilizaremos la palabra clave override antes de definir el método (a diferencia de Java, en que utilizamos anotaciones): class nombreSubClase : nombreSuperclase() {... // Sobreescritura del método f1. Por defecto, este método sobeescrito // ahora será open. override fun f1(Paràmetres:Tipus):TipoRetorno{...} Propiedad de McGraw-Hill®. Prohibida la reproducción total o parcial sin el permiso adecuado. Uso exclusivo para el contenido de los cursos FPActiva® de McGraw-Hill. Prohibida la reproducción total o parcial sin el permiso adecuado. Uso exclusivo para el contenido de los cursos FPActiva® de McGraw-Hill. 1 UNIDAD // Sobreescritura de f2, declarándolo como final override final fun f2(Parametros:Tipos):TipoRetorno{...} } B. INTERFACES Recordemos que una interfaz define un comportamiento común a varias clases que la implementan. Este comportamiento se concreta en una serie de métodos abstractos que las clases que implementan la interfaz deben aplicar. La forma de definir una interfaz en Kotlin es similar a la definición de una clase, pero utilizando la palabra clave interface y sin utilizar constructores: interface IdentificadorInterfaz { // Constantes val Identificador_1:Tipo_1=Valor_1;... // Métodos abstractps fun Metodo(parámetro_1:Tipo_1): TipoRetorno_1;... } Y para definir una clase que implemente la interfaz utilizamos una sintaxis muy parecida a la de la herencia, con la diferencia de que no invocamos al constructor: class NombreClase : NombreInterfaz { // Implementación de los métodos de la interfaz override fun Metodo(parámetro_1:Tipo_1): TipusRetorno_1{ // Implementación }... } Además, una clase puede implementar tantas interfaces como desee, separándolas por una coma, aunque solo va a poder extenderse de una clase. A diferencia de Java, aquí la palabra clave override es obligatoria para sobrescribir los métodos de la interfaz. Una interfaz también puede ofrecer una implementación por defecto para los métodos, pudiéndolos utilizar directamente en las clases que implementan la interfaz o sobrescribirlos con override. En caso de sobrescribir los métodos por defecto, se puede acceder a la implementación por defecto mediante super. La programación orientada a objetos de Kotlin guarda todavía muchas más cosas interesantes, como la po- sibilidad de personalizar getters y setters o la creación directa de objetos sin necesidad de instanciar clases. Todo ello lo iremos viendo poco a poco a lo largo del curso y en los materiales adicionales. IMPORTANTE tar la ampliación de estos contenidos en la sección Material de trabajo/Enlaces web. Propiedad de McGraw-Hill®. Prohibida la reproducción total o parcial sin el permiso adecuado. Uso exclusivo para el contenido de los cursos FPActiva® de McGraw-Hill. Prohibida la reproducción total o parcial sin el permiso adecuado. Uso exclusivo para el contenido de los cursos FPActiva® de McGraw-Hill. 1 UNIDAD 5. Actividades, cicfo de vida y depuracióu 5.1. Actividades Como hemos visto, las actividades son uno de los componentes principales de las aplicaciones en Android y representan las diferentes pantallas en que recogemos la interacción del usuario. Las actividades son objetos de la clase Activity o alguna clase descendiente, como AppCompatActivity, y son instanciadas por el propio sistema Android. Además, están vinculadas a algún recurso de tipo Layout, donde se especifican los diferentes elementos de interfaz (botones, textos, etc.). Estos elementos serán elementos especializados de la clase View, conocidos como Vistas. En este apartado vamos a examinar y trabajar el proyecto Contador, que deberás haber descargado en la sección Ejemplos para trabajar y analizar. A. tA CtAS5 Maı AcTIuıTr Cuando generamos una aplicación basada en un proyecto de tipo Empty Activity, se genera una clase princi- pal MainActivity (fichero MainActivity.tk), con el contenido siguiente: package com.mgh.pmdm.contador import androidx.appcompat.app.AppCompatActivity import android.os.Bundle class MainActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) } } La sintaxis de este código ya nos resulta familiar. En primer lugar, define el paquete com.mgh.pmdm.conta- dor de la aplicación, y seguidamente importa un par de clases: androidx.appcompat.app.AppCompatActivity: Hace referencia a las librerías de compatibilidad (app- compat) dentro de Jetpack (androidx). De estas librerías importa la clase AppCompatActivity, que es la clase base para aquellas actividades que requieran características comunes como la barra de acciones, la barra de herramientas, los modos de navegación o el cambio entre temas claros y oscuros. android.os.Bundle: Se trata de una clase del sistema que permite mantener el estado de la actividad en la recarga y facilita la comunicación entre actividades. Posteriormente veremos su utilidad. Después de importar las librerías, se declara la clase principal MainActivity como una subclase de AppCom- patActivity y se sobrescribe el método onCreate, que recibe un objeto nullable de tipo Bundle llamado save- dInstanceState. Profundizaremos en todo esto más adelante. De momento, como podéis ver, aunque se trate de la clase que gestiona la actividad principal de la aplicación, no existe un método o una función main que la inicie explícitamente. De esto se encargará el propio sistema Android. Recordad que en archivo AndroidManifest.xml se registran las actividades de las que se compone la aplicación, y en este registro se indican sus puntos de entrada. Concretamente, sabemos que esta es la actividad principal de la aplicación por la acción android.intent.action.Main: Propiedad de McGraw-Hill®. Prohibida la reproducción total o parcial sin el permiso adecuado. Uso exclusivo para el contenido de los cursos FPActiva® de McGraw-Hill. Prohibida la reproducción total o parcial sin el permiso adecuado. Uso exclusivo para el contenido de los cursos FPActiva® de McGraw-Hill. 1 UNIDAD Más adelante detallaremos el ciclo de vida de una actividad. De momento, podemos avanzar que el método onCreate se invoca automáticamente cuando se crea la actividad. Este método contiene, inicialmente, una llamada al método onCreate de su superclase (AppCompatActivity) y una llamada al método setContentView, que establece el contenido de la vista (interfaz) a partir del recurso R.layout.activity_main. B. 5t tAYOUT O DIS5ÑO D5 tA ACTIVIDAD Cuando se crea la actividad y se establece el contenido de la vista, el recurso R.layout.activity_main con el que se inicializa hace referencia al fichero activity-main.xml, ubicado dentro de la carpeta de recursos res/layout. Estos ficheros XML contienen el diseño con los diferentes elementos de la interfaz de usuario de las activi- dades. A pesar de ser un fichero XML, Android Studio muestra una interfaz WYSIWYG (What you see is what you get), de forma que vemos el diseño de la pantalla junto con una paleta de componentes que podemos arrastrar y soltar, así como los atributos de cada elemento de la interfaz. Trabajaremos con este diseñador en la unidad siguiente. Por ahora, observad que en la parte superior derecha este diseñador ofrece tres vistas: Code, Split y Design. Podemos consultar el código XML de la interfaz con la vista de código (Code), o podemos usar la vista dividida (Split) para ver el código y el diseñador al mismo tiempo. En el código XML de la interfaz podemos encontrar algunos elementos interesantes: Propiedad de McGraw-Hill®. Prohibida la reproducción total o parcial sin el permiso adecuado. Uso exclusivo para el contenido de los cursos FPActiva® de McGraw-Hill. Prohibida la reproducción total o parcial sin el permiso adecuado. Uso exclusivo para el contenido de los cursos FPActiva® de McGraw-Hill. 1 UNIDAD Como podemos ver, consta de un elemento raíz de tipo ConstraintLayout asociado, en principio, a la actividad MainActivity, dentro del cual se define un componente o Vista de tipo TextView con el texto «Hello World!». C. tA CtAS5 Maı AcTIuıTr 5N 5t PROT5CTO CONTADOR En el proyecto Contador que está disponible para descarga se han añadido algunos componentes más a la interfaz y, también, funcionalidad a la clase MainActivity para ilustrar algunos conceptos nuevos. Como veréis, se trata de una aplicación con una única actividad, compuesta por un contador y un botón que incrementa dicho contador cuando se hace clic en él. Veamos cada una de las partes. El Layout del contador El diseño de la actividad consta ahora de una vista de tipo TextView y de un botón (Button): En estas vistas hemos incluido un atributo identificador, android:id, para poder referirnos a las vistas dentro del código. Cuando definimos los atributos con @+id indicamos que estamos incorporando un nuevo identifi- cador a los recursos de la aplicación. La clase MainActivity El comportamiento de la aplicación se define en la clase principal MainActivity, donde se trata la interacción con el usuario igual que con cualquier interfaz gráfica: asociando una acción a un evento en la interfaz. En primer lugar, en la clase se define una propiedad contador inicializada a 0: class MainActivity : AppCompatActivity() { var contador=0... Y se añade el código siguiente dentro del método onCreate: // Referencia al TextView val textViewContador=findViewById(R.id.textViewContador) // Inicializamos el TextView con el contador a 0 textViewContador.setText(contador.toString()) // Referencia al botón val btAdd=findViewById(R.id.btAdd) // Asociaciamos una expresióin lambda como // respuesta (callback) al evento Clic sobre // el botón btAdd.setOnClickListener { contador++ textViewContador.setText(contador.toString()) } Propiedad de McGraw-Hill®. Prohibida la reproducción total o parcial sin el permiso adecuado. Uso exclusivo para el contenido de los cursos FPActiva® de McGraw-Hill. Prohibida la reproducción total o parcial sin el permiso adecuado. Uso exclusivo para el contenido de los cursos FPActiva® de McGraw-Hill. 1 UNIDAD El método findViewById Este método pertenece a la actividad y devuelve la vista correspondiente al identificador que se le proporcio- na como argumento. Estos identificadores, que definimos mediante @+id en el Layout, se encuentran en la clase R. El método devuelve un tipo genérico, por lo que debe indicarse el tipo de vista de que se trata ( o ). De todos modos, si declaramos un tipo para la variable que guardará la referencia, no es necesario indicar el tipo genérico. Por ejemplo: val btAdd:Button=findViewById(R.id.btAdd) Con este método se han obtenido el TextView del contador y el botón. Una vez tenemos las referencias a los objetos de la interfaz, podemos utilizar sus propiedades y métodos, así como asignarles controladores de eventos. Por ejemplo, para establecer el texto del TextView del contador usamos el método setText: textViewContador.setText(contador.toString()) IMPORTANT5 mediante las bibliotecas de vinculación de datos (Data Binding) que veremos en la unidad siguiente, en detrimento del método findViewById. Controladores de eventos Los controladores de eventos se utilizan para indicar las acciones a realizar cuando se produce un evento sobre una vista o un elemento de la interfaz. En el ejemplo hemos capturado el evento Clic sobre el botón btAdd y establecido un controlador de eventos mediante el método setOnClickListener, proporcionándole una expresión lambda con las acciones a ejecutar: btAdd.setOnClickListener({ contador++ textViewContador.setText(contador.toString()) }) En este caso, se ha incrementado el contador y se ha actualizado la vista. Además, dado que únicamente pasamos esta lambda como argumento, podemos eliminar los paréntesis para que este controlador quede del modo siguiente: btAdd.setOnClickListener { contador++ textViewContador.setText(contador.toString()) } 5.2. 5f cicfo de vida de fas actividades Las actividades y la forma en que estas se inician y relacionan son parte fundamental del modelo de aplica- ción de Android. Una aplicación Android puede componerse de varias actividades, y, a pesar de que estas trabajan conjunta- mente para dar una experiencia de usuario coherente, en realidad tienen poca relación entre ellas, lo que facilita la invocación de actividades entre diferentes aplicaciones. Las actividades, a lo largo de su vida útil, pasan por diferentes estados. El usuario de la aplicación puede abrirla, cerrarla, abrir otra aplicación... En estas transiciones entre estados se disparan ciertos eventos, que podemos capturar y gestionar mediante funciones de callback. Propiedad de McGraw-Hill®. Prohibida la reproducción total o parcial sin el permiso adecuado. Uso exclusivo para el contenido de los cursos FPActiva® de McGraw-Hill. Prohibida la reproducción total o parcial sin el permiso adecuado. Uso exclusivo para el contenido de los cursos FPActiva® de McGraw-Hill. 1 UNIDAD De forma simplificada, podemos representar este proceso del modo siguiente: onStart() onRestart() retoma la Otra actividad vuelve al primer plano actividad Otra aplicación más prioritaria requiere memoria La actividad deja el primer plano actividad La actividad finaliza o es eliminada por el sistema Fuente: Android Open Source Project, imagen utilizada conforme a los términos de la licencia Creative Commons 2.5. Attribution: https://developer.android.com/guide/components/activities/activity-lifecycle Los callbacks que podemos implementar en la clase Activity para capturar estos eventos del ciclo de vida son los siguientes: onCreate(): Se activa en la creación de la actividad y se usa para inicializar sus componentes, enlazar las vistas o vincular los datos. En este método es donde generalmente utilizamos setContentView() para establecer el layout de la interfaz. onStart(): Se activa después del callback onCreate(), cuando ya se ha iniciado la actividad y esta pasa a primer plano, volviéndose visible para el usuario. onResume(): Se invoca inmediatamente después de OnStart() o cuando la actividad estaba pausada y vuelve al primer plano, permitiendo, de nuevo, su interacción con el usuario. onPause(): Se invoca cuando la actividad pierde el foco y pasa al estado de pausada (por ejemplo, se ha pulsado el botón Atrás o Recientes). Cuando el sistema invoca onPause(), la actividad todavía es parcialmente visible. Las actividades pausadas pueden continuar actualizando la interfaz si el usuario espera que esto pase (como, por ejemplo, actualizar un mapa de navegación). Este callback no se ha de utilizar para guardar datos ni de la aplicación ni del usuario, hacer llamadas de red o realizar tran- sacciones sobre bases de datos. onStop(): Se invoca cuando la actividad ya no es visible para el usuario, bien porque se esté eliminando esta, bien porque se inicie una actividad nueva, bien porque se reanude otra que la cubra. Propiedad de McGraw-Hill®. Prohibida la reproducción total o parcial sin el permiso adecuado. Uso exclusivo para el contenido de los cursos FPActiva® de McGraw-Hill. Prohibida la reproducción total o parcial sin el permiso adecuado. Uso exclusivo para el contenido de los cursos FPActiva® de McGraw-Hill. 1 UNIDAD onRestart(): Se invoca cuando una actividad que estaba detenida pasa de nuevo a estar en primer plano. Este callback restaura el estado de la actividad en el momento en que esta se detuvo. Después de este callback se invoca siempre onStart(). onDestroy(): Se invoca antes de que se elimine la actividad, y se usa para garantizar que sus recursos se liberan con ella y el proceso que la contiene se elimine. Conocer este ciclo de vida e implementar correctamente los diferentes callbacks es de vital importancia para garantizar que el comportamiento de las actividades sea el que se espera y evitar que: La aplicación se interrumpa abruptamente cuando el usuario recibe una llamada telefónica o cambia de aplicación. Se consuman muchos recursos del sistema cuando no se están utilizando. Se pierda el estado de la aplicación cuando el usuario sale de la actividad y vuelve después, o cuando la pantalla cambia de orientación. MANT5NI5NDO 5t 5STADO D5 tAS ACTIVIDAD5S Además de parar la actividad, algunas acciones del usuario provocan que esta se destruya, finalizando su ciclo de vida y forzando que se tenga que volver a crear al volver a ella. Casos como hacer tap en el botón de atrás o cambios de orientación provocan esta reacción y, con ella, una pérdida en el estado de la actividad. Para mantener este estado utilizamos los callback onSaveInstanceState y onRestoreInstanceState, heredados de Activity y que se invocan antes de destruir la actividad y antes de devolverla al primer plano, respectivamente. Guardaudo ef estado Restauraudo ef estado onStart() onSaveInstanceState() onRestoreInstanceState() Para guardar el estado se utiliza un objeto de tipo Bundle que almacena pares clave-valor. Este tipo Bundle se corresponde también con el que se utiliza en el argumento savedInstanceState para inicializar la actividad en el método onCreate. De hecho, también podríamos restaurar el estado en el método onCreate, aunque es más apropiado hacerlo en el método onRestoreInstanceState. Los objetos de tipo Bundle admiten varios métodos para almacenar y extraer según el tipo de datos que va- yamos a utilizar, como putInt/getInt, putString/getString, etcétera. Por ejemplo, para guardar un valor entero al cerrar la actividad y restaurarlo al volver a activarla, podemos utilizar el código siguiente: override fun onSaveInstanceState(estado: Bundle) { super.onSaveInstanceState(estado) // Código para guardar el estado estado.putInt(“CLAVE”, valor) }

Use Quizgecko on...
Browser
Browser