El uso generalizado en los últimos tiempos de dispositivos móviles como smartPhone o tablets ha dado lugar a una gran demanda de software para este nuevo tipo de hardware. Es por esta razón por la que Ada, socia fundadora de la empresa BK Programación y con cierta experiencia en el desarrollo de aplicaciones para dispositivos móviles, ha decidido que su compañía entre también en este nuevo mercado. Se trata de una oportunidad interesante para abrir nuevos negocios tanto para sus clientes actuales como para la captación de otros nuevos.
Hasta este momento la única persona de la empresa que ha trabajado antes con este tipo de tecnologías es la propia Ada, de manera que va a ser ella quién se encargará de formar a María y a Juan en estas nuevas tecnologías. En concreto Ada ha desarrollado aplicaciones para Android utilizando lenguajes como Java y XML.
Teléfono inteligente capaz de almacenar datos y realizar tareas semejantes a un mini-ordenador
Dispositivo móvil con un diseño plano, fino y compacto que tiene algunas prestaciones muy similares a las de un ordenador
Creado con eXeLearning (Ventana nueva)
Ocultar
El gran avance tecnológico de los últimos años en la telefonía móvil unido a la evolución que ha tenido Internet, ha supuesto un gran cambio en el uso que hacemos de los nuevos terminales. Tanto los nuevos dispositivos móviles o smartphones como las tabletas o tablets, están revolucionando el mercado de las telecomunicaciones. Podríamos hablar de los nuevos ordenadores del futuro. Con la aparición de estos dispositivos, han aparecido diferentes plataformas para desarrollar aplicaciones.
Entre estas plataformas se encuentra Android, que apareció a finales de 2008 cuando Google lanzó su primer dispositivo móvil con este sistema operativo. Y desde ahí hasta la actualidad ha incrementado de forma espectacular su cuota de mercado como veremos a lo largo de la unidad.
También veremos qué necesitamos para poder desarrollar una aplicación en Android y desarrollaremos una primera aplicación muy sencilla que podremos probar tanto en un emulador como en nuestro propio dispositivo móvil.
Vamos a comenzar con el estudio de los dispositivos móviles, viendo una clasificación de los mismos y pasaremos a identificar las principales plataformas que existen actualmente para decantarnos finalmente por Android debido a su gran éxito como ya hemos mencionado.
Creado con eXeLearning (Ventana nueva)
Ocultar
La primera pregunta que podemos hacernos es: ¿qué entendemos por “móvil”?
Si se nos ocurre investigar sobre ese término, a través de algún buscador de Internet, podremos observar que no hay una respuesta única y que en algunas ocasiones las diferencias pueden ser sustanciales en función de qué es lo que consideremos “móvil”. Obviamente esto da lugar a su vez a muchas otras preguntas como por ejemplo:
Es móvil… ¿alguna parte del dispositivo? ¿El dispositivo completo? ¿La aplicación que usamos en el dispositivo? ¿Una aplicación cliente? ¿Una aplicación servidor? ¿El usuario del dispositivo? ¿Es “móvil” sinónimo de “portátil”? ¿Es “móvil” sinónimo de “limitado”? ¿Hasta qué punto “móvil” es sinónimo de “autónomo”? ¿Existen diversos grados de “movilidad”? ¿Se pueden clasificar los dispositivos móviles en distintos tipos? ¿Bajo qué criterios?
Y así sucesivamente podríamos plantearnos más y más preguntas… Para evitar este tipo de controversias, en nuestro caso vamos a intentar dar una definición con la que trabajaremos a lo largo del desarrollo del módulo:
Ocultar
¿Qué es un dispositivo móvil?
Se trata de un aparato de pequeño tamaño y de poco peso, con pantalla y teclado (puede ser táctil), con pequeñas capacidades de procesamiento, memoria limitada y conexión (permanente o no) a una red. Este tipo de dispositivos están diseñados para cumplir algún tipo de función específica, como realizar llamadas telefónicas, servir como agendas, jugar, navegación GPS, escuchar música, acceso al correo electrónico, navegar por Internet, etc., aunque normalmente pueden llevar a cabo también funciones más generales.
Ocultar
Estos aparatos son cada vez más populares especialmente para aquellos entornos en los que llevar consigo un ordenador convencional (incluso un portátil) no es práctico.
Para obtener más información acerca de cuáles pueden ser las características de un dispositivo móvil puedes consultar el siguiente artículo en la Wikipedia sobre dispositivos móviles:
Acceder a Dispositivo Móvil
Creado con eXeLearning (Ventana nueva)
Ocultar
¿Qué tipos de dispositivos móviles existen?
Entre los dispositivos móviles más habituales se encuentran:
-
SmartPhones: Teléfono inteligente con funciones avanzadas y conexión a internet.
-
PDA o PocketPC: Dispositivos portátiles para gestión de información personal. Ambos ya están en desuso.
-
Tablet: Dispositivo táctil portátil para navegación y multimedia, con pantalla grande.
-
Phablet: Dispositivo intermedio entre smartphone y tablet, con pantalla grande.
-
Wearable: Tecnología que se lleva puesta en el cuerpo para monitorear salud y actividades.
-
Gafas inteligentes: Lentes con tecnología que muestran información al usuario.
-
Dispositivos de realidad virtual (VR): Cascos que sumergen al usuario en entornos virtuales.
-
E-readers: Dispositivos específicos para la lectura de libros digitales.
Según las fuentes que consultes puedes encontrar diversas clasificaciones donde se incluyan unos u otros tipos de dispositivos; en nuestro caso, los principales aparatos a los que nos referiremos al hablar de dispositivos móviles debido a su gran uso, serán los smartphones y las tablets. Por otro lado, según la tecnología vaya avanzando, te podrás ir encontrando con nuevos tipos de productos y servicios que irán ampliando las posibilidades de elección. Como siempre sucede en el mundo de la tecnología, habrá que estar continuamente al día de los nuevos avances que van apareciendo para no quedarse atrás.
Siglas en inglés de Asistente Personal Digital. Computadora de mano que funciona como una agenda electrónica.
Ordenador de bolsillo con capacidades similares a los PC
La tecnología avanza con tal rapidez que lo que hoy consideramos innovador, mañana puede quedar obsoleto.
Mark Zuckerberg
Esta cita resalta cómo los avances tecnológicos ocurren a un ritmo vertiginoso, lo que hace que incluso los dispositivos y herramientas que en su momento fueron considerados innovadores rápidamente se vean desplazados por nuevas tecnologías. Es un recordatorio de cómo, en el mundo digital, la innovación constante puede hacer que lo que es novedoso hoy quede atrás en un futuro cercano.
Creado con eXeLearning (Ventana nueva)
Ocultar
Antes de comenzar a desarrollar software para alguno de estos dispositivos, es necesario ser conscientes de las limitaciones con las que nos podemos encontrar en estos aparatos. ¿Cuáles son las restricciones a las que nos vamos a tener que enfrentar?
Hasta hace poco nos encontrábamos con algunas de las siguientes restricciones.
- Suministro de energía limitado (normalmente dependiente de baterías).
- Procesadores con capacidad de cómputo reducida. Suelen tener una baja frecuencia de reloj por la necesidad de ahorrar energía. En algunos casos, por ejemplo, podrían no disponer de la capacidad de cálculos en punto flotante.
- Poca memoria principal (RAM).
- Almacenamiento de datos persistente reducido (pequeña memoria flash interna, tarjetas SD, etc.)
- Conexión a algún tipo de red intermitente y con ancho de banda limitado.
- Pantallas de reducidas dimensiones.
- Teclados con funcionalidad muy básica y muy pequeños.
Este tipo de restricciones, y algunas otras que dependían de cada dispositivo en concreto, habrán de ser tenidas muy en cuenta a la hora del análisis y diseño de una aplicación “móvil”, pues no podemos pretender que esa aplicación pueda contener la misma funcionalidad que la que podemos encontrar habitualmente en un programa que es ejecutado en un ordenador de sobremesa o un portátil. Debido a la evolución muchas de ellas han desaparecido, como la limitación en RAM o Procesador, y el tamaño de la pantalla de manera parcial. Sin embargo hablamos de dispositivos de gama alta, teniendo en cuenta que muchos usuarios solo disponen de dispositivos de gama media o baja.
Por otro lado, no todo van a ser restricciones. También habrá que tener en consideración que esta tecnología va a aportar una serie de ventajas muy importantes:
- Movilidad.
- Poco peso.
- Pequeño tamaño.
- Facilidad para el transporte.
- Conectividad a diversos tipos de redes de comunicaciones (3G, 4G, 4G+, mensajería SMS y MMS, voz, Internet, Bluetooth, infrarrojos, radiofrecuencia, etc.).
Estas serán las ventajas que podrás explotar en tus aplicaciones.
A través del siguiente vídeo puedes aprender más sobre limitaciones de los dispositivos móviles, cada vez más cubiertas por funcionalidades mejoradas.
Creado con eXeLearning (Ventana nueva)
María y Juan ya tienen claro que programar para un dispositivo móvil no va a ser exactamente lo mismo que programar para un ordenador convencional, debido a las limitaciones y características especiales que aquellos aparatos pueden presentar. Tienen ahora que empezar a descubrir y conocer con qué tipos de tecnologías se pueden encontrar en este nuevo mundo, tanto a nivel de hardware (dispositivos sobre los que se realizarán las aplicaciones) como a nivel de software (sistemas operativos que funcionan sobre esos dispositivos, plataformas de desarrollo disponibles, entornos API, lenguajes de programación, etc.)
Ada, la responsable de María y Juan en la compañía, va a realizar un pequeño estudio de algunas de las tecnologías que más se están utilizando hoy día. Este estudio será muy importante para el conocimiento que la empresa BK Programación quiere ir acumulando para proporcionar valor añadido a los productos y servicios que desea ofrecer a sus clientes. Ada aprovechará el desarrollo de este estudio para ir mostrando a Juan y a María las diversas tecnologías con las que se van a poder encontrar.
Es importante que este tipo de análisis y estudios se sigan realizando de manera continua en la empresa al menos una vez al año, pues se trata de un mundo que avanza muy deprisa y en el que es muy fácil quedarse desfasado. Hay que estar siempre al día de los últimos productos que salen al mercado así como de los sistemas operativos, las aplicaciones, los entornos de desarrollo, nuevos lenguajes, etc.
Ocultar
Cuando vas a desarrollar una aplicación para un dispositivo móvil, algunas de las primeras preguntas que te puedes hacer son:
- ¿Sobre qué tipos de dispositivos móviles se pueden hacer programas?
- ¿Sobre qué tipo de hardware se puede programar?
- ¿Qué sistema operativo puede llevar ese hardware?
- ¿Qué plataformas de desarrollo existen para desarrollar sobre ese hardware y ese sistema operativo?
- ¿Con qué lenguajes puedo programar? ¿Qué herramientas (compiladores, bibliotecas, entornos, etc.) hay disponibles?
Las respuestas a este tipo de preguntas pueden ser múltiples y muy variadas:
- Hardware: puedes encontrar teléfonos móviles (smartphones), tabletas (tablets) y otros dispositivos. Entre los principales fabricantes de smartphones se encuentran Samsung (uno de los mayores proveedores desde 2019), Apple, Xiaomi, Huawei, y otros como Oppo y Vivo, cuyo ranking de ventas puede variar por trimestre. Un dato interesante es que el mercado de los smartphones sigue siendo predominantemente asiático. En cuanto a las tablets, las ventas son más variables y dependen de los modelos disponibles en el mercado. Apple (iPad) sigue dominando el mercado de tablets, seguido de Samsung (Galaxy Tab y Note) y otros como Huawei y Amazon.
- Sistemas operativos (SO): dependiendo del hardware, habrá sistemas diseñados para unos u otros dispositivos. Entre los más populares se encuentran Android, iOS y iPadOS. También hay sistemas basados en Linux y variantes de Microsoft Windows, aunque Windows Phone ha dejado de ser relevante en el mercado.
- Plataformas de desarrollo: Android Studio, que es la plataforma principal para el desarrollo de aplicaciones Android. Además, existen diversos entornos de desarrollo como Microsoft Visual Studio, Eclipse, y NetBeans.
- Lenguajes de programación: Se recomienda Kotlin para el desarrollo de aplicaciones Android, aunque Java sigue siendo aceptado. Para aplicaciones híbridas, se utilizan JavaScript con Ionic y Dart con Flutter, permitiendo la creación de aplicaciones multiplataforma.
En definitiva, puedes observar que en este nuevo mundo del desarrollo para dispositivos móviles te encuentras con una problemática similar a la que te puedes enfrentar con los ordenadores convencionales: distintos tipos de hardware, distintas opciones de sistemas operativos dependiendo del hardware que los soporte, diferentes lenguajes de programación, plataformas, API y bibliotecas, entornos de desarrollo, etc.
Creado con eXeLearning (Ventana nueva)
El primer acercamiento que Ada va a realizar con María y Juan al mundo de la tecnología de los dispositivos móviles será en lo que respecta al hardware, es decir, los componentes físicos de los dispositivos.
En este punto, María y Juan se plantean una serie de preguntas, como: ¿qué tipos de dispositivos existen y qué características tienen?, ¿cómo son por dentro y por fuera?, ¿usan microprocesadores similares a los de los ordenadores?, ¿son todos similares?, ¿existen modelos para usos específicos?, ¿qué marcas y modelos hay?, y ¿cuáles son los más vendidos?
Ada, como experta en tecnología móvil, se encargará de responder algunas de estas preguntas para aclarar sus inquietudes.
Ocultar
Todos hemos tenido que decidir qué móvil comprar, basándonos en sus características, que determinan si un dispositivo es de gama alta, media o baja.
En 2025, para que un teléfono sea de gama media, debe tener:
- Pantalla FullHD o superior (1080p, 1200p).
- Procesador potente (como Snapdragon 700, MediaTek Dimensity 800 o similar).
- Sistema de cámaras versátil, con cámara frontal y al menos dos cámaras traseras, con características como modo nocturno o gran angular.
- Batería de al menos 4.000 mAh con carga rápida (18 W o superior).
- Diseño premium, con pantallas plegables, sin bordes, con perforaciones y/o con bordes curvos.
- Almacenamiento de 128 GB o superior y la opción de expansión con microSD, ya que las aplicaciones y multimedia ocupan mucho espacio.
- Características de seguridad avanzadas, como reconocimiento facial o sensor de huella digital, que permiten un desbloqueo rápido y realizar acciones avanzadas.
Cuando desarrollamos, siempre debemos tener en cuenta las características de los móviles del perfil al que va destinada nuestra aplicación móvil. Por ejemplo, si la aplicación utiliza seguridad biométrica (como huella digital o reconocimiento facial), debemos asegurarnos de que el dispositivo cuente con el sensor adecuado y soporte en el sistema operativo. Si no es así, tendremos que ofrecer métodos alternativos de seguridad, como PIN o patrones.
Los dispositivos de gama media siguen mejorando, acercándose a los de gama alta, pero con algunas limitaciones de hardware. Como desarrolladores, debemos optimizar nuestras aplicaciones para abarcar el mayor público posible, sin perder de vista al perfil específico que queremos atraer. Esto significa ajustar el rendimiento, la memoria y la compatibilidad con diferentes pantallas y cámaras, garantizando que la experiencia del usuario sea fluida, sin importar el dispositivo. Sin embargo, siempre debemos priorizar la experiencia para el público objetivo de nuestra aplicación móvil, adaptando nuestras soluciones a sus necesidades.
¿Es importante el hardware?
Queremos desarrollar una aplicación móvil de fitness para hacer seguimiento de actividades como correr. Si está dirigida a atletas profesionales, se necesita un GPS de alta precisión y sensores avanzados como el de frecuencia cardíaca, que solo están disponibles en dispositivos de gama alta. Además, el procesador potente es esencial para manejar datos en tiempo real.
Sin embargo, si la aplicación móvil también busca llegar a un público más amplio, como usuarios casuales con móviles de gama media o baja, se deben ofrecer funciones más básicas. Por ejemplo, en lugar de un GPS (Sistema de Posicionamiento Global) ultra preciso, podría usarse una ubicación aproximada o un seguimiento de pasos simple, optimizando la aplicación móvil para que funcione bien en dispositivos con menos potencia y sensores limitados. Así, la aplicación móvil se adapta a diferentes tipos de público, manteniendo una buena experiencia para todos.
Creado con eXeLearning (Ventana nueva)
Una vez que Ada ha mostrado algunas de las peculiaridades del hardware de los dispositivos móviles a María y Juan, es necesario pasar al siguiente nivel: el software, y en concreto el nivel más bajo, es decir, el Sistema Operativo (SO).
Nuevamente, surgen los interrogantes entre María y Juan: ¿también tienen sistema operativo como los ordenadores?, ¿hay más de un sistema operativo disponible?, ¿hay sistemas “libres” y “propietarios” como en los PC?, ¿quién desarrolla esos sistemas?, ¿con qué herramientas se puede programar para ellos?, ¿funcionan todos los sistemas sobre todos los tipos de hardware?
Ada, como experta, va a intentar responder estas preguntas en esta ocasión.
Ocultar
Los sistemas operativos más habituales que te puedes encontrar en un dispositivo móvil son:
-
Android. Desarrollado por Android Inc. y adquirido por Google en 2005, está basado en el núcleo de Linux. Actualmente, está en la mayoría de los dispositivos del mercado bajo versiones fragmentadas, siendo las más recientes Android 12, 13 y 14. Este sistema operativo es de código abierto, lo que permite que fabricantes de diferentes dispositivos lo personalicen según sus necesidades.
-
iOS. Desarrollado por Apple para el iPhone y utilizado también para el iPod Touch y el iPad. iOS es conocido por su estabilidad, actualizaciones frecuentes y su ecosistema cerrado que asegura una experiencia de usuario consistente.
-
HarmonyOS. Desarrollado por Huawei, emergiendo como una opción en el mercado. Aunque es relativamente nuevo, se espera que HarmonyOS crezca y se convierta en un competidor fuerte a medida que Huawei lo implemente en más dispositivos.
-
KaiOS. Sistema operativo que ha ganado popularidad en teléfonos de bajo costo. KaiOS ofrece funciones esenciales de smartphone como aplicaciones populares, pero con un sistema operativo ligero que permite su funcionamiento en dispositivos con hardware limitado.
A medida que los dispositivos móviles crecen en popularidad, los sistemas operativos adquieren mayor importancia. Android sigue siendo el sistema operativo para teléfonos inteligentes más popular, seguido de iOS. Estos dos sistemas dominan el mercado, pero otros como HarmonyOS y KaiOS también tienen un papel importante en mercados específicos.
Conocer el software es esencial antes de desarrollar una app, ya que cada SO tiene sus propias características y requisitos. Comprender estas diferencias ayuda a crear una app optimizada y adaptada a las necesidades del público objetivo.
Por ejemplo, al desarrollar una aplicación móvil, iOS y Android ofrecen diferentes ventajas. iOS tiene una gama más estandarizada de dispositivos, lo que facilita la optimización, pero requiere usar un Mac y Xcode, lo que puede limitar a algunos desarrolladores.
Por otro lado, Android es más flexible, ya que se adapta a una gran variedad de dispositivos y hardware, pero esto implica que haya más variación y fragmentación, lo que puede hacer más difícil garantizar la misma experiencia en todos los modelos.
En conclusión, la plataforma a elegir depende del público objetivo. Si queremos optimizar para una gama más controlada, iOS es ideal; si buscamos llegar a un público más amplio, Android es más versátil. También existen opciones como los lenguajes híbridos (por ejemplo, Flutter o React Native) que permiten desarrollar para ambas plataformas a la vez.
Creado con eXeLearning (Ventana nueva)
Ocultar
Montaje de Elaboración propia
(fuentes citadas en Anexo).
¿Qué necesitamos para poder programar dispositivos móviles?
Para desarrollar aplicaciones para los sistemas operativos móviles actuales, es necesario contar con plataformas de desarrollo que permitan generar código ejecutable sobre esos sistemas, ya sea en una máquina virtual o utilizando un intérprete que esté instalado en el dispositivo y soportado por el sistema operativo.
Entre las plataformas de desarrollo más populares se encuentran:
-
Android: Android Studio es el IDE oficial y más utilizado. Se puede programar principalmente en Kotlin, aunque Java sigue siendo soportado. También es posible utilizar C o C++ mediante el NDK, que permite generar código nativo.
- iOS: XCode es el IDE oficial que puede descargarse gratuitamente, pero para comercializar aplicaciones en la App Store es necesario registrarse en el programa de desarrollo de Apple, lo cual conlleva una tarifa. El lenguaje de programación principal es Swift, aunque Objective-C todavía es compatible.
Además del desarrollo nativo, hoy en día es común utilizar soluciones híbridas, que permiten crear aplicaciones para múltiples plataformas (iOS y Android) desde un mismo código base. Tecnologías como Flutter (lenguaje Dart), React Native (lenguaje JavaScript/TypeScript) o Ionic (lenguaje JavaScript/HTTP/CSS) facilitan el desarrollo de aplicaciones móviles sin necesidad de escribir código específico para cada sistema operativo. Estas soluciones suelen ofrecer un equilibrio entre rendimiento y facilidad de desarrollo, haciendo que sean una opción atractiva para muchas empresas y desarrolladores.
Creado con eXeLearning (Ventana nueva)
María y Juan saben programar en Java, ya que lo aprendieron en el módulo de Programación. Sin embargo, en la actualidad, Kotlin ha ganado gran popularidad y es el lenguaje oficialmente recomendado por Google para el desarrollo de aplicaciones Android. Por esta razón, Ada quiere que amplíen sus conocimientos y se familiaricen con ambos lenguajes.
Es importante conocer tanto Java como Kotlin para tener un mayor poder de adaptación a cualquier proyecto y poder afrontar con éxito una amplia variedad de desafíos en el desarrollo de aplicaciones. Es por eso que Ada les anima a dominar ambos lenguajes, para que puedan elegir el más adecuado según las necesidades técnicas de cada proyecto.
Ocultar
Kotlin y Java son dos lenguajes importantes en el desarrollo de aplicaciones Android, pero actualmente Kotlin está tomando la delantera. Es el lenguaje oficialmente recomendado por Google y, al contener características de lenguajes más modernos, está ganando terreno rápidamente. Aunque Java sigue siendo ampliamente usado y es compatible con Kotlin, el soporte a largo plazo para Java en Android podría ir disminuyendo con el tiempo, ya que Google se está enfocando más en Kotlin.
Java sigue siendo relevante debido a su madurez y base de recursos, pero con el tiempo, Kotlin se está posicionando como el futuro del desarrollo en Android. Es importante seguir formándose en ambos lenguajes, ya que esto proporcionará la flexibilidad necesaria para adaptarse a proyectos existentes y a las nuevas tecnologías que continúan evolucionando.
Kotlin es una excelente elección para el desarrollo de aplicaciones Android, ya que es el lenguaje recomendado por Google. Permite aprovechar el conocimiento en Java
y ofrece características modernas como nullabilidad y funciones de extensión.
En cuanto a la plataforma, se optará por Android, dada la gran cuota de mercado que ha alcanzado, lo que permitirá instalar las aplicaciones en una amplia variedad de dispositivos. Además, Google ofrece todas las herramientas necesarias de forma gratuita, lo que facilita el desarrollo.
La competitividad en este sector exige estar siempre atento a los nuevos cambios y necesidades, y es fundamental seguir formándose en los entornos más demandados, sin olvidar aquellos que podrían surgir en el futuro.
La nullabilidad se refiere a la capacidad de una variable de poder tener un valor nulo. A diferencia de Java, Kotlin maneja esto de manera más estricta, ayudando a prevenir errores relacionados con valores nulos en tiempo de ejecución.
Las funciones de extensión permiten agregar nuevas funcionalidades a clases existentes sin tener que modificarlas directamente. Esto permite, por ejemplo, añadir métodos a clases de la biblioteca estándar o clases de terceros de forma sencilla y sin necesidad de heredar de ellas.
Creado con eXeLearning (Ventana nueva)
Ocultar
Android fue desarrollado por Android Inc. y adquirido por Google en 2005. Desde entonces, ha evolucionado hasta convertirse en uno de los sistemas operativos más utilizados en el mundo.
En 2007, se creó la Open Handset Alliance para promover Android, y en 2008, se lanzó el primer Android SDK y el primer dispositivo con este sistema operativo. Su código fuente, liberado bajo la licencia Apache, ha permitido que desarrolladores de todo el mundo contribuyan a su crecimiento, creando un ecosistema de aplicaciones disponibles en la Google Play Store.
Para mejorar el rendimiento y la eficiencia energética, Android reemplazó Dalvik VM por Android Runtime (ART). Además, desde Android 10, se dejó de usar nombres de postres en sus versiones, optando por un sistema de numeración más claro y profesional.
El desarrollo de aplicaciones Android se ha expandido a múltiples dispositivos, incluyendo smartphones, tablets, wearables e IoT. Herramientas como Android Studio, junto con el uso de Kotlin (lenguaje oficial recomendado por Google), han facilitado la creación de aplicaciones modernas y eficientes.
La comunidad de desarrolladores sigue creciendo, con recursos como Jetpack, que agiliza el desarrollo. Además, tecnologías emergentes como la inteligencia artificial y el aprendizaje automático están revolucionando la experiencia de usuario.
Es esencial que los desarrolladores elijan la versión adecuada de Android y se mantengan actualizados, ya que el soporte para versiones antiguas está disminuyendo, lo que puede afectar la seguridad y funcionalidad de las aplicaciones. Adaptarse a las tendencias y mejores prácticas es clave para el éxito en el desarrollo móvil.
Ocultar
Android se actualiza con frecuencia, por lo que es recomendable desarrollar nuestras aplicaciones para que sean compatibles con la mayor cantidad de dispositivos posible. Para lograrlo, es útil conocer qué versiones de Android son las más utilizadas en los dispositivos móviles en el momento de desarrollar el proyecto.
Creado con eXeLearning (Ventana nueva)
Una vez que Ada ha decido que en la empresa BK Programación se comience a trabajar en el entorno Android con el lenguaje escogido, lo primero que María y Juan tienen que hacer es empezar a analizar cómo es este nuevo entorno. Dado que ambos ya tienen ciertos conocimientos de programación en lenguaje Java, las preguntas que se hacen ahora son del tipo:
- ¿Qué dificultad añadirá la utilización del nuevo lenguaje Kotlin?
- ¿Qué tipo de API tendrán disponibles? ¿Habrá conceptos nuevos?
- ¿Qué máquina virtual se utiliza?
- ¿Qué características mínimas deben cumplir los dispositivos para poder ejecutar aplicaciones desarrolladas bajo este entorno?
- ¿Con qué herramientas de desarrollo vamos a trabajar?
Ada intentará resolver algunas de estas dudas.
Ocultar
Android está compuesto por varias capas que trabajan en conjunto para ofrecer un sistema operativo eficiente y seguro. Aquí, vamos a centrarnos en las más importantes, que son las siguientes:
Es la máquina virtual que ejecuta las aplicaciones en Android, optimizando su rendimiento y consumo de recursos.
Es el núcleo del sistema operativo que gestiona la comunicación entre el hardware y el software.
Es una versión modular del kernel de Android que facilita las actualizaciones y compatibilidad entre dispositivos.
WebView es un componente que permite mostrar páginas web dentro de las aplicaciones, y está basado en el motor de navegación Chromium.
Son técnicas de compilación que convierten el código de una app en instrucciones ejecutables antes (AOT) o durante (JIT) su uso para mejorar el rendimiento.
Es una medida de seguridad que impide que las aplicaciones accedan a datos de otras apps sin permiso.
Creado con eXeLearning (Ventana nueva)
Ocultar
¿Qué nos permite hacer un dispositivo móvil con Android?
Los dispositivos Android ofrecen una gran variedad de funcionalidades, desde la comunicación básica (llamadas, mensajería) hasta la interacción con el entorno mediante sensores y la gestión de datos. En este módulo, exploraremos las funcionalidades fundamentales de Android.
Algunas de las funciones clave que aprenderemos incluyen:
-
Creación de aplicaciones interactivas con interfaces de usuario diseñadas mediante XML o Jetpack Compose.
-
Gestión de datos, utilizando tecnologías como SQLite, Room, SharedPreferences/DataStore, almacenamiento de ficheros y bases de datos en la nube para guardar y manejar datos.
-
Procesamiento y reproducción de objetos multimedia como imágenes, animaciones, transiciones, audios y videos dentro de las aplicaciones.
Otras funcionalidades clave incluyen:
-
Mensajería: Envío y recepción de SMS y mensajes multimedia (aunque los MMS están siendo reemplazados por RCS y aplicaciones de mensajería como WhatsApp o Telegram).
-
Notificaciones push: Uso de Firebase Cloud Messaging (FCS) para recibir notificaciones en segundo plano.
-
Ejecución en segundo plano: Implementación de tareas programadas y procesos persistentes con WorkManager.
-
Uso de sensores: Acceso a sensores del dispositivo como GPS, acelerómetro o giroscopio.
-
Conexión de red: Uso de Wi-Fi y Bluetooth para la comunicación entre dispositivos.
-
Conexiones HTTP/HTTPS: Realización de peticiones web seguras con bibliotecas como Retrofit o Volley.
Este módulo tiene como objetivo ofrecerte una base sólida sobre las funcionalidades esenciales de Android. Al finalizar, podrás crear aplicaciones simples y funcionales, integrando interfaces, datos y multimedia de forma eficiente.
Mensajes enviados desde un servidor a un dispositivo móvil para alertar al usuario sobre eventos o actualizaciones.
Sensor que mide la orientación o la rotación del dispositivo en el espacio.
Sensor que mide la aceleración en las tres direcciones espaciales, útil para detectar movimientos.
Creado con eXeLearning (Ventana nueva)
Después de repasar la arquitectura general de Android, María y Juan se dan cuenta de que necesitan saber qué debe estar instalado en el ordenador para comenzar a desarrollar. Así que deciden buscar información sobre todo lo necesario para empezar a programar en Android.
- ¿Qué debemos instalar?
- ¿Qué habrá que configurar?
Ocultar
Como ya se mencionó anteriormente, Java sigue siendo un lenguaje válido para el desarrollo en Android y todavía se utiliza en muchos proyectos. Sin embargo, Kotlin es ahora el lenguaje oficial recomendado por Google para el desarrollo de aplicaciones Android. Aunque en este módulo se trabajarán ambos lenguajes, es importante destacar que Kotlin es más moderno y ofrece ventajas significativas en cuanto a simplicidad y optimización. Este lenguaje será clave en los proyectos futuros, ya que Android lo está promoviendo activamente.
El entorno de desarrollo que utilizaremos será Android Studio, el IDE oficial para el desarrollo de aplicaciones Android. Android Studio ofrece un conjunto completo de herramientas diseñadas específicamente para facilitar el desarrollo de aplicaciones en esta plataforma. Incluye:
- Editor de código inteligente: Ofrece autocompletado, sugerencias de código y refactorización de código, lo que facilita la escritura de código limpio y eficiente.
- Diseñador de interfaces de usuario: Permite diseñar interfaces gráficas utilizando XML o Jetpack Compose, lo que hace que el diseño de aplicaciones sea mucho más visual e intuitivo.
- Emulador de Android: Te permite probar y ejecutar tus aplicaciones en dispositivos virtuales con diferentes configuraciones (como distintas versiones de Android, tamaños de pantalla, etc.), sin necesidad de contar con un dispositivo físico.
- Herramientas de depuración y rendimiento: Android Studio incluye potentes herramientas para depurar aplicaciones, monitorear el rendimiento y resolver problemas de manera eficiente.
- Integración con Firebase: Si decid es utilizar Firebase, Android Studio facilita su integración, lo que permite agregar funcionalidades como bases de datos en tiempo real, autenticación, notificaciones push, entre otras.
Android Studio configura automáticamente la versión adecuada del JDK para el entorno, pero es importante asegurarte de que tienes JDK 8 o superior si trabajas con versiones de Android Lollipop o superiores. Si necesitas verificar tu instalación de JDK, puedes hacerlo fácilmente con el comando
javac -version
en la terminal.
Normalmente, Android Studio configura automáticamente la versión adecuada del JDK. No obstante, si necesitas verificarlo, puedes hacerlo fácilmente con el comando javac -version en la terminal.
El siguiente enlace a un Codelab de la documentación oficial de desarrolladores de Android te ofrece una guía de instalación por cada sistema operativo.
Creado con eXeLearning (Ventana nueva)
Ada ha decidido que aprender Kotlin puede ser muy positivo para el equipo, ya que se trata de un lenguaje moderno, conciso y seguro, adoptado oficialmente por Google para el desarrollo de aplicaciones Android.
María y Juan, con experiencia previa en Java, comienzan a familiarizarse con Kotlin. Pronto descubren que este lenguaje les permite escribir código más limpio y con menos errores, gracias a características modernas.
Con el apoyo de Ada, se sumergen en este nuevo entorno con el objetivo de dominar sus conceptos clave y aplicarlos en el desarrollo de aplicaciones Android más eficientes y mantenibles.
Ocultar
En este apartado, nos adentramos en el lenguaje de programación Kotlin, que se ha convertido en una de las principales herramientas para el desarrollo de aplicaciones Android. Kotlin es un lenguaje moderno, conciso y seguro que se adapta perfectamente a los proyectos Android, proporcionando una alternativa más eficiente y legible a Java. A lo largo de esta sección, exploraremos sus características clave, comenzando por su relevancia para Android, sus diferencias con Java y cómo nos permite escribir código más limpio y con menos errores.
Empezaremos por entender qué es Kotlin y por qué ha sido adoptado por Google como lenguaje oficial para Android. Luego, compararemos Kotlin con Java, destacando las ventajas y diferencias clave. A medida que avancemos, aprenderemos cómo trabajar con variables, tipos de datos, condicionales y bucles en Kotlin, así como las nuevas posibilidades que nos ofrece a través de funciones, tipos anulables y lambdas.
También exploraremos conceptos importantes como clases, objetos, constructores y data class, que son fundamentales para entender cómo se estructuran las aplicaciones en Kotlin. Para finalizar, nos introduciremos en conceptos más avanzados, como herencia, interfaces, clases abstractas y coroutines que te permitirán manejar tareas asíncronas de manera más eficiente.
Este apartado tiene como objetivo proporcionarte una comprensión completa de Kotlin y sus aplicaciones en Android, de modo que puedas aprovechar sus ventajas para escribir código más eficiente, legible y fácil de mantener.
Kotlin es un lenguaje que fue diseñado para ser simple, seguro y pragmático. Al aprender Kotlin, no solo mejoras la calidad del código, sino que también experimentas la sensación de escribir código moderno que te ayuda a resolver problemas de forma más eficiente.
Andrey Breslav, Creador de Kotlin
Creado con eXeLearning (Ventana nueva)
Ocultar
Kotlin es un lenguaje de programación de tipado estático desarrollado por JetBrains que se lanzó oficialmente en 2011. Kotlin está diseñado para ser un lenguaje más conciso, seguro y moderno que Java, y es completamente interoperable con Java. Esto significa que puedes usar ambos lenguajes en un mismo proyecto Android, lo que hace que la transición a Kotlin sea gradual y sin la necesidad de reescribir todo el código en Java.
La relevancia de Kotlin en el contexto de Android es clara: Google lo adoptó como un lenguaje oficial para el desarrollo de aplicaciones Android en 2017, como parte de su esfuerzo por mejorar la calidad y eficiencia del desarrollo. Kotlin aporta varias características que hacen que el desarrollo de aplicaciones Android sea más rápido y seguro:
- Concisión: Permite escribir menos código para realizar las mismas tareas, lo que mejora la productividad.
- Seguridad de tipos: La gestión de los nulls en Kotlin es mucho más segura que en Java, lo que ayuda a evitar uno de los errores más comunes en el desarrollo Android.
- Compatibilidad con Java: Como se mencionó, Kotlin es totalmente compatible con el código Java, lo que permite que ambos lenguajes se utilicen en paralelo sin problemas.
Estas características hacen que Kotlin sea una opción ideal para el desarrollo de aplicaciones Android modernas, proporcionando un lenguaje más eficiente y robusto, mientras se mantiene compatible con el ecosistema de herramientas y bibliotecas de Java.
¿Cómo impacta la compatibilidad de Kotlin con Java en los proyectos ya existentes? ¿Crees que es importante poder integrar Kotlin gradualmente en un proyecto Java?
Creado con eXeLearning (Ventana nueva)
Ocultar
Aunque Java ha sido durante años el lenguaje principal para el desarrollo de aplicaciones Android, Kotlin introduce varias mejoras que hacen que sea una opción más atractiva para los desarrolladores. Las diferencias más destacadas entre Kotlin y Java incluyen:
- Sintaxis más concisa: Kotlin permite escribir menos código para realizar las mismas tareas. Esto se traduce en menos posibilidades de cometer errores y un código más fácil de mantener. Por ejemplo, Kotlin no requiere el uso de puntos y comas al final de cada línea, y su sintaxis para la creación de clases, funciones y variables es más simple.
- Manejo de nulls: Kotlin aborda uno de los problemas más comunes en el desarrollo Android: las excepciones de null pointer. En Kotlin, los tipos nulos son explícitos y no se permiten por defecto, lo que obliga al programador a manejarlos de manera segura. Esto reduce significativamente los errores en tiempo de ejecución relacionados con valores nulos.
- Funciones de orden superior: Kotlin soporta funciones de orden superior de manera nativa, lo que permite pasar funciones como parámetros, devolver funciones desde otras funciones y más. Esto abre un abanico de posibilidades para escribir código más flexible y reutilizable.
- Interoperabilidad: Kotlin es completamente interoperable con Java, lo que permite usar bibliotecas Java existentes y migrar de manera gradual un proyecto Java a Kotlin sin necesidad de realizar una reescritura total.
- Características modernas: Kotlin también tiene muchas características modernas que facilitan el trabajo con colecciones, flujos,coroutines y otras herramientas para crear aplicaciones más rápidas y eficientes.
Un error de null pointer ocurre cuando se intenta acceder a una variable que no tiene un valor asignado (es nula), lo que puede causar fallos en la aplicación.
Las coroutines son una forma ligera y eficiente de manejar tareas asíncronas y concurrencia en Kotlin, permitiendo escribir código más fácil de entender y manejar en comparación con los enfoques tradicionales.
Creado con eXeLearning (Ventana nueva)
Ocultar
En Kotlin, la declaración de variables es simple y flexible. Se pueden declarar variables mutables con <strong data-start="265" data-end="274">var</strong> o inmutables con val.
Además, Kotlin permite inferir tipos automáticamente, y ofrece la posibilidad de declarar variables nulas (null)<b> </b>o no nulas. También se puede usar el modificador lateinit para inicializar variables más tarde. A continuación, exploraremos cada uno de estos conceptos en detalle.
Variables inmutables (val)
Las variables inmutables son aquellas cuyo valor no cambia después de ser asignado. Se utilizan para declarar constantes. Se definen con la palabra reservada val.
Ejemplo:
val nombre: String = "Juan"
Una vez asignado el valor a nombre, no puede modificarse.
Variables mutables (var)
Las variables mutables permiten cambiar su valor durante la ejecución del programa. Estas se definen con la palabra reservada var.
Ejemplo:
var edad: Int = 25
edad = 26
La variable edad se puede modificar
Inferencia de tipos
El tipo de una variable puede inferirse automáticamente según el valor que se le asigne. Esto significa que no es necesario especificar el tipo explícitamente.
Ejemplo:
val nombre = "Ana"
var edad = 30
Kotlin infiere que nombre es de tipo String y edad es de tipo Int
Inicialización tardía (lateinit)
El modificador lateinit permite declarar variables que se inicializarán más tarde, pero solo para variables no anulables. Esto es útil cuando no se puede asignar un valor en el momento de la declaración, pero se garantiza que se inicializará antes de su uso.
Ejemplo:
lateinit var nombre: String
fun inicializar() {
nombre = "Pedro" // Inicialización posterior
}
Nullabilidad de las variables
En Kotlin, las variables pueden ser nulas o no nulas. Por defecto, las variables no pueden tener valor <strong data-start="2237" data-end="2245">null</strong>, lo que ayuda a evitar errores de tipo <strong data-start="2285" data-end="2309">NullPointerException</strong>. Sin embargo, si necesitas que una variable pueda ser <strong data-start="2364" data-end="2372">null</strong>, debes indicar su tipado anulable añadiendo un ? al tipo de la variable.
Ejemplo de variable no anulable:
var nombre: String = "Juan" // No puede ser null
var nombre: String? = null // Puede ser null
Creado con eXeLearning (Ventana nueva)
Ocultar
Los tipos de datos son categorías fundamentales que indican qué clase de valores puede almacenar una variable y cómo se comportan dentro del programa. En Kotlin, como en Java, esta clasificación permite al lenguaje gestionar la memoria, validar operaciones y evitar errores. Sin embargo, aunque ambos lenguajes comparten muchos tipos comunes (como Int, String o Boolean), Kotlin introduce ciertas diferencias clave que conviene conocer.
Por ejemplo, en Kotlin todos los tipos son objetos, no existen tipos primitivos como en Java, aunque el compilador realiza optimizaciones internas para no perder rendimiento. Además, la gestión de valores nulos es más estricta, lo que ayuda a evitar errores comunes como el NullPointerException. Esto obliga a declarar explícitamente cuándo una variable puede ser null, haciendo el código más seguro y predecible. Entender los tipos de datos en Kotlin no solo facilita el paso desde Java, sino que permite escribir código más conciso, legible y robusto desde el principio.
Enteros (Int)
El tipo Int en Kotlin es similar al int de Java, pero en Kotlin no es necesario usar Integer para trabajar con números enteros. Además, en Kotlin, los enteros son siempre Int (32 bits) por defecto, no long como en Java.
Ejemplo:
val edad: Int = 25 // En Java: int edad = 25;
val saldo: Int = -100 // En Java: int saldo = -100;
Decimales (Double y Float)
Kotlin tiene dos tipos para trabajar con números decimales:
-
- <strong>Double</strong>: Similar al double de Java, con 64 bits de precisión.
- <strong>Float</strong>: Similar al float de Java, con 32 bits de precisión. Se debe agregar un f al número para especificar que es de tipo Float.
Ejemplo:
val altura: Double = 1.75 // En Java: double altura = 1.75;
val temperatura: Float = 36.5f // En Java: float temperatura = 36.5f;
Cadena de texto (String)
En Kotlin, las cadenas de texto se representan con String, al igual que en Java.
Ejemplo:
val nombre: String = "Juan" // En Java: String nombre = "Juan";
Booleanos (Boolean)
El tipo Boolean en Kotlin es exactamente igual al de Java. Se utiliza para almacenar los valores true o false.
Ejemplo:
val esEstudiante: Boolean = true // En Java: boolean esEstudiante = true;
val tieneLicencia: Boolean = false // En Java: boolean tieneLicencia = false;
Caracteres (Char)
El tipo Char en Kotlin es equivalente al char en Java. Se utiliza para representar un solo carácter y se indica con comillas simples (').
Ejemplo:
val letra: Char = 'A' // En Java: char letra = 'A';
Nulos (Null)
Una de las diferencias más importantes entre Kotlin y Java es cómo manejan los valores nulos. En Kotlin, los tipos no pueden ser null por defecto, a menos que se indique explícitamente con el operador ?. En Java, las referencias a objetos pueden ser null por defecto.
Ejemplo en Kotlin:
val nombre: String? = null // Esta variable puede ser nula
En Java, esta sería equivalente a:
String nombre = null; // En Java, esto es válido sin necesidad de un operador especial
¿Por qué crees que Kotlin ha implementado un sistema de tipos más estricto para manejar valores nulos, en comparación con Java, y cómo crees que este enfoque podría ayudar a reducir errores en el desarrollo de aplicaciones Android?
Creado con eXeLearning (Ventana nueva)
Ocultar
Los condicionales permiten ejecutar diferentes bloques de código dependiendo de si se cumple o no una condición. Los condicionales más comunes son:
if y else
El if es el condicional básico, que evalúa UNA condición booleana. Si la condición es verdadera, ejecuta el bloque de código correspondiente.
Ejemplo:
val edad = 18
if (edad >= 18) {
println("Eres mayor de edad")
} else {
println("Eres menor de edad")
}
¿Cuándo usarlo? El if es ideal para evaluar una condición booleana simple (true y false) y ejecutar una acción si se cumple y otra si no es así.
else if
Cuando tienes que evaluar VARIAS condiciones secuenciales, puedes usar else if. Esto te permite verificar una serie de condiciones diferentes de forma ordenada.
Ejemplo:
val nota = 85
if (nota >= 90) {
println("Excelente")
} else if (nota >= 75) {
println("Bueno")
} else {
println("Necesita mejorar")
}
¿Cuándo usarlo? Usa else if para evaluar varias condiciones relacionadas en una sola estructura. Es útil cuando la lógica depende de rangos o valores conectados.
<span>when</span>
El when es el equivalente en Kotlin al switch de Java, pero es mucho más potente y flexible. Puedes usarlo para evaluar múltiples valores de una sola variable, pero también te permite trabajar con condiciones más complejas, como rangos y expresiones.
<span></span>
Mientras que con if/else solo puedes evaluar una condición booleana, when te permite comparar una sola variable contra múltiples valores o rangos de manera más eficiente y legible.
Además, el manejo de múltiples condiciones es mucho más limpio y legible, por lo tanto, lo hace más fácil de mantener.
Ejemplo básico:
val dia = "Lunes"
when (dia) {
"Lunes" -> println("Inicio de semana")
"Viernes" -> println("Fin de semana a la vista")
else -> println("Es un día cualquiera")
}
<span></span>
Ejemplo con rangos:
<span></span>
val numero = 7
when (numero) {
in 1..5 -> println("Número entre 1 y 5")
in 6..10 -> println("Número entre 6 y 10")
else -> println("Número fuera de rango")
}
<span></span>
Ejemplo con expresiones complejas:
<span></span>
val x = 10
val y = 20
when {
x > y -> println("x es mayor que y")
x == y -> println("x es igual a y")
else -> println("x es menor que y")
}
<span></span>
¿Cuándo usarlo? Usa when para comparar una variable con varios valores, rangos o manejar condiciones complejas de forma clara y eficiente.
<span></span>
Creado con eXeLearning (Ventana nueva)
Ocultar
Los bucles se utilizan para repetir una sección de código varias veces, y al igual que en Java, puedes usar diferentes tipos de bucles según las necesidades de tu programa. Aunque la sintaxis y las estructuras son similares a las de Java, Kotlin ofrece algunas simplificaciones y mejoras. A continuación, exploraremos los tipos de bucles más comunes en Kotlin.
Bucle for
El bucle for en Kotlin es bastante similar al de Java, pero con una sintaxis más compacta y legible. Se utiliza para iterar sobre un rango de valores, una colección o un <strong data-start="796" data-end="805">array</strong>.
Ejemplo de bucle for básico
for (i in 1..5) {
println(i)
}
Características clave:
- Rangos: Los rangos (..) se utilizan para definir un intervalo de valores. Puedes usar rangos para iterar de forma sencilla.
- Avance personalizado: Puedes personalizar el paso del rango utilizando step, por ejemplo: 1..10 step 2 itera de 2 en 2.
- Exclusión del límite superior: Si solo deseas iterar hasta un valor excluyendo el límite superior, puedes usar el operador until.
for (i in 1..10 step 2) {
println(i)
} //Ejemplo de avance personalizado
for (i in 1 until 5) {
println(i)
} //Ejemplo de limite superior
¿Cuándo usarlo? Usa el bucle for cuando necesites iterar sobre un rango, colección o array de manera definida y controlada.
Bucle while
El bucle while en Kotlin funciona de manera similar al de Java, ejecutándose mientras se cumpla una condición.
¿Cuándo usarlo? Usa el bucle while cuando no sepas de antemano cuántas veces se debe ejecutar el bucle, pero sí tienes una condición clara de terminación.
Bucle do-while
El bucle do-while es como en Java, similar al while, pero con la diferencia de que la condición se evalúa después de ejecutar el bloque de código.
var i = 0
do {
println(i)
i++
} while (i < 5)
¿Cuándo usarlo? Usa el bucle do-while cuando necesitas que el bloque de código se ejecute al menos una vez, independientemente de la condición.
Bucle foreach
El método forEach nos permite iterar sobre colecciones o <strong data-start="3597" data-end="3607">array</strong> de forma más funcional. Este método es una alternativa más concisa al bucle for tradicional.
Ejemplo:
fun imprimirNumero(numero: Int) {
println(numero)
}
val numbers = listOf(1, 2, 3, 4, 5)
numbers.forEach(::imprimirNumero)
¿Cuándo usarlo? Usa forEach cuando trabajes con colecciones o arrays y quieras aplicar una acción a cada elemento sin necesidad de un índice explícito.
Etiquetas en bucles (break y continue)
Kotlin permite utilizar las palabras clave break y continue dentro de los bucles para controlar el flujo de ejecución.
break: Detiene la ejecución del bucle cuando se cumple una condición.
continue: Omite la iteración actual y pasa a la siguiente.
for ((nombre, edad) in personas) {
if (nombre == "Pedro") {
println("La edad de Pedro es: $edad")
break // Detiene el bucle una vez que encuentra a Pedro
}
} //Ejemplo de break
for ((nombre, edad) in personas) {
if (edad > 45) {
continue // Omite las personas mayores de 45 años
}
println("$nombre tiene $edad años")
} //Ejemplo de continue
IMPORTANTE:
Abusar de break y continue puede hacer que el código sea difícil de leer y mantener, especialmente en bucles anidados. Úsalos solo cuando realmente simplifiquen la lógica o mejoren la claridad del flujo de ejecución. Si se usan en exceso, el código puede volverse confuso y difícil de depurar.
Imagina que estás trabajando en un sistema que procesa una lista de pedidos. Dentro de un bucle, usas break o continue cada vez que encuentras un problema con un pedido, como un valor faltante o un error en los datos. Por ejemplo, si un pedido tiene un precio incorrecto, usas break para detener todo el proceso, o si falta un campo en el pedido, usas continue para saltarte ese pedido.
Esto puede llevar a un código difícil de seguir, ya que los desarrolladores que lean tu código no sabrán fácilmente por qué el bucle se detiene o salta ciertos pedidos, especialmente si no están familiarizados con las condiciones específicas. El flujo del programa puede ser confuso, y podría ser más difícil depurar y hacer mantenimiento del sistema.
En lugar de depender de break o continue en cada error, sería mejor utilizar un manejo de errores más explícito, como lanzar excepciones, para que el flujo del código sea más claro y fácil de seguir.
Creado con eXeLearning (Ventana nueva)
Ocultar
Las funciones en Kotlin son bloques de código reutilizables que se definen en archivos con extensión .kt. Pueden aceptar parámetros y devolver valores, o no devolver nada (en cuyo caso se usa el tipo Unit). Gracias a esto, se pueden organizar tareas específicas de forma más clara y reutilizable.
Kotlin permite asignar valores por defecto a los parámetros, lo que simplifica las llamadas a funciones y evita sobrecargas innecesarias.
En programas simples, se utiliza la función main como punto de entrada o programa principal, igual que en otros lenguajes. Aunque en aplicaciones Android no se usa directamente, es útil para pruebas.
Cuando se trabaja con varios archivos .kt, se pueden usar funciones de otros archivos, siempre que se declaren como public o protected y estén en el mismo paquete, solo importando con la instrucción import. Esto permite una mejor organización y reutilización del código.
Funciones
Una función en Kotlin se define utilizando la palabra clave fun, seguida por el nombre de la función, los parámetros entre paréntesis y el tipo de retorno (si lo hay). Si la función no devuelve nada, el tipo de retorno será Unit (equivalente a void en Java), pero no hace falta especificarlo, ya que Kotlin lo interfiere de manera automática.
fun saludar(nombre: String) {
println("Hola, $nombre!")
}
Parámetros con valor por defecto
En Kotlin, puedes asignar un valor por defecto a un parámetro de una función. Si no se proporciona un valor para ese parámetro al llamar a la función, se usará el valor por defecto.
fun saludar(nombre: String = "Invitado") {
println("Hola, $nombre!")
}
fun saludar2(nombre: String = "Invitado", edad: Int = 18) {
println("Hola, $nombre! Tienes $edad años.")
}
fun main() {
// Llamada a la función saludar con un nombre específico
saludar("Pedro") // Imprime: Hola, Pedro!
// Llamada a la función saludar sin argumentos, usando el valor por defecto
saludar() // Imprime: Hola, Invitado!
// Llamada a la función saludar2 con nombre y edad específicos
saludar2("Pedro", 25) // Imprime: Hola, Pedro! Tienes 25 años.
// Llamada a la función saludar2 solo con nombre, usando el valor por defecto para la edad
saludar2("Ana") // Imprime: Hola, Ana! Tienes 18 años.
// Llamada a la función saludar2 sin argumentos, usando los valores por defecto
saludar2() // Imprime: Hola, Invitado! Tienes 18 años.
}
Parámetros nombrados
Cuando una función tiene varios parámetros con valores por defecto, puedes usar parámetros nombrados para especificar el valor de un parámetro sin tener que seguir el orden de los mismos.
fun saludar(nombre: String = "Invitado", edad: Int = 18) {
println("Hola, $nombre! Tienes $edad años.")
}
fun main() {
// Llamada con los parámetros nombrados, donde se asignan explícitamente los valores
saludar(edad = 25) // Imprime: Hola, Invitado! Tienes 25 años.
}
Kotlin permite declarar funciones con parámetros de longitud variable usando la palabra clave vararg. Esto te permite pasar un número indefinido de argumentos de un tipo específico a la función.
fun saludar(vararg nombres: String) {
for (nombre in nombres) {
println("Hola, $nombre!")
}
}
saludar("Pedro", "Ana", "Maria") // Imprime: Hola, Pedro! Hola, Ana! Hola, Maria!
Un caso común de uso de vararg es cuando queremos sumar un número indefinido de valores, como en una función que calcule la suma de varios números sin tener que pasar cada número como un parámetro individual.
Creado con eXeLearning (Ventana nueva)
Ocultar
Las funciones de orden superior y las lambdas son conceptos fundamentales para la programación funcional.
- Una Lambda es una función pequeña y anónima que se define en una sola línea. Anónima porque no tienen un nombre explícito y no le hace falta porque se utiliza mediante su definición. Las lambdas se utilizan frecuentemente cuando se quiere definir una función breve de forma rápida y sencilla o para formar funciones de orden superior, explicadas más adelante.
- Una función de orden superior es una función que puede recibir otra función como argumento o devolver una función, siendo común que estas funciones sean lambdas. Este tipo de funciones son muy poderosas y permiten un nivel de flexibilidad y abstracción muy alto en el código. Sus características clave son:
- Reciben otras funciones como parámetros.
- Pueden devolver funciones.
- Ayudan a crear código más limpio y modular.
Ejemplo básico lambda
val saludar = { nombre: String -> println("Hola, $nombre!") }
fun main() {
saludar("Pedro") // Imprime: Hola, Pedro!
}
Este código define una función lambda y la utiliza en el main. Vamos a desglosarlo paso a paso:
val saludar: crea una variable llamada saludar.
{ nombre: String -> println("Hola, $nombre!") }: Esta es la lambda que se esta asignando a la variable saludar.
nombre: String: Define el parámetro de la lambda, que es una variable de tipo String.
->: Este símbolo separa los parámetros de la lógica de la lambda.
println("Hola, $nombre!"): Es la acción que realiza la lambda. Imprime en consola un saludo usando el valor de nombre.
Ejemplo de funcion de orden superior
fun operar(a: Int, b: Int, operacion: (Int, Int) -> Int): Int {
return operacion(a, b)
}
fun main() {
val suma = { x: Int, y: Int -> x + y }
val resta = { x: Int, y: Int -> x - y }
println(operar(5, 3, suma)) // Imprime: 8
println(operar(5, 3, resta)) // Imprime: 2
}
Explicación del ejemplo:
- operar recibe tres parámetros:
a y b son dos enteros con los que se realizarán operaciones.
operacion es una función que toma dos enteros (Int, Int) y devuelve un entero (Int).
- Dentro de la función, se ejecuta la operación pasada como argumento (
operacion(a, b)), devolviendo el resultado de aplicar esa función a a y b.
suma y resta son funciones lambda, que son funciones anónimas y se definen en una sola línea.
suma suma dos números: x + y.
resta resta dos números: x - y.
- En cada llamada a
operar, se pasan los números 5 y 3 junto con la función lambda correspondiente:
- En la primera línea, se pasa
suma, por lo que se realiza 5 + 3, resultando en 8.
- En la segunda línea, se pasa
resta, por lo que se realiza 5 - 3, resultando en 2.
Ejemplo de función de orden superior forEach con lambda
Las lambdas son muy útiles cuando se trabajan con funciones de orden superior. Una de las funciones más comunes que utiliza lambdas es forEach (vista en apartados anteriores), que itera sobre los elementos de una colección:
fun main() {
val nombres = listOf("Pedro", "Ana", "Maria")
nombres.forEach { nombre -> println("Hola, $nombre!") }
}
Explicación del ejemplo:
val nombres: Declara una variable inmutable llamada nombres que contiene una lista de cadenas de texto (String).
listOf("Pedro", "Ana", "Maria"): La función listOf crea una lista con los elementos "Pedro", "Ana" y "Maria".
nombres.forEach: El método forEach se usa para iterar sobre cada elemento de la lista nombres. En otras palabras, recorre la lista y ejecuta una acción para cada elemento.
{ nombre -> println("Hola, $nombre!") }: Esta es una lambda que define la acción a ejecutar sobre cada elemento de la lista. En este caso:
nombre: Es el parámetro de la lambda que representa el valor de cada elemento de la lista en cada iteración (es decir, primero "Pedro", luego "Ana", luego "Maria").
->: Este símbolo separa el parámetro de la acción que realiza la lambda.
println("Hola, $nombre!"): Es la acción que imprime en consola el saludo. El $nombre se reemplaza por el valor actual de nombre en cada iteración, lo que genera un saludo personalizado.
Ejemplo de función de orden superior con retorno de lambda
fun multiplicar(factor: Int): (Int) -> Int {
return { numero -> numero * factor }
}
fun main() {
val multiplicarPor2 = multiplicar(2)
println(multiplicarPor2(5)) // Imprime: 10
}
Explicación del ejemplo:
fun multiplicar(factor: Int): (Int) -> Int: Esta es la declaración de la función multiplicar.
factor: Int es el parámetro de entrada de tipo entero. Es el valor con el que multiplicaremos.
(Int) -> Int es el tipo de retorno de la función: una función que toma un entero (Int) como argumento y devuelve un entero (Int). Es decir,
multiplicar
no devuelve un valor directamente, sino otra función.
{ numero -> numero * factor }: Esta es una lambda que define la operación de multiplicación. La lambda:
- Toma un parámetro
numero de tipo Int.
- Realiza la operación
numero * factor y devuelve el resultado. El valor de factor es capturado de manera cerrada (closure), lo que significa que la lambda tiene acceso al valor de factor incluso después de que la función multiplicar haya terminado de ejecutarse.
- En resumen:
multiplicar devuelve una nueva función (la lambda) que toma un número y lo multiplica por el valor factor que se pasó a la función multiplicar.
multiplicarPor2(5): Ahora, multiplicarPor2 es una función que multiplica cualquier número por 2. Cuando le pasamos 5 como argumento, la lambda calcula 5 * 2, lo que da como resultado 10.
println(multiplicarPor2(5)): Imprime el resultado de la multiplicación, que es 10.
Ocultar
Las ventajas del uso de las funciones de orden superior y lambdas:
- Concisión y legibilidad: Las lambdas permiten escribir código más compacto y expresivo, haciendo que las funciones sean más fáciles de entender y usar.
- Modularidad y reutilización: Puedes pasar funciones como parámetros, lo que hace que tu código sea más flexible y reutilizable.
- Abstracción: Al utilizar funciones de orden superior, puedes abstraer comportamientos complejos en funciones pequeñas y reutilizables.
- Programación funcional: Facilitan el uso de paradigmas funcionales como la transformación de colecciones, la composición de funciones, y la creación de funciones puras.
Creado con eXeLearning (Ventana nueva)
Ocultar
Kotlin ofrece una distinción importante entre tipos que pueden ser nulos y aquellos que no pueden ser nulos. En esta sección, exploraremos los tipos nulables y cómo se usan los operadores ? y !! para manejar variables que pueden contener un valor nulo. Estas herramientas son fundamentales para garantizar que las variables y objetos sean tratados de manera segura, evitando errores de tiempo de ejecución relacionados con valores nulos.
- Tipos Nulables (?). En Kotlin, por defecto, todos los tipos no pueden ser nulos. Para permitir que un tipo sea nulo, se debe agregar un
? al tipo, lo que indica que la variable puede contener un valor nulo o un valor del tipo especificado.
- Operador de Afirmación de No Nulo (!!). El operador
!! se utiliza para convertir un tipo nulable en un tipo no nulable. Esto indica que estás seguro de que la variable no es nula en ese momento. Si resulta ser nula, se lanzará un NullPointerException.
Ejemplo tipo nulable (?)
var nombre: String? = null
Dónde nombre puede ser un String o null, porque se lo imponemos expresamente en la declaración de tipo String?.
Ejemplo operador de afirmación de NO nulo (!!)
val nombre: String? = null
val longitud: Int = nombre!!.length // Lanza NullPointerException si nombre es null
En este caso:
nombre!!: El operador !! fuerza el acceso a nombre como si no fuera null. Si nombre es null, lanza un NullPointerException en tiempo de ejecución.
nombre!!.length: Intenta acceder a la propiedad length de nombre. Como nombre es null, se producirá un error y el programa fallará con un NullPointerException en esta misma línea de código.
Creado con eXeLearning (Ventana nueva)
Ocultar
En Kotlin, los operadores ?. y ?: se diseñaron para mejorar el manejo de valores nulos y reducir la cantidad de código necesario para evitar excepciones relacionadas con la nulidad, como el famoso NullPointerException. Ambos operadores ofrecen una forma más segura, concisa y legible de trabajar con objetos que pueden ser nulos, lo que hace que el código sea menos propenso a errores y más fácil de mantener.
- Operador Seguro (?.). Este operador se usa para acceder de manera segura a propiedades o llamar a métodos en un objeto que puede ser nulo. Si el objeto sobre el que se invoca el operador es no nulo, la operación se realiza normalmente. Sin embargo, si el objeto es nulo, la operación no se lleva a cabo y se devuelve
null de manera segura. Este operador permite evitar la necesidad de verificaciones manuales de nulidad, lo que hace el código más limpio y fácil de leer. Por ejemplo, si tenemos una variable que puede ser nula, persona?.direccion, la expresión se evaluará como null si persona es nula.
- Operador Elvis (?:). El operador Elvis se utiliza para proporcionar un valor predeterminado cuando una expresión resulta ser nula. Si la expresión a la izquierda del operador es no nula, se devuelve su valor. Si es nula, se devuelve el valor que está a la derecha del operador. Este operador es muy útil cuando necesitamos asegurar que una variable nunca sea nula, proporcionando una alternativa en caso de que la expresión original sea nula. Por ejemplo, si tenemos una variable
nombre que puede ser nula, podemos usar nombre ?: "Desconocido" para asignar un valor por defecto en caso de que nombre sea nulo.
Ejemplo operador seguro (?.)
fun main() {
var nombre: String? = null // Se declara una variable de tipo String que puede ser nula
println(nombre?.length) // Uso seguro con el operador ? para evitar NullPointerException
}
En este caso:
- La variable
nombre es de tipo String?, lo que significa que puede contener una cadena o un valor nulo.
- Al utilizar el operador
?. (llamado operador seguro de llamada), evitamos un error si nombre es nulo. En lugar de lanzar una excepción, el operador retorna null si la variable es nula, sin intentar acceder a una propiedad o método.
Ejemplo Operador Elvis (?:)
fun main() {
var nombre: String? = null
val longitud = nombre?.length ?: 0 // Si nombre es nulo, longitud será 0
println(longitud) // Imprime: 0
}
En este caso:
nombre es una variable de tipo nulable (String?), lo que significa que puede contener un valor de tipo String o bien null.
- En este caso,
nombre se inicializa con el valor null.
nombre?.length: Aquí usamos el operador seguro ?. para intentar acceder a la propiedad length de la variable nombre. Este operador asegura que si nombre no es null, obtendremos la longitud de la cadena. Pero si nombre es null, la expresión devuelve null en lugar de lanzar un error de tipo NullPointerException.
- En este caso, como
nombre es null, la expresión nombre?.length devuelve null.
?: 0: Este es el operador Elvis ?:, que se utiliza para manejar el caso en el que la expresión anterior (nombre?.length) sea
null
. Si la parte de la izquierda (en este caso, nombre?.length) es null, el operador Elvis devuelve el valor a la derecha (en este caso,
0
).
- Entonces, como
nombre?.length es null, el operador Elvis devuelve 0 y se asigna a la variable longitud.
- Finalmente, se imprime el valor de
longitud, que es 0, porque como nombre era null, la expresión nombre?.length ?: 0 resultó en 0.
Las buenas prácticas de programación nos recomiendan:
- Evitar el uso excesivo de
!!: Usar !! debería ser lo último que elijas, ya que puede generar excepciones. Si no estás seguro de que el valor no sea nulo, es mejor usar el operador seguro ?. o proporcionar un valor por defecto con ?:.
- Preferir tipos
? y el operador seguro ?.: Siempre que sea posible, usa ? y ?. para trabajar con valores nulos de manera más segura y predecible.
Creado con eXeLearning (Ventana nueva)
Ocultar
En Kotlin, los objetos y las clases son fundamentales para estructurar el código de manera eficiente y modular. Kotlin ofrece un enfoque flexible y conciso para trabajar con programación orientada a objetos, permitiendo la creación de clases con propiedades y métodos que modelan comportamientos específicos. Además, la implementación de objetos como instancias únicas o clases con métodos estáticos facilita el manejo de componentes reutilizables y patrones de diseño, lo que resulta en un código más limpio y organizado.
Para poder utilizar una clase definida en otro archivo .kt, simplemente se importa al comienzo del archivo donde se necesita con la instrucción import, siempre que ambas clases pertenezcan al mismo proyecto o módulo.
Una buena práctica en Kotlin es almacenar cada clase en su propio archivo con extensión .kt, lo que mejora la organización y el mantenimiento del código. Aunque el lenguaje permite tener varias clases por archivo, se recomienda que cada archivo .kt contenga una sola clase principal.
Este apartado explorará cómo aprovechar estas herramientas para estructurar y organizar programas de manera más eficaz.
- Una clase es una plantilla a partir del cual se crean instancias (objetos) que comparten las mismas propiedades (atributos) y comportamientos (métodos o funciones). Para crear una clase en Kotlin, se usa la palabra clave
class . Las clases están compuestas por:
- Funciones constructoras: Son las funciones especiales que se utilizan para inicializar las propiedades de la clase al momento de su creación, permitiendo asignar valores a los atributos o realizar configuraciones iniciales.
- Propiedades: Son los datos que la clase almacena (por ejemplo, un nombre, una edad, una dirección).
- Métodos: Son las funciones que definen lo que la clase puede hacer (por ejemplo, calcular una edad, modificar un valor, realizar una acción).
- Modificadores de visibilidad: Las propiedades y métodos de la clase pueden tener modificadores de visibilidad que controlan desde dónde pueden ser accedidos. Los admitidos son:
public: Accesible desde cualquier lugar (por defecto).
private: Solo accesible dentro de la clase.
protected: Accesible dentro de la clase y sus subclases.
internal: Accesible dentro del mismo módulo (proyecto).
- Particularidades del lenguaje referentes a las clases, a diferencia de Java:
- Las clases y métodos son
final por defecto, por lo que para poder heredar o sobrescribir una clase se debe añadir el modificador de clase open.
- Las propiedades y funciones son públicas si no se especifica lo contrario.
- Se generan automáticamente las funciones getter de todas las propiedades de la clase y también los setters de las propiedades catalogados como var, que son las que pueden variar su valor.
- Un objeto es una instancia concreta de una clase. Mientras que la clase define la estructura y el comportamiento general, el objeto es una entidad específica con valores únicos para sus propiedades. Cada vez que se crea un objeto, se asignan valores a sus propiedades y se pueden ejecutar sus métodos, interactuando con otros objetos y modificando su estado.En Kotlin los objetos tienen:
- Propiedades: Datos que el objeto almacena, variables como podrían ser
nombre o edad.
- Métodos: Funciones que definen lo que el objeto puede hacer, como
saludar().
Sintaxis de una clase
class NombreDeClase(val propiedad1: Tipo, var propiedad2: Tipo) { // Constructora primaria
// Propiedad
private var propiedad: Tipo = valor //modificador de visibilidad privado
// Bloque init
init {
println("Clase creada: $propiedad, $propiedad1, $propiedad2")
}
// Método
fun metodo() { //modificador de visibilidad público por defecto
// código del método
}
}
Como se ve en el ejemplo, también se puede usar el bloque init para lógica de inicialización:
Ejemplo de una clase
class Persona(private val dni: String) {
var nombre: String = ""
var edad: Int = 0
fun saludar() {
println("Hola, mi nombre es $nombre y tengo $edad años.")
}
// Método público para acceder al dni, si es necesario
fun obtenerDni(): String {
return dni
}
}
Sintaxis de un objeto
//Creación del objeto
val nombreObjeto = Clase(parametrosDelConstructor)
//acceso a las propiedades y métodos del objeto
nombreObjeto.propiedad
nombreObjeto.metodo()
Ejemplo de objeto
Utilizando la clase del ejemplo anterior y creamos una instancia -conocida como Objeto- de esa clase, que se llama Persona.
fun main() {
val persona = Persona("45888888Q") // Crea un objeto de la clase Persona, pasando el dni
persona.nombre = "Pedro"
persona.edad = 25
persona.saludar() // Imprime: Hola, mi nombre es Pedro y tengo 25 años.
// No puedes acceder directamente a 'dni' desde fuera de la clase
// println(persona.dni) // Esto dará un error, ya que 'dni' es privado
// Sin embargo, puedes acceder al dni a través de un método público, si lo deseas
println("DNI de la persona: ${persona.obtenerDni()}") // Imprime: DNI de la persona: 45888888Q
}
¿Cómo puedes identificar cuándo es realmente necesario crear una clase u objeto en Kotlin, y cuándo es mejor optar por una solución más simple?
Creado con eXeLearning (Ventana nueva)
Ocultar
En este apartado exploraremos dos conceptos clave del lenguaje Kotlin: los constructores y las clases de datos o data class. Ambos son fundamentales para crear y manejar objetos en Kotlin, y presentan diferencias importantes con respecto a su equivalente en Java.
- Los constructores permiten inicializar objetos al momento de crearlos, al igual que en Java. A diferencia de Java, donde se definen múltiples constructores dentro del cuerpo de la clase, en Kotlin el constructor primario se define en la cabecera de la clase, lo que hace el código más conciso y expresivo. Kotlin ofrece dos tipos de constructores:
- Constructor primario: Es el constructor principal de una clase, definido directamente en la cabecera, y permite declarar e inicializar propiedades de forma concisa.
- Constructores secundarios: Son opcionales, se define dentro del cuerpo de la clase y ofrece formas adicionales de crear objetos cuando se necesita más flexibilidad o lógica personalizada.
- Las data class son clases pensadas para almacenar datos. A diferencia de Java, Kotlin genera automáticamente:
- equals(): Compara dos objetos evaluando si sus propiedades son iguales; por ejemplo, dos libros con el mismo autor (si el autor es también un
data class) se consideran iguales aunque sean instancias diferentes: Libro("1984", Autor("Orwell")) == Libro("1984", Autor("Orwell")) devuelve true.
- hashCode(): Genera un número entero único (dentro de lo posible) basado en los valores de las propiedades del objeto; este código se usa internamente en estructuras de datos como
HashMap, HashSet o cualquier colección que dependa de operaciones de búsqueda rápida. Si dos objetos son iguales según equals(), deben tener el mismo hashCode().
- toString(): Devuelve una representación en texto del objeto, mostrando los valores de sus propiedades.
- copy(): Crea una copia del objeto, permitiendo opcionalmente modificar una o más propiedades.
- Funciones getter y
setter, igual que en cualquier clase Kotlin.
Sintaxis constructores
Un constructor primario se define directamente en la cabecera de la clase. Puede incluir modificadores como val o var para declarar propiedades y añadirle modificadores de visibilidad según necesidad.
class NombreClase(val propiedad1: Tipo1, private var propiedad2: Tipo2)
Un constructor secundario se declara dentro del cuerpo de la clase con la palabra clave constructor. Debe delegar al constructor primario si existe.
class NombreClase(val nombre: String) {
var edad: Int = 0
constructor(nombre: String, edad: Int) : this(nombre) {
this.edad = edad
}
}
Ejemplo clase con constructor primario y secundarios
class Libro(val titulo: String, val autor: String) {
var paginas: Int = 0
var disponible: Boolean = true
// Bloque de inicialización
init {
println("Libro creado: $titulo de $autor")
}
// Constructor secundario
constructor(titulo: String, autor: String, paginas: Int) : this(titulo, autor) {
this.paginas = paginas
}
fun descripcion(): String {
return "$titulo, escrito por $autor, tiene $paginas páginas."
}
fun prestar() {
if (disponible) {
disponible = false
println("El libro '$titulo' ha sido prestado.")
} else {
println("El libro '$titulo' no está disponible.")
}
}
}
// Uso de la clase creada Libro con ambos constructores
fun main() {
val libro1 = Libro("1984", "George Orwell")
val libro2 = Libro("Fahrenheit 451", "Ray Bradbury", 249)
println(libro1.descripcion())
println(libro2.descripcion())
libro2.prestar()
libro2.prestar()
}
Sintaxis data class
Creación básica con solo propiedades:
data class NombreDeClase(val propiedad1: Tipo, var propiedad2: Tipo)
Creación de data class con métodos:
data class NombreDeClase(
val propiedad1: Tipo1, // Propiedad de solo lectura
var propiedad2: Tipo2 // Propiedad de lectura y escritura
) {
// Los métodos personalizados pueden ser agregados aquí
// Método 1: Método personalizado
fun metodo1() {
// Código del método
}
// Método 2: Otro método personalizado
fun metodo2() {
// Código del método
}
}
Ejemplo data class
data class Libro(
val titulo: String, // Propiedad de solo lectura
var autor: String, // Propiedad de lectura y escritura
var precio: Double // Propiedad de lectura y escritura
)
fun main() {
// Crear un objeto Libro
val libro1 = Libro("1984", "George Orwell", 15.99)
// Usar toString() generado automáticamente
println(libro1.toString())
// Imprime: Libro(titulo=1984, autor=George Orwell, precio=15.99)
// Crear un segundo objeto Libro con los mismos valores
val libro2 = Libro("1984", "George Orwell", 15.99)
// Usar equals() generado automáticamente
println(libro1 == libro2)
// Imprime: true (porque los valores son iguales)
// Usar copy() para crear una copia del libro con un precio modificado
val libro3 = libro1.copy(precio = 12.99)
println(libro3)
// Imprime: Libro(titulo=1984, autor=George Orwell, precio=12.99)
// Usar componentN() para desestructuración
val (titulo, autor, precio) = libro1
println("Título: $titulo, Autor: $autor, Precio: $precio")
// Imprime: Título: 1984, Autor: George Orwell, Precio: 15.99
}
Usa data class cuando necesites almacenar datos y aprovechar sus métodos automáticos como toString(), equals() y copy(). Si necesitas más lógica o comportamiento personalizado, es mejor usar una clase regular con un constructor tradicional.
Coloca las data class en archivos separados si son reutilizables o complejas. Si son simples y solo se usan en un contexto específico, pueden ir en el mismo archivo que la clase que las utiliza.
Creado con eXeLearning (Ventana nueva)
Ocultar
La herencia es un concepto fundamental en la programación orientada a objetos que permite a una clase heredar propiedades y métodos de otra clase. Esto facilita la reutilización de código y la creación de relaciones jerárquicas entre clases. En herencia, la clase que hereda se llama subclase o clase derivada, y la clase de la que se hereda se llama superclase o clase base.
La subclase puede añadir nuevos métodos o propiedades, y también puede modificar los heredados (a través de la sobrescritura o <strong data-start="540" data-end="552">override</strong>).
La herencia en Kotlin es un poco diferente de otros lenguajes como Java, ya que por defecto, todas las clases en Kotlin son finales, lo que significa que no pueden ser heredadas a menos que se indique explícitamente lo contrario. Para que una clase pueda ser heredada, debemos marcarla con la palabra clave open. De manera similar, para que un método o propiedad de una clase sea sobrescrito (overridden) por una clase hija, también debe ser marcado con open. Las clases y métodos no son heredables por defecto en Kotlin, lo que ayuda a evitar la herencia no deseada y a crear un diseño más seguro y controlado.
Sintaxis herencia
// Archivo Superclase.kt: Este archivo contiene la definición de la clase base `Superclase`,
// que utiliza el modificador `open` para permitir que otras clases hereden de ella.
// La clase define un método `metodo()` que puede ser sobrescrito por las clases derivadas.
open class Superclase {
open fun metodo() {
println("Método de la superclase")
}
}
// Archivo Subclase.kt: Este archivo contiene la clase `Subclase`, que hereda de la clase `Superclase`.
// La subclase sobrescribe el método `metodo()` para modificar su comportamiento,
// demostrando cómo las clases pueden personalizar los métodos heredados.
class Subclase : Superclase() {
override fun metodo() {
println("Método sobrescrito en la subclase")
}
}
Ejemplo herencia
// Archivo Animal.kt: Este archivo contiene la clase base `Animal`, que define comportamientos comunes
// como el método `hacerSonido()` y `respirar()`. La clase está diseñada para ser heredada por otras clases
// que necesiten estos comportamientos, como en el caso de la subclase `Perro`.
open class Animal(val nombre: String) {
open fun hacerSonido() {
println("$nombre está haciendo un sonido")
}
fun respirar() {
println("$nombre está respirando")
}
}
// Archivo Perro.kt: Este archivo contiene la clase `Perro`, que es una subclase de `Animal`.
// En ella se sobrescribe el método `hacerSonido()` para personalizar el comportamiento específico del perro
// (en este caso, ladrar). También incluye un método adicional `correr()` que es exclusivo de la clase `Perro`.
class Perro(nombre: String, val raza: String) : Animal(nombre) {
override fun hacerSonido() {
println("$nombre está ladrando")
}
fun correr() {
println("$nombre está corriendo")
}
}
// Archivo Main.kt: Este archivo contiene la función `main()`, donde se crea un objeto de la clase `Perro`.
// Aquí se demuestran los conceptos de herencia y polimorfismo, llamando a los métodos heredados de la clase
// `Animal` (como `respirar()`) y a los métodos específicos de la subclase `Perro` (como `hacerSonido()` y `correr()`).
fun main() {
// Crear un objeto de la clase Perro, que hereda de Animal
val perro = Perro("Fido", "Labrador")
// Llamar al método heredado respirar()
perro.respirar() // Fido está respirando
// Llamar al método sobrescrito hacerSonido()
perro.hacerSonido() // Fido está ladrando
// Llamar al método específico de la subclase correr()
perro.correr() // Fido está corriendo
}
- La clase
Animal es la superclase, con un método hacerSonido() que puede ser sobrescrito.
- La clase
Perro hereda de Animal y sobrescribe el método hacerSonido(), además de agregar un método propio correr().
- Cuando se crea un objeto de la clase
Perro, se puede acceder tanto a los métodos heredados (como respirar()) como a los sobrescritos y específicos de la subclase (como hacerSonido() y correr()).
Creado con eXeLearning (Ventana nueva)
Ocultar
Las interfaces y clases abstractas se utilizan para compartir comportamientos comunes entre diferentes clases. Aunque ambas sirven para este propósito, su objetivo y uso son distintos. Cada una tiene características únicas que las hacen más apropiadas para ciertos escenarios. A continuación, vamos a explicar de manera técnica qué es cada una y cómo puedes entender su uso de forma sencilla.
- Usa interfaces cuando necesites definir un contrato que una clase debe seguir, pero no te importe cómo lo haga ni que tenga un estado. Son ideales cuando quieres asegurarte de que las clases comparten comportamientos pero sin imponerles una estructura común. Por lo tanto, las interfaces pueden:
- Definir un contrato: Métodos que las clases deben implementar, sin detalles de implementación.
- Implementación por defecto: Pueden incluir implementaciones de métodos o no.
- No mantener estado: No pueden tener propiedades de instancia (variables).
- Herencia múltiple: Las clases pueden implementar varias interfaces.
- Comportamientos compartidos: Se usan para compartir comportamiento sin imponer una estructura común.
- Usa clases abstractas cuando quieras una base común que incluya tanto detalles de implementación como la capacidad de mantener un estado. Son útiles cuando tienes clases relacionadas y necesitas compartir comportamientos y atributos.
- Definir una plantilla y comportamiento común: Métodos abstractos que las subclases deben implementar, con posibles implementaciones concretas.
- Mantener estado: Pueden tener propiedades de instancia (variables).
- No se pueden instanciar: Es una clase, pero solo se pueden usar como base.
- Herencia simple: Una clase puede heredar solo de una clase abstracta.
- Métodos opcionales u obligatorios: Los métodos pueden ser abstractos (obligatorios de implementar) o tener una implementación concreta que puede ser utilizada tal cual o sobrescrita.
Sintaxis interface
// Archivo NombreDeInterfaz.kt: Este archivo contiene la definición de la interfaz `NombreDeInterfaz`.
// La interfaz define un método abstracto `metodoAbstracto()` que debe ser implementado por cualquier clase
// que la implemente. También contiene un método `metodoConcreto()` con una implementación por defecto,
// que puede ser utilizado directamente o sobrescrito por las clases implementadoras.
interface NombreDeInterfaz {
// Métodos abstractos (no tienen implementación)
fun metodoAbstracto()
// Métodos con implementación por defecto
fun metodoConcreto() {
println("Método con implementación por defecto")
}
}
Ejemplo interface
// Archivo Animal.kt: Este archivo contiene la definición de la interfaz `Animal`,
// que define dos métodos: uno abstracto `hacerSonido()` que debe ser implementado por las clases
// que la implementen, y otro método con una implementación por defecto `respirar()`.
interface Animal {
fun hacerSonido()
fun respirar() {
println("El animal está respirando")
}
}
// Archivo Mascota.kt: Este archivo contiene la definición de la interfaz `Mascota`,
// que define dos métodos: uno abstracto `jugar()` y otro con implementación por defecto `dormir()`,
// que deben ser implementados o usados por las clases que implementen esta interfaz.
interface Mascota {
fun jugar()
fun dormir() {
println("La mascota está durmiendo")
}
}
// Archivo Perro.kt: Este archivo contiene la clase `Perro`, que implementa tanto la interfaz `Animal` como la interfaz `Mascota`.
// La clase `Perro` proporciona implementaciones específicas para los métodos abstractos `hacerSonido()` y `jugar()`
// definidos en las interfaces. Además, puede utilizar los métodos con implementación por defecto de ambas interfaces.
class Perro : Animal, Mascota {
// Implementación del método abstracto de Animal
override fun hacerSonido() {
println("¡Guau!")
}
// Implementación del método abstracto de Mascota
override fun jugar() {
println("El perro está jugando")
}
}
// Archivo Main.kt: Este archivo contiene la función `main()`, donde se crea un objeto de la clase `Perro`.
// Se demuestran los conceptos de múltiples interfaces al llamar a los métodos de ambas interfaces `Animal` y `Mascota`,
// que fueron implementados en la clase `Perro`.
fun main() {
val perro: Perro = Perro()
perro.hacerSonido() // ¡Guau!
perro.respirar() // El animal está respirando
perro.jugar() // El perro está jugando
perro.dormir() // La mascota está durmiendo
}
Sintaxis clase abstracta
// Archivo NombreDeClaseAbstracta.kt: Este archivo contiene la definición de la clase abstracta `NombreDeClaseAbstracta`.
// Una clase abstracta permite definir tanto métodos abstractos (sin implementación) como métodos concretos (con implementación).
// Las clases que heredan de una clase abstracta deben implementar los métodos abstractos definidos en ella.
abstract class NombreDeClaseAbstracta {
// Propiedades y métodos concretos
var propiedad: Tipo = valor
// Métodos abstractos (sin implementación)
abstract fun metodoAbstracto()
// Métodos con implementación
fun metodoConcreto() {
println("Método de la clase abstracta")
}
}
Ejemplo clase abstracta
// Archivo Vehiculo.kt: Este archivo contiene la clase abstracta `Vehiculo`, que define un método abstracto `mover()`
// y un método concreto `detener()`. Las clases que hereden de `Vehiculo` deberán implementar el método `mover()`,
// pero podrán usar o sobrescribir el método `detener()` que tiene implementación propia.
abstract class Vehiculo(val nombre: String) {
// Método abstracto
abstract fun mover()
// Método concreto
fun detener() {
println("$nombre se ha detenido")
}
}
// Archivo Coche.kt: Este archivo contiene la clase `Coche`, que hereda de `Vehiculo`.
// La clase `Coche` implementa el método abstracto `mover()`, proporcionando su propia implementación
// sobre cómo un coche se mueve.
class Coche(nombre: String, val modelo: String) : Vehiculo(nombre) {
// Implementación del método abstracto
override fun mover() {
println("$nombre ($modelo) está moviéndose")
}
}
// Archivo Barco.kt: Este archivo contiene la clase `Barco`, que también hereda de `Vehiculo`.
// La clase `Barco` implementa el método abstracto `mover()`, proporcionando su propia implementación
// sobre cómo un barco se mueve.
class Barco(nombre: String, val tipo: String) : Vehiculo(nombre) {
// Implementación del método abstracto
override fun mover() {
println("$nombre ($tipo) está navegando")
}
}
// Archivo Main.kt: Este archivo contiene la función `main()` donde se crean objetos de las clases `Coche` y `Barco`.
// Se demuestran el uso de los métodos `mover()` y `detener()`, que se heredan de la clase `Vehiculo` y se sobrescriben
// según el tipo de vehículo.
fun main() {
val coche = Coche("Toyota", "Corolla")
val barco = Barco("Yate", "De lujo")
coche.mover() // Toyota (Corolla) está moviéndose
coche.detener() // Toyota se ha detenido
barco.mover() // Yate (De lujo) está navegando
barco.detener() // Yate se ha detenido
}
La modularización del código mediante el uso de interfaces y clases abstractas es fundamental para mejorar la mantenibilidad, flexibilidad y escalabilidad de una aplicación. Utilizar interfaces permite definir contratos de comportamiento sin preocuparse de la implementación concreta, lo que facilita la extensión de la funcionalidad sin alterar la estructura del código existente. Por otro lado, las clases abstractas permiten compartir comportamientos comunes y estado entre clases relacionadas, evitando la duplicación de código y garantizando la consistencia.
En el desarrollo de aplicaciones Android, estas prácticas son esenciales. Por ejemplo, en RecyclerView.Adapter, una interfaz utilizada para manejar datos en listas, se definen los métodos que deben implementarse para gestionar los elementos de una lista. También se utilizan clases abstractas como Fragment, que proveen funcionalidades comunes para los fragmentos en una actividad y permiten personalizar su comportamiento según las necesidades del proyecto. Estas estructuras ayudan a crear un código más organizado, modular y fácil de mantener a medida que la aplicación crece.
Creado con eXeLearning (Ventana nueva)
Ocultar
Las coroutines son una herramienta poderosa para manejar operaciones asíncronas de manera más eficiente y comprensible. Permiten ejecutar tareas en segundo plano, como descargar datos, consultas a bases de datos o interacciones con API, sin bloquear el hilo principal de la aplicación, lo que garantiza una mejor experiencia de usuario al evitar que la aplicación se congele o vuelva lenta.
A diferencia de otras soluciones como los callbacks o hilos tradicionales, las coroutines permiten escribir código asíncrono de una forma secuencial, que es más fácil de leer y mantener. Utilizan un concepto llamado suspensión para pausar una tarea y reanudarla más tarde sin bloquear el hilo. Esto mejora el rendimiento y simplifica el manejo de tareas asíncronas complejas.
¿Por qué Kotlin utiliza Coroutines?
Kotlin se ha convertido en el lenguaje oficial para el desarrollo de aplicaciones Android, y una de sus características más destacadas es el soporte nativo para coroutines. Esto permite a los desarrolladores escribir código asíncrono de manera más sencilla y directa, sin la complejidad de otros enfoques. Además, muchas de las bibliotecas estándar de Kotlin y librerías de Android, como Retrofit para las peticiones HTTP o Room para el acceso a bases de datos, ya utilizan coroutines internamente.
Esto significa que, al desarrollar aplicaciones Android con Kotlin, verán y usarán coroutines de forma habitual. Al trabajar con tareas como la descarga de datos de una API o la ejecución de operaciones en segundo plano, las coroutines se convierten en una herramienta esencial para garantizar que las aplicaciones sigan siendo rápidas y responsivas.
Las partes principales de las Coroutines son:
- Lanzar una Coroutine:
launch y async. Las coroutines se lanzan usando launch o async. Ambas se usan para ejecutar código asíncrono, pero tienen diferencias en cómo gestionan el resultado.
launch: Se usa cuando no necesitas obtener un valor de retorno, simplemente lanzas una tarea asíncrona.
async: Se usa cuando necesitas obtener un valor de retorno de la tarea asíncrona.
- Funciones
suspend. Las funciones <strong data-start="1376" data-end="1387">suspend</strong> son funciones que pueden ser "pausadas" y reanudadas. Se usan dentro de coroutines para realizar tareas largas o que tardan tiempo en completarse (como descargar datos o consultar una base de datos).
Sintaxis Coroutines
import kotlinx.coroutines.*
fun main() = runBlocking {
// 1. Ejemplo de launch: Tarea asíncrona sin retorno
println("Inicio de launch")
GlobalScope.launch {
// Código dentro de la coroutine lanzada con 'launch'
delay(1000L) // Simula una tarea que tarda 1 segundo
println("Operación con launch completada")
}
// 2. Ejemplo de async: Tarea asíncrona con retorno de resultado
println("Inicio de async")
val result = async {
// Código dentro de la coroutine lanzada con 'async'
delay(1000L) // Simula una tarea que tarda 1 segundo
"Resultado obtenido con async"
}
// La coroutine async devuelve un 'Deferred', por lo que necesitamos esperar el resultado
println("Esperando el resultado de async...")
println(result.await()) // Espera y obtiene el resultado cuando se complete la tarea
// 3. Ejemplo de suspend: Función suspendida que puede ser llamada dentro de una coroutine
println("Inicio de la función suspend")
val fetchResult = fetchData()
println(fetchResult) // Muestra el resultado obtenido de la función suspendida
}
// 3. Función suspendida que simula una operación asíncrona
suspend fun fetchData(): String {
delay(2000L) // Simula una operación que tarda 2 segundos
return "Datos obtenidos de fetchData"
}
Ejemplo Coroutine con launch
import kotlinx.coroutines.*
fun main() {
GlobalScope.launch {
// Este bloque de código se ejecuta en una coroutine
println("Inicio de la tarea")
delay(2000L) // Simula una tarea que tarda 2 segundos
println("Tarea completada")
}
// Aquí puedes seguir ejecutando más código, sin esperar a que la coroutine termine
println("Esperando la tarea...")
Thread.sleep(3000L) // Espera lo suficiente para que la coroutine termine
}
GlobalScope.launch: Inicia una coroutine en el ámbito global. Es decir, se ejecuta en segundo plano y no bloquea el hilo principal.
delay(2000L): Simula una operación larga. La función delay suspende la coroutine durante el tiempo indicado (sin bloquear el hilo).
Thread.sleep(3000L): Esta línea es solo para que el programa espere lo suficiente para que la coroutine termine su ejecución.
Ejemplo Coroutine con async
import kotlinx.coroutines.*
fun main() = runBlocking {
// Lanza una coroutine con async para obtener un valor
val result = async {
delay(2000L) // Simula una tarea larga
"Resultado de la operación"
}
// Mientras tanto puedes hacer otras cosas, pero vamos a esperar el resultado
println("Esperando el resultado...")
println(result.await()) // Espera hasta que la tarea termine y devuelve el resultado
}
async: Lanza una coroutine que devuelve un valor. En este caso, el valor que devuelve es un Deferred que representa el valor que la coroutine va a devolver una vez termine su ejecución.
result.await(): Espera a que la coroutine termine y obtiene el resultado. Es importante notar que await() no bloquea el hilo principal, sino que suspende la ejecución de la coroutine hasta que se obtenga el resultado.
Ejemplo Coroutine con suspend
import kotlinx.coroutines.*
suspend fun fetchData(): String {
delay(2000L) // Simula una operación de red que tarda 2 segundos
return "Datos obtenidos"
}
fun main() = runBlocking {
// Llamamos a una función suspendida dentro de una coroutine
val data = fetchData()
println(data) // Imprime los datos obtenidos
}
suspend fun fetchData(): Es una función suspendida. Esta función puede ser pausada por un
delay
sin bloquear el hilo en el que se ejecuta.
delay(2000L): Simula una tarea larga (como una operación de red).
runBlocking: Inicia una coroutine de bloque. Es un mecanismo especial para ejecutar coroutines en el hilo principal cuando se está escribiendo código de manera síncrona (esto es útil en ejemplos como este).
Creado con eXeLearning (Ventana nueva)
Ha llegado la hora de ponerse manos a la obra. María va a crear una primera aplicación sencilla que le permita ver alguno de los componentes básicos que Ada les ha explicado en funcionamiento. Su primera aplicación consistirá en hacer un “Hello World”, algo muy típico cuando comenzamos a desarrollar aplicaciones para una nueva plataforma o lenguaje, utilizando además un IDE con el que tenemos que familiarizarnos.
Para empezar, Ada les comenta las principales carpetas y ficheros que se van a encontrar en cualquier proyecto y les explica lo más importante de cada uno de ellos.
Ocultar
Ya tenemos instalado el IDE y vamos a desarrollar una primera aplicación muy simple que sacará por pantalla el famoso "Hello World".
Para nombrar el proyecto y el resto de componentes utilizaremos el inglés. No te preocupes si no sabes alguna palabra, siempre se puede utilizar el Traductor de Google.
Algunos aspectos que debemos tener en cuenta cuando creamos nuestra aplicación son los siguientes:
- Inicio de Android Studio: Si es la primera vez que ejecutas Android Studio, en la pantalla de bienvenida debes seleccionar la opción Start a new Android Studio Project.
- Selección del tipo de proyecto: Escoge el tipo de proyecto que deseas crear; en nuestro caso, seleccionamos Phone and Tablet, y partimos de una actividad vacía (Empty Views Activity).
- Configuración del proyecto: A continuación, aparecerá la pantalla para configurar el proyecto. Según la versión de Android Studio, esta pantalla puede variar, pero siempre nos pedirá los siguientes datos:
- Nombre de la aplicación (Name): Es el nombre que le darás al proyecto para identificarlo, en este caso HelloWorld.
- Nombre de la compañía (Package Name): Este nombre del paquete es crucial para garantizar la unicidad de la aplicación en Google Play, será su identificador único.
Utilizaremos el formato de inicio de paquete dam.pmdm. seguido del nombre de la aplicación como tercer argumento. Por ejemplo, para una aplicación llamada "HelloWorld", el nombre del paquete sería dam.pmdm.helloworld.
- Localización del proyecto (Save Location): Es la ruta donde se guardará el proyecto, junto con toda su estructura de carpetas y archivos.
- Lenguaje del proyecto (Language): Este será el lenguaje en que se programará la aplicación y utilizaremos Kotlin.
- Versión mínima (Minimum SDK): Debes indicar la versión de API recomendada para tu aplicación. Esto asegura que la aplicación funcionará correctamente en los dispositivos que cumplan con esta versión mínima. Al seleccionar la versión mínima, se proporcionará un enlace Help me Choose que muestra el porcentaje de dispositivos que utilizan cada versión de Android.
- Kotlin DSL para el compilador: Asegúrate de configurar el proyecto para utilizar Kotlin DSL (Domain-Specific Language) en los archivos de construcción (build scripts). Esto simplificará la gestión de dependencias y configuraciones en tu proyecto.
- Exploración de la estructura del proyecto: Una vez completada la configuración, exploraremos los archivos y carpetas generados para entender mejor cómo se estructura una aplicación Android.
Existen Codelabs que ayudan a aprender y practicar el desarrollo de aplicaciones Android. En este Codelab: "Cómo crear tu primera app para Android", aprenderás a crear tu primera app.
Un Codelab es un tutorial interactivo que guía paso a paso sobre cómo realizar una tarea de programación, generalmente con ejemplos de código. Es útil para aprender nuevas tecnologías, mejorar habilidades prácticas y experimentar con conceptos de desarrollo en un entorno controlado y accesible.
Creado con eXeLearning (Ventana nueva)
Ocultar
Android Studio es un entorno que facilita significativamente el desarrollo de aplicaciones mediante asistentes y herramientas que generan automáticamente la estructura de carpetas necesarias, los archivos de configuración y ayudan en el diseño de las interfaces de usuario. Para comprender mejor la estructura de un proyecto Android, considera lo siguiente:
- Panel de Proyecto: El listado de archivos se muestra en el panel <strong>Project</strong> de la barra de herramientas de Android Studio. Este listado puede variar según la vista o perspectiva seleccionada. Por defecto, suele mostrarse en la vista Android.
- Vista de Proyecto: La estructura de carpetas que se muestra en la vista Android no es la estructura real de carpetas del proyecto. Al seleccionar la vista <strong>Project</strong>, podrás identificar las principales carpetas y archivos que se han creado en tu primera aplicación. Es importante conocer la ubicación y finalidad de cada uno de los ficheros, aunque no todas las carpetas especificadas a continuación deban estar presentes en todos los proyectos.
- Estructura de Módulos: Un proyecto creado en Android Studio puede estar formado por varios módulos, pero en nuestro caso, nos centraremos en el módulo principal llamado <strong>app</strong>, donde se encuentran los archivos de la aplicación:
| Carpeta/Archivo |
Descripción |
Ejemplos de Archivos |
| <strong>/libs/</strong> |
Contiene archivos de tipo JAR, donde se incluyen las librerías utilizadas en el proyecto. |
library.jar, gson.jar |
| <strong>/build/</strong> |
Alberga los archivos generados automáticamente durante la compilación del proyecto. |
outputs/apk/app-debug.apk, intermediates/ |
| <strong>/src/main/java/</strong> |
Almacena los archivos fuente en <strong>Kotlin/Java</strong> de la aplicación. Android Studio crea automáticamente el código básico de la pantalla principal, <strong>MainActivity.kt/MainActivity.java</strong>. |
MainActivity.kt, User.java |
| <strong>/src/main/res/</strong> |
Contiene todos los recursos necesarios para la aplicación. Algunas subcarpetas importantes son: |
|
| <strong>/res/drawable/</strong> |
Almacena imágenes y elementos gráficos, organizados por resolución y densidad de pantallas. |
icon.png, background.xml |
| <strong>/res/mipmap/</strong> |
Contiene iconos para lanzar la aplicación, divididos en subcarpetas según resolución y densidad. |
ic_launcher.png, ic_launcher_round.png |
| <strong>/res/layout/</strong> |
Almacena archivos XML que definen las pantallas de la interfaz gráfica. |
activity_main.xml, item_list.xml |
| <strong>/res/values/</strong> |
Contiene archivos XML para cadenas de texto, estilos, colores, etc. |
strings.xml, styles.xml, colors.xml |
| <strong>/res/menu/</strong> |
Almacena los menús de la aplicación. |
main_menu.xml, context_menu.xml |
| <strong>/res/navigation/</strong> |
Almacena archivos de navegación, utilizados para gestionar la navegación entre fragmentos y actividades. |
nav_graph.xml |
| <strong>/res/xml/</strong> |
Puede contener archivos XML para configuraciones adicionales, como preferencias de usuario. |
preferences.xml |
| <strong>/src/main/AndroidManifest.xml</strong> |
Contiene aspectos cruciales de la aplicación, como nombre, versión, icono, actividades (pantallas) y permisos. |
AndroidManifest.xml |
| <strong>build.gradle</strong> |
Almacena la información necesaria para compilar el proyecto y gestionar las dependencias. Es importante que esté configurado para el uso de Kotlin y las librerías necesarias. |
build.gradle |
Estructura de carpetas y archivos típicos en un proyecto Android
Familiarízate con Android Studio
Para desarrollar aplicaciones efectivamente, es fundamental que te familiarices con la interfaz de Android Studio y sus herramientas.
- Introducción al IDE Android Studio. Este enlace te llevará a una introducción de la documentación oficial, donde podrás obtener una visión general de la herramienta y su funcionalidad.
- Descripción Detallada de la Interfaz de Usuario. En este segundo enlace encontrarás una descripción completa de la interfaz de usuario de Android Studio. Te ayudará a entender cada elemento y cómo utilizarlo en tu proceso de desarrollo.
Creado con eXeLearning (Ventana nueva)
Ocultar
Al ejecutar cualquier aplicación Android, te encontrarás con una pantalla principal que contiene diferentes elementos organizados de una manera específica. Este diseño se define en un archivo XML llamado <strong>activity_main.xml</strong>, que se localiza en la carpeta /app/src/main/res/layout/. Este archivo es fundamental, ya que se encarga de especificar el diseño (layout) de los componentes de tipo view que incluirá la aplicación.
En Android Studio, puedes ver el diseño de la pantalla de tres maneras:
- Code: Muestra únicamente el código XML.
- Split: Muestra el código XML junto con una vista previa del diseño.
- Design: Muestra el resultado final del diseño.
La navegación entre estas vistas se realiza a través de los íconos ubicados en la parte superior derecha del editor.
El IDE facilita la lectura del código XML resaltando diferentes elementos mediante colores y mejorándonos así la legibilidad del código:
- Morado: Este color representa el espacio de nombres declarado en el nodo raíz mediante el atributo xmlns:<name>=<"uri">. Aquí, <name> es el prefijo del espacio de nombres, mientras que <"uri"> es el URI que identifica dicho espacio de nombres.
- Blanco: Los atributos que siempre llevan como prefijo su espacio de nombres se resaltan en azul. Esto ayuda a identificar rápidamente los atributos asociados a un espacio de nombres específico.
- Verde: El valor que toma cada atributo se resalta en verde. Este color permite distinguir fácilmente los valores asignados a los atributos en el código.
En la imagen de la derecha podemos ver un ejemplo de IDE mostrando el código XML de la pantalla de "Hello World". Aunque ahora todo puede parecer desconocido, lo importante es fijarnos en el IDE y familiarizarnos con él, ya que tiene muchas funcionalidades que nos serán de gran ayuda. Cuanto antes nos acostumbremos a su interfaz y herramientas, más rápido podremos movernos y aprovecharlo al máximo, convirtiéndose en nuestro mejor aliado en el desarrollo de aplicaciones Android.
Modifica la posición del TextView que contiene el texto “Hello World!” para que quede centrado en la pantalla. Reemplaza el texto por el siguiente “Bienvenido a Android”.
Creado con eXeLearning (Ventana nueva)
Ocultar
El siguiente fichero que veremos es la clase <strong data-start="145" data-end="161">MainActivity</strong> que puede ser escrita tanto en Java como en Kotlin. Este archivo se almacena en la carpeta /app/src/main/java/ y dentro del paquete llamado dam.pmdm.helloworld. Este fichero es el encargado de cargar la pantalla principal (Layout).
JAVA
package com.example.helloworld;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
}
KOTLIN
package com.example.helloworld
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)
}
}
En ambos códigos es mediante el método setContentView(R.layout.activity_main) que indicamos que se visualice un recurso a través de la clase estática llamada <strong data-start="986" data-end="998">R.layout</strong>. Esta clase referencia a todos los ficheros XML que se encuentran en el directorio /res/layout. En este caso, le decimos a través de una constante entera llamada activity_main (el nombre del archivo XML de /res/layout) qué vista queremos que se visualice.
Por cada archivo de <span lang="en">layout</span> que tengamos en /res/layout se generará una entrada en la clase <span lang="en">R.java</span>.
Creado con eXeLearning (Ventana nueva)
Ocultar
Sabemos cómo diseñar una pantalla utilizando XML y cómo mostrarla mediante código en Java o Kotlin, pero surge una pregunta clave: ¿cómo comienza una aplicación Android? ¿Cómo sabe la aplicación, qué componentes la forman y cómo interactúan entre ellos? La respuesta se encuentra en el archivo de manifiesto.
El fichero de manifiesto es uno de los elementos más importantes de una aplicación Android, ya que define las principales características necesarias para su correcto funcionamiento. En este archivo se especifica información crucial como:
- El nombre de la aplicación
- Las actividades (pantallas) que contiene
- Los permisos que requiere (por ejemplo, acceso a la cámara o al almacenamiento)
- Los servicios y receptores que forman parte de la aplicación móvil
- La versión de la aplicación y su compatibilidad con diferentes versiones de Android
El manifiesto organiza y estructura la aplicación, asegurando que todos los componentes interactúen de manera correcta y eficiente. Es un archivo clave que el sistema Android consulta cada vez que se ejecuta o instala la aplicación.
Si estudiamos su código y su estructura, observamos lo siguiente:
Nodo principal <manifest>
El nodo raíz del archivo es <manifest>, y entre sus atributos destaca:
- xmlns:android="http://schemas.android.com/apk/res/android": este atributo define el espacio de nombres de Android, que siempre tendrá ese valor.
- xmlns:tools="http://schemas.android.com/tools": se usa para incluir herramientas adicionales en el proyecto, en este caso, la herramienta define configuraciones específicas (como targetApi).
Nodo <application>
Dentro de este nodo se definen todas las características generales de la aplicación. Aquí encontramos varios atributos importantes:
- android:icon y
android:roundIcon: indican los iconos de la aplicación, referenciando a los recursos en la carpeta mipmap.
- android:label: hace referencia al nombre de la aplicación, el cual está almacenado en un recurso strings.xml bajo la clave app_name.
- android:theme: especifica el tema de la aplicación, que se encuentra en el archivo styles.xml.
- android:allowBackup,
android:dataExtractionRules y android:fullBackupContent: estas configuraciones definen las reglas para copias de seguridad y extracción de datos, útiles para la preservación de datos del usuario cuando reinstala la aplicación.
- tools:targetApi: se utiliza para especificar una versión objetivo del SDK para propósitos de desarrollo, en este caso, la API 31.
Nodo <activity>
Dentro del nodo <application>, se definen todas las actividades de la aplicación. En este caso, la actividad principal es:
- android:name=".MainActivity": esto hace referencia a la clase principal que actúa como punto de entrada de la aplicación. Este archivo Kotlin, MainActivity.kt, contiene el código que gestiona la pantalla principal.
- android:exported="true": indica si esta actividad puede ser llamada desde otras aplicaciones. En este caso, está configurado para que sea accesible.
Nodo <intent-filter>
El nodo intent-filter que está dentro del nodo <activity> indica que esta actividad es la que se debe ejecutar al iniciar la aplicación:
- <action android:name="android.intent.action.MAIN" />: esta acción declara que esta actividad es el punto de entrada principal de la aplicación.
- <category android:name="android.intent.category.LAUNCHER" />: indica que esta actividad debe aparecer en el lanzador (es decir, en la pantalla de aplicaciones de Android).
Retroalimentación
Falso
Es falso. El fichero que define el diseño del layout está en la carpeta /res/layout/.
Retroalimentación
Falso
Es falso. Ese método se encarga de iniciar la aplicación y está dentro del fichero que se encarga de mostrar la pantalla principal (en nuestro caso MainActivity.java dentro de la carpeta /src/)
Creado con eXeLearning (Ventana nueva)
Llegados a este punto, Ada explica a Juan y María cuáles son los componentes principales con los que van a trabajar a partir de ahora. Deben comprender para qué se utiliza cada uno de ellos y cómo funcionan. Ada les explica con ejemplos claros que pueden ver en sus propios móviles, ya que utilizan dicha plataforma. Por ejemplo, el reloj que les aparece en la pantalla principal es un tipo de componente que viene por defecto, cuando pulsamos sobre un icono para ejecutar una aplicación:
- ¿Qué mecanismo se lleva a cabo?
- ¿Qué nombre reciben cada una de las ventanas o pantallas que se abren?
- ¿Cómo se organizan los elementos que hay en ellas?
- ¿Cómo se puede compartir datos entre varias aplicaciones?
Es importante que conozcan e identifiquen cada uno de estos componentes, porque son la base de cualquier aplicación.
Ocultar
Si has programado en Java, estarás acostumbrado a trabajar con ventanas, controles, eventos, servicios, etc. a la hora de desarrollar una aplicación. En Android disponemos también de estos componentes aunque con algunas variaciones que pasaremos a comentar.
En una aplicación Android podemos encontrar los siguientes componentes:
- Activity (Actividad): es el componente principal de la interfaz gráfica de una aplicación Android. Es similar a una ventana o pantalla en cualquier lenguaje visual.
- Service (Servicio): es el componente que se ejecuta en segundo plano. Es similar a los servicios de cualquier sistema operativo. Estos servicios se encargan, por ejemplo, de enviar notificaciones, mostrar elementos visuales (activity), actualizar datos, etc.
- Content Provider (Proveedor de contenidos): es el componente que se encarga de compartir datos entre distintas aplicaciones Android.
- Broadcast Receiver (Receptor de anuncios): es el componente que se encarga de detectar y reaccionar ante algunos mensajes o eventos generados por el sistema (como por ejemplo batería baja, tarjeta SD insertada, SMS recibido, etc.) o por otras aplicaciones (cuando generan mensajes que no van dirigidos a una aplicación concreta).
Estos componentes se deben definir siempre en el fichero manifiesto dentro de la etiqueta <span class="tag"><application></span>. Por cada tipo de componente de nuestra aplicación se debe declarar uno de los siguientes elementos XML en función del tipo:
- <activity> para cada subclase de Activity.
- <service> para cada subclase de Service.
- <receiver> para cada subclase de BroadcastReceiver.
- <provider>para cada subclase de ContentProvider.
También podemos encontrarnos otros elementos que tienen una funcionalidad específica dentro de nuestra aplicación:
- Intent (Intención): es el objeto encargado de la comunicación entre el resto de componentes. Esa comunicación se realiza mediante mensajes o peticiones. Como ejemplo un intent nos permite abrir una actividad desde otra inicial, enviar un mensaje broadcast, iniciar un servicio, iniciar otra aplicación, etc.
- Widget: es un elemento visual que suele mostrarse en la pantalla principal del dispositivo. Muestra información de la aplicación al usuario. Pero en el ámbito de la programación de Android esta palabra adquiere otro significado, ya que también puede hacer referencia a un objeto View en el diseño de una interfaz de usuario.
- View (Vista): es el componente básico con el que se construye la interfaz gráfica de la aplicación, sería algo similar a los controles de Java. Entre alguno de los controles básicos o views que tiene Android estarían los cuadros de texto, botones, listas, etc.
- Layout (Diseño): se utiliza para agrupar y organizar los diferentes componentes de tipo view que componen una actividad o pantalla (activity). Existen diferentes tipos y además un layout también puede contener a su vez otros layouts.
The art of programming is the art of organizing ideas and tools. The more you can understand the fundamental components of a system, the more power you will have to build complex applications.
Brian W. Kernighan
Como señala Brian W. Kernighan, la programación no solo se trata de escribir código, sino de organizar las ideas y herramientas de manera efectiva. Cuanto mejor comprendes los componentes fundamentales de un sistema, más capacidad tienes de crear aplicaciones más complejas y eficientes, adaptándolas a diferentes necesidades y problemas.
Creado con eXeLearning (Ventana nueva)
Juan ha visto cómo María ha creado la primera aplicación, el proceso no es muy complejo pero, ¿cómo se pueden ver los resultados? Es decir, ¿cómo pueden comprobar lo que realmente hace esa aplicación? ¿Dónde la pueden ejecutar? ¿Existen tipos de emuladores para ver el resultado de diferentes formas? ¿Se puede ejecutar la aplicación en sus propios móviles?
Ocultar
Captura del
IDE Android Studio cuya licencia
es
Apache 2.0
Normalmente las herramientas de desarrollo integradas suelen incorporar uno o varios emuladores que te servirán para poder probar las aplicaciones antes de instalarlas en el dispositivo para el cual se han programado. Así podrás observar si la aplicación funciona correctamente y si tiene más o menos el aspecto que tenías pensado.
Hay que tener en cuenta que los emuladores no siempre van coincidir en aspecto (y a veces incluso en funcionalidad) con el dispositivo real y podrás encontrar algunas diferencias. En Android Studio esta herramienta se llama AVD Manager, y es el gestor de dispositivos virtuales o emuladores. Esta herramienta viene integrada dentro de Android Studio con lo cual sólo se tendrá que crear el emulador.
Es importante probar nuestra aplicación en diferentes emuladores con diferentes niveles de API de Android y así garantizar que nuestra aplicación se ejecuta correctamente. Ten en cuenta que existen muchas marcas y modelos de dispositivos Android y no tenemos a nuestro alcance tantos dispositivos físicos. Será a través de un emulador que probemos casi todas las funciones de un dispositivo Android real.
La mayor parte del proceso de depuración (por no decir todo) se realizará normalmente con el emulador, pues podremos depurar el software como con un programa en un ordenador convencional (ejecutar las instrucciones paso a paso, establecer breakpoints, observar el contenido de variables, etc).
Finalmente podremos probarlas en un dispositivo real.
La depuración es un aspecto crucial en el desarrollo de aplicaciones Android. Gracias a herramientas como el emulador de Android Studio y el uso de puntos de interrupción (breakpoints), podemos examinar cómo se comporta nuestra aplicación en diferentes condiciones, asegurándonos de que todo funcione correctamente antes de su despliegue en un dispositivo real.
La depuración no solo nos permite encontrar y corregir errores, sino que también optimiza el rendimiento de la aplicación, mejorando la experiencia del usuario final.
Depurar en Android Studio
Creado con eXeLearning (Ventana nueva)
Ocultar
Una vez tenemos la aplicación creada, el siguiente paso es probarla en un emulador de Android. Esto nos permitirá verificar cómo se comporta nuestra app en un entorno virtual que simula un dispositivo móvil real. Para comenzar, primero necesitamos crear un dispositivo móvil virtual en el Android Virtual Device (AVD) Manager, que es la herramienta encargada de gestionar los emuladores.
Una vez configurado el emulador, podremos instalar y ejecutar la aplicación directamente sobre el dispositivo virtual, lo que nos permitirá comprobar su funcionamiento sin necesidad de tener un dispositivo físico. Esto es especialmente útil durante el desarrollo, ya que podemos hacer pruebas rápidas y frecuentes.
Puedes acceder a este Codelab para aprender a emular una aplicación Android en el emulador o seguir los pasos detallados a continuación para configurar y probar tu aplicación:
Paso 1: Configurar un Dispositivo AVD (Android Virtual Device)
1.1.- Abrir AVD Manager
Localiza y haz clic en el icono del AVD Manager en la barra de herramientas de Android Studio.
1.2.- Crear un Nuevo Dispositivo Virtual
Haz clic en "Create Virtual Device".
1.3.- Elegir un Dispositivo
- Selecciona el tipo de dispositivo que deseas emular (teléfono, tableta, etc.).
- Haz clic en "Next".
1.4.- Seleccionar la Versión de Android
- Elige una imagen de sistema (versión de Android) que desees utilizar para tu emulador.
- Asegúrate de que la imagen tenga un nivel de API compatible con tu aplicación.
- Haz clic en "Next".
1.5.- Configurar Opciones del Dispositivo
- Asigna un nombre a tu dispositivo virtual y ajusta otras configuraciones si es necesario (como la cantidad de RAM).
- Haz clic en "Finish" para crear el AVD.
Paso 2: Desplegar la Aplicación en el Emulador
2.1.- Seleccionar el Dispositivo AVD
Asegúrate de que el emulador que acabas de crear esté seleccionado en el menú desplegable de dispositivos en la barra de herramientas de Android Studio.
2.2.- Iniciar el Emulador
Haz clic en el botón de "Run" (el triángulo verde) para iniciar el emulador.
2.3.- Ejecutar Aplicación
Selecciona la aplicación que deseas desplegar y haz clic en "OK". La aplicación se instalará y se ejecutará en el emulador.
Paso 3: Probar la Aplicación
3.1.- Interacción con la Aplicación
Una vez que la aplicación se esté ejecutando, puedes interactuar con ella como lo harías en un dispositivo físico.
3.2.- Depuración
Utiliza las herramientas de depuración disponibles en Android Studio para observar el comportamiento de la aplicación.
Una opción muy extendida entre los desarrolladores de aplicaciones Android para emular sus aplicaciones es utilizar cualquier emulador que ofrece Genymotion. Esta empresa proporciona emuladores más potentes y rápidos que los que podemos encontrar en Android Studio. Para utilizarlos, debemos instalar primero una máquina virtual con VirtualBox. En los siguientes enlaces puedes encontrar todo el proceso para trabajar con estos emuladores. Sería conveniente que lo instales y lo configures.
Descargar VirtualBox
Página oficial de Genymotion
Creado con eXeLearning (Ventana nueva)
Ocultar
Todas las pruebas que realizamos con los distintos emuladores virtuales son de gran ayuda durante el desarrollo, ya que nos permiten avanzar sin necesidad de un dispositivo físico. Sin embargo, ¿de qué sirve si finalmente la aplicación no funciona igual en un dispositivo real? ¿Puede variar el aspecto o la funcionalidad al ejecutarla en un smartphone, tablet u otro dispositivo Android? La respuesta es sí, pueden existir diferencias importantes, ya sea por el hardware, la versión del sistema operativo o el rendimiento del dispositivo.
Por eso, resulta imprescindible probar nuestras aplicaciones también en dispositivos reales, para asegurarnos de que todo funciona como se espera.
Para ello, es necesario configurar correctamente el dispositivo activando la depuración USB. A continuación, se explican los pasos necesarios para hacerlo:
Paso 1: Activar las Opciones de Desarrollador
- Accede a la Configuración de tu dispositivo.
- Desplázate hasta "Acerca del teléfono" o "Acerca del dispositivo".
- Busca el número de compilación y tócalo 7 veces. Esto habilitará las Opciones de desarrollador.
Paso 2: Activar la Depuración USB
- Regresa a la pantalla principal de Configuración.
- Busca y selecciona "Opciones de desarrollador".
- Activa la opción "Depuración USB". Aparecerá un aviso; selecciona "Aceptar".
Paso 3: Conectar el Dispositivo al Ordenador
- Utiliza un cable USB para conectar tu dispositivo móvil a la computadora.
- Asegúrate de que el dispositivo esté desbloqueado y, si es necesario, selecciona el tipo de conexión "Transferencia de archivos" o "MTP".
Paso 4: Desplegar la Aplicación desde Android Studio IDE
- Abre Android Studio y carga tu proyecto.
- Haz clic en el botón run (el ícono de "play") en la barra de herramientas.
- En la ventana que aparece, selecciona tu dispositivo móvil de la lista de dispositivos disponibles.
- Presiona OK y espera a que la aplicación se instale y se ejecute en tu dispositivo.
Si no has podido desplegar la aplicación en tu dispositivo móvil mediante este apartado, prueba accediendo a este Codelab de Google.
Creado con eXeLearning (Ventana nueva)
Juan y María han terminado la primera aplicación Android y la han desplegado tanto en distintos emuladores como en algunos dispositivos móviles reales. Antes de continuar viendo el diseño de la interfaz de usuario para realizar aplicaciones más complejas deciden preguntar a Ada cuál es el funcionamiento interno de la aplicación que acaban de realizar. Ada les explica que como desarrolladores tendrán que conocer los métodos que gestionan todo el proceso de una actividad o pantalla.
Ocultar
Ya está todo listo para poder empezar a crear aplicaciones algo más complejas y poderlas instalar y probar tanto en los emuladores como en dispositivos reales. Pero antes de comenzar con esa tarea, vamos a ver un aspecto muy importante a tener en cuenta en las aplicaciones Android, hablamos del ciclo de vida de las actividades o pantallas.
Nuestra aplicación constará de varias Activity. La primera que se ejecuta suele llamarse actividad principal y esta invocará a otra actividad de nuestra aplicación mientras el usuario interacciona con nuestra aplicación. Este cambio de estado de las actividades es debido a que el sistema operativo llama de forma automática a los métodos del ciclo de vida de las actividades y estos devuelven el resultado al sistema, a este tipo de llamadas se les conoce como métodos callback.
Esto no quiere decir que las actividades que dejamos de ver se destruyan, sino que se guardan en una pila de actividades en el mismo orden en el que han sido abiertas. Es cuando el usuario pulsa el botón back o Atrás, cuando la actividad finaliza y se quita de la pila de actividades. Cuando finalmente la actividad principal de nuestra aplicación finalice, se eliminará toda la información de la aplicación.
Las actividades de la pila nunca se reordenan, solo se insertan o se quitan
También una actividad se elimina cuando hay un cambio de configuración del dispositivo, el ejemplo más común es el cambio de idioma. En este supuesto, todo lo que tenga interfaz de usuario deberá actualizarse para que coincida con esa configuración, de ahí que la actividad se elimine llamando a sus métodos onPause(), onStop() y onDestroy() y se creará una nueva instancia de la actividad mediante las llamadas a onCreate(), onStart() y onResume().
Debemos ser conscientes que la capacidad de memoria de los dispositivos es limitada y, por tanto, tener muchas aplicaciones en ejecución puede ser un problema. En estos casos, el sistema para liberar memoria, puede destruir actividades que estén detenidas.
Los distintos estados por los que puede pasar una actividad son:
- Activa: la actividad está visible y puede ser utilizada por el usuario.
- Pausada: la actividad está visible, pero ha perdido el foco por otra actividad (por ejemplo: ventanas de diálogo o avisos). Se puede ver la actividad anterior porque la nueva actividad no suele ocupar la pantalla completa o es semitransparente.
- Parada: la actividad deja de estar visible, es conveniente guardar el estado por si el usuario vuelve a esta actividad.
Los métodos que gestionan el ciclo de vida son los siguientes:
- onCreate(): la actividad es creada por primera vez. Aquí tiene lugar la inicialización de la interfaz gráfica, así como los datos. Es obligatorio sobrescribir este método en una actividad. Este método recibe como parámetro una instancia de la clase Bundle que contiene la información necesaria para restaurar la actividad de su estado anterior. Si es la primera vez que se ejecuta la actividad, el valor de este parámetro será nulo.
- onStart(): la actividad está preparada para ser visualizada. No implica que se visualice al usuario.
- onResume(): la actividad se encuentra en la parte superior de la pila del sistema y está visible al usuario. Se puede empezar a interactuar con la actividad.
- onPause(): la actividad va a pasar a segundo plano porque otra actividad toma el foco. Es fundamental guardar el estado de la actividad.
- onStop(): la actividad va a dejar de estar visible por completo. Si el sistema no tiene memoria suficiente, puede ser que la actividad sea destruida sin pasar por este método.
- onRestart(): la actividad volverá a visualizarse después de haber sido parada y sin haber llegado a destruirse.
- onDestroy(): la actividad se destruye completamente para liberar la memoria utilizada. Si el sistema no tiene memoria suficiente, puede ser que la actividad sea destruida sin pasar por este método.
Los métodos que abarcan todo el ciclo de vida son onCreate() y onDestroy(), inicio y fin de la actividad. La actividad será visible al usuario desde el método onStart() hasta el método onStop(), aunque puede ser que no tenga el foco porque hay otras actividades con las que esté interactuando el usuario. La actividad está visible y además tiene el foco desde onResume() hasta onPause().
Creado con eXeLearning (Ventana nueva)
Ocultar
Licencias de recursos de la unidad
| Miniatura del recurso | Credenciales |
Montaje de elaboración propia usando recursos externos.
|
Autoría: Elaboración propia.
Licencia: Uso Educativo no comercial, citando fuentes.
Procedencia: Montaje de elaboración propia a partir de las imágenes siguientes:
- Imagen 1: Android
- Imagen 2: iOS
- Imagen 3: Windows Phone.
- Imagen 4: Java ME
- Autoría: Oracle.
- Licencia: Copyright
|
Nota: Este anexo incluye exclusivamente recursos cuya licencia obliga a la cita expresa, y que por la extensión de sus credenciales o por cualquier cuestión técnica no se pueden citar en línea. El resto de recursos son de elaboración propia y no requieren cita expresa, quedando su licencia expresada en la de los propios materiales, o se citan en línea, en el lugar donde aparecen en contenidos.
Creado con eXeLearning (Ventana nueva)
Ocultar
Materiales desarrollados inicialmente por el Ministerio de Educación, Cultura y Deporte y actualizados por el profesorado de la Junta de Andalucía bajo licencia Creative Commons BY-NC-SA.

Antes de cualquier uso leer detenidamente el siguente Aviso legal
Ocultar
Historial de actualizaciones
| Versión: 04.00.00 | Fecha de actualización: 10/06/25 | Autoría: Lindsay Barrero Martínez |
|---|
Ubicación: Contenidos Mejora (tipo 1): Corrección de errores según revisión de coordinación Ubicación: No especificada. Mejora (tipo 1): He actualizado el contenido de la unidad según la sugerencia de mejora Ubicación: Casi todos los apartados. Mejora (tipo 3): Cambios sugeridos:
1.2: Añadir los nuevos tipos de dispositivos móviles (smartwatches, e-books, brazaletes, etc)
2. Actualizar las tecnologías disponibles (ya no existe Windows Mobile como SO, existe Kotlin como lenguaje oficial de Android y ahora Android Studio es el IDE oficial de Android)
2.1. Actualizar el hardware movil de gama media actual.
2.2. Actualizar los SO móviles disponibles en la actualidad (Hay muchos ya obsoletos como Symbian, Windows Phone, Bada, Blackberry OS... Hoy en dia IOS y Android lideran el mercado con un 95% de uso global)
2.3. Desaparecen IDEs junto con los lenguajes obsoletos del punto 2.2.
2.4. Enfocar este apartado a que hay 2 alternativas de desarrollo Android (Java y Kotlin) y mantendremos las 2.
2.5. Eliminar la tabla de versiones y solo lincar a la tabla propuesta por Google, así no hay que actualizarla cada 6 meses (tiempo medio de actualización de Android).
3. Añadir que Runtime también incorporas librerias Kotlin.
3.1. Eliminar los MMS, ya no están disponibles.
4. Eliminar la versión de JDK recomendado (está desactualizado). Añadir que el IDE Android Studio ya incorpora todo lo necesario, no hay que instalar nada suelto.
5. Actualizar el proceso de creación de un nuevo proyecto, ha cambiado. Añadir un codelab de Google, para fortalecer la teoria.
5.1. La estructura del proyecto se ha modificado y existen nuevos elementos (nuevos recursos y nueva ubicación de elementos).
5.2. Actualizar la leyenda de colores, ya que ha cambiado. Mencinar que existe colores para mejor comprensión del código, pero no mencionarlos, porque se suelen actualizar.
5.3. Añadir ejemplo de código Kotlin
5.4. Añadir nuevos atributos del Manifest (como tagetApi o exported). Completar la explicación de atributos, ya que es importante entender cada uno de ellos.
7.1. Actualizar el proceso de despliegue en emulador, el actual está obsoleto. Añadir codelab como tutorial guiado complementando.
7.2. Actualizar el proceso de despliegue en dispositivo real, el actual está obsoleto. Añadir codelab como tutorial guiado complementando.
Además:
- Añadir un nuevo apartado (quizá entre el punto 4 y 5) para un tutorial de Kotlin.
- Añadir un nuevo apartado de Splash, que no hay, y explicar para API 31 y 31, que genera muchas dudas e incompatibilidades.
Es fundamental actualizar esta unidad, ya que es con la que el alumnado entra en contacto con el módulo y es clave para que puedan entender el mercado actual y desenvolverse con agilidad en un proyecto Android y el entorno de desarrollo de Android Studio. Conocer y dominar la estructura de un proyecto y el IDE les permitirá aprovechar todas sus funciones y ayudas mientras desarrollan, evitando que se sientan perdidos. El material actual está desactualizado en todos sus tutoriales y, en lugar de facilitar el aprendizaje, está dificultando la experiencia del alumnado. Ubicación: mapa Mejora (Mapa conceptual): Actualización del mapa y las descripciones con Kotlin. Ubicación: mapa conceptual Mejora (Mapa conceptual): He añadido Kotlin al mapa conceptual Ubicación: orientaciones Mejora (Orientaciones del alumnado): orientaciones Ubicación: Actualización Kotlin Mejora (Orientaciones del alumnado): He añadido los nuevos apartados del índice |
| Versión: 03.00.00 | Fecha de actualización: 01/06/20 | Autoría: Lourdes Rodríguez Morón |
|---|
Ubicación: 1.5.1 Mejora (tipo 3): La clase surfaceview muy importante y de complejidad no se explica adecuadamente. Esta clase es la recomendada por Android para la programación multimedia. Ubicación: En la sección 1.1. (recuadro Para saber más) Mejora (tipo 1): Hay dos enlaces que no funcionan que son los indicados de la siguiente forma:
- Puedes ver en funcionamiento de uno de los primeros videojuegos documentados de la historia siguiendo este enlace.
- En el siguiente enlace podrás comprobar cómo era el primer videojuego multijugador: Tenis para dos. Ubicación: 2.8 Mejora (tipo 2): El componente TabHost está obsoleto (legacy) Ubicación: 7.1, 7.2 Mejora (tipo 2): Añadir diseño de pantalla con la vista BluePrint, no sólo con la vista xml. Uso de la interfaz gráfica para el diseño de pantallas. Ubicación: 4. Mejora (tipo 1): Actualizar a la nueva versión de Android Studio Ubicación: 2.4, 2.5 Mejora (tipo 1): Actualizar: No referenciar j2me.
Actualizar: completar la tabla hasta android 9 Ubicación: 2.3 Mejora (tipo 1): El IDE más utilizado ya no es Eclipse, es Android Studio. Es al que Android (Google) da soporte. Ubicación: 2.5 Mejora (tipo 1): La tabla de versiones de Android hay que completarla hasta la última versión Android 9.0 Pie Ubicación: 2.5 Mejora (tipo 1): La actual máquina virtual de Android a cambiado a ART. Ubicación: Nodos del mapa Mejora (Mapa conceptual): Actualización en base a los nuevos contenidos. Ubicación: Tabla de contenidos Mejora (Orientaciones del alumnado): Actualización en base a los nuevos contenidos |
| Versión: 02.02.00 | Fecha de actualización: 05/07/16 | Autoría: Víctor Gil Rodríguez |
|---|
Ubicación: No especificada. Mejora (tipo 2): Adaptar los contenidos a Android Studio en todas las unidades Ubicación: Punto 2. Parrafo 2º Mejora (tipo 1): Dice: Samsung (el mayor proveedor en 2014), Apple, Huawei, Sony, ZTE, HTC, Blackberry), LG, Motorola, etc.
Debe decir: Samsung (el mayor proveedor en 2014), Apple, Huawei, Sony, ZTE, HTC, Blackberry, LG, Motorola, etc. Ubicación: 3.1.- Funcionalidades de Android. Mejora (tipo 1): El formato de fuente es distinto Ubicación: 3.1.- Funcionalidades de Android. Mejora (tipo 1): En el segundo parrafo dice:
Recepvión de mensajes tipo Push
debe decir:
Recepción de mensajes tipo Push Ubicación: No aparece mapa conceptual correcto. Mejora (Mapa conceptual): Aparece el mapa conceptual del tema 6, cuando deberia de aparecer el del tema 4 |
| Versión: 02.01.00 | Fecha de actualización: 05/01/15 | Autoría: Antonio José López Jiménez |
|---|
| Actualización de datos generales y características con las tendencias actuales. eliminación de detalles obsoletos (algunos marcados en desuso). Inclusión de pequeña introducción a Android Studio. |
| Versión: 02.00.00 | Fecha de actualización: 25/04/14 | Autoría: Víctor Gil Rodríguez |
|---|
| Nuevos contenidos actualizados con Android. |
| Versión: 01.00.00 | Fecha de actualización: 25/04/14 |
|---|
| Versión inicial de los materiales. |