Manual de Prácticas Programación Móvil

Descargar como pdf o txt
Descargar como pdf o txt
Está en la página 1de 171

MANUAL DE PRÁCTICAS DE LA

MATERIA

Desarrollo de Aplicaciones para Dispositivos


Móviles

Ingeniería en Tecnologías de la Información y


Comunicaciones

Elaborado por

Alejandro Guzmán Zazueta, Claudia Rodríguez Lemus


Dictamen <<CMPSC-XXX-XXXX >>

Adscrito(a) al Departamento de Sistemas y


Computación

Instituto Tecnológico de Roque


MANUAL DE PRÁCTICAS DE LA MATERIA “DESARROLLO DE APLICACIONES
PARA DISPOSITIVOS MÓVILES”
Carrera Ingeniería en Tecnologías de la Información y Comunicaciones
Elaborado por: Alejandro Guzmán Zazueta

OBJETIVO DE LA MATERIA

El principal objetivo de esta asignatura es que al final del curso los estudiantes sean
capaces de diseñar y construir aplicaciones para dispositivos móviles. Para alcanzar este
objetivo, los estudiantes tienen que desarrollar paso a paso una aplicación Android
completa.

Competencias específicas:

Aplica las metodologías y tecnologías emergentes para el desarrollo de aplicaciones


móviles que resuelvan problemáticas del entorno.

Competencias previas:

• Analiza y soluciona problemas informáticos y representa su solución mediante


herramientas de software orientado a objetos.
• Identifica y analiza necesidades de información para su representación, tratamiento y
automatización para la toma de decisiones.
• Crea y aplica los esquemas de bases de datos y tecnologías de conectividad para
generar aplicaciones en el tratamiento de la información.

Introducción.

El presente escrito plantea el desarrollo de prácticas de la Desarrollo de Aplicaciones para


Dispositivos Móviles Clave de la asignatura: AEB-1011 (Créditos 1-4-5) SATCA1Carrera: Ingeniería
Informática e Ingeniería en Tecnologías de la Información y Comunicaciones.
Esta asignatura aporta al perfil del egresado las competencias necesarias para el desarrollo de
aplicaciones enfocadas a los dispositivos móviles.
Tiene especial relevancia debido a la tendencia del uso generalizado de las tecnologías móviles en
los diversos ámbitos.

i
MANUAL DE PRÁCTICAS DE LA MATERIA “DESARROLLO DE APLICACIONES
PARA DISPOSITIVOS MÓVILES”
Carrera Ingeniería en Tecnologías de la Información y Comunicaciones
Elaborado por: Alejandro Guzmán Zazueta

Consiste en aplicar las herramientas de programación para el desarrollo de aplicaciones móviles


considerando la evolución del software y hardware.
Esta asignatura es integradora, ya que es posterior a las definidas en programación, ingeniería de
software y tratamiento de la información, por lo que permite conjuntar los conocimientos con
respecto al planteamiento y propuesta de soluciones a problemas del entorno.

Contenido
Unidad 1. Introducción a las Tecnologías de Móviles ................................................................................... 1
Practica 1. Instalación de Android Studio.................................................................................................. 2
Unidad 2. Arquitecturas y Entorno de Desarrollo ......................................................................................... 6
Práctica 2. Estructura de un Proyecto ....................................................................................................... 7
Práctica 3. Lenguaje de Programación Kotlin .......................................................................................... 15
Unidad 3. Desarrollo de Aplicaciones Móviles ............................................................................................ 42
Práctica 4. Uso de Layouts ...................................................................................................................... 43
Unidad 4. Administración de datos en dispositivos móviles ....................................................................... 62
Práctica 5. Bases de Datos en SQLite y Llenado de Controles ................................................................. 63
Práctica 6. Servicios Web ........................................................................................................................ 89
Práctica 7. Generación de PDF en Android ........................................................................................... 128
Práctica 8. Generación de una Gráficas en Android .............................................................................. 139
Práctica 9. Mapas y Marcas en Android ................................................................................................ 148
Práctica 10. Geolocalización en Tiempo Real Android .......................................................................... 158
Bibliografía ................................................................................................................................................ 168

ii
MANUAL DE PRÁCTICAS DE LA MATERIA “DESARROLLO DE APLICACIONES
PARA DISPOSITIVOS MÓVILES”
Carrera Ingeniería en Tecnologías de la Información y Comunicaciones
Elaborado por: Alejandro Guzmán Zazueta

Unidad 1. Introducción a las Tecnologías de Móviles

Competencia específica a desarrollar:

Conoce la evolución de los dispositivos móviles y de las tecnologías de conectividad móviles para
identificar los ambientes de desarrollo en esta área.

Subtema

1.1 Evolución de los dispositivos móviles.


1.2 Introducción a las tecnologías y herramientas móviles.
1.3 Tecnologías emergentes.
1.4 Tecnología de clientes ligeros: tecnología inalámbrica, redes de datos de radio, tecnología de
microondas, redes de radio móvil, asistentes personales digitales, tarjetas inteligentes.

Sugerencias Didácticas

Instalar y configurar Android Studio para desarrollar aplicaciones móviles.


El estudiante deberá plantear un proyecto a desarrollar durante la materia.

1
MANUAL DE PRÁCTICAS DE LA MATERIA “DESARROLLO DE APLICACIONES
PARA DISPOSITIVOS MÓVILES”
Carrera Ingeniería en Tecnologías de la Información y Comunicaciones
Elaborado por: Alejandro Guzmán Zazueta

PRACTICAS PROPUESTAS

Practica 1. Instalación de Android Studio

Objetivo

Instalación y configuración del Entorno de Desarrollo Integrado “IDE” de Android Studio

Introducción

El estudiante deberá descargar el instalador del IDE de Android Studio para poder practicar el
desarrollar aplicaciones móviles en Kotlin.

Correlación con los temas y subtemas del programa de estudio

La práctica apoya al tema 1.2. Introducción a las tecnologías y herramientas móviles, para que el
estudiante conozca las herramientas que proporciona el Entorno de Desarrollo Integrado “IDE”
para aplicaciones móviles de Android.

Material y equipo necesario

Computadora i3, i5 o i7 con mínimo de 8GB de Ram.


Acceso a Internet, porque se descargará 1GB para el instalador.

Metodología

1. Descarga Android Studio

2
MANUAL DE PRÁCTICAS DE LA MATERIA “DESARROLLO DE APLICACIONES
PARA DISPOSITIVOS MÓVILES”
Carrera Ingeniería en Tecnologías de la Información y Comunicaciones
Elaborado por: Alejandro Guzmán Zazueta

El primer paso es, obviamente, descargar el instalador. Está disponible oficialmente para Windows,
Mac y Linux, y encontrarás el enlace de descarga en su web oficial. La instalación será para la
versión de Windows, aunque muchas indicaciones te servirán para los otros sistemas operativos.

2. Inicia la instalación

Android Studio es una herramienta enormemente compleja, pero por suerte su instalación no lo
es. Aunque está disponible únicamente en inglés, lo cierto es que no hay mucha dificultad pues
en la mayoría de pantallas solo necesitas pulsar Next, o siguiente.

3. Configuración inicial

Lo primero que verás al abrir Android Studio por primera vez es una pantalla como la siguiente.
En ella simplemente se te pregunta si quieres importar la configuración de una versión anterior.
Generalmente Android Studio detectará la configuración por sí mismo, y si no tienes ninguna
configuración anterior guardada se marcará Do not import settings, o no importar configuración.

4. Descarga los componentes

¿Anteriormente instalar Android Studio era un lío? Parte de la culpa la tenía Java y el SDK de
Android, pero ahora el proceso es automático. Si elegiste la instalación estándar, Android Studio
elige por ti los componentes que necesita descargar.

NOTA: Se deberá instalar la API de acuerdo a la versión del sistema operativo en que se ejecutará
la App.

5. Habilite la cuenta de desarrollador de su celular Android habilitando la depuración por USB, en


seguida conecte el celular a la computadora y ejecute la App de Hola Mundo en el dispositivo.

Pregunta de análisis en el aula

Que API instalo e indique el porcentaje de dispositivos en los que se podrá ejecutar la App.

3
MANUAL DE PRÁCTICAS DE LA MATERIA “DESARROLLO DE APLICACIONES
PARA DISPOSITIVOS MÓVILES”
Carrera Ingeniería en Tecnologías de la Información y Comunicaciones
Elaborado por: Alejandro Guzmán Zazueta

Reporte del Estudiante

Presentación del trabajo

a.) Reporte escrito: El estudiante deberá presentar un reporte escrito explicando las ventanas del
proceso de instalación de Android Studio. Este deberá incluir portada e índice, así como
referencias bibliográficas.
b.) Rubrica de evaluación

CATEGORÍA 4 Sobresaliente 3 Notable 2 Aprobado 1 Insuficiente

El reporte detallado es El reporte incluye El reporte incluye la Al reporte le falta


presentado toda la información mayoría de la información requerida
ordenadamente que requerida y es información requerida y es difícil de leer.
El Reporte incluye toda la legible. y es legible.
información requerida.

Todos los párrafos La mayor parte de Los párrafos incluyen La estructura del
incluyen una los párrafos incluye información párrafo no estaba
Construcción de introducción, una introducción, relacionada pero no clara y las oraciones
Párrafos explicaciones o explicaciones o fueron generalmente no estaban
detalles y una detalles y una bien organizados. generalmente
conclusión. conclusión. relacionadas.

No hay errores de Casi no hay errores Unos pocos errores Muchos errores de
gramática, ortografía o de gramática, de gramática, gramática, ortografía o
puntuación. ortografía o ortografía o puntuación.
Redacción puntuación. puntuación.

Todos los temas Todos los temas Todos los temas Uno o más temas no
tratados y todas las tratados y la mayor tratados y la mayor están tratados.
Cantidad de preguntas fueron parte de las parte de las
Información contestadas en al preguntas fueron preguntas fueron
menos 2 oraciones. contestadas en al contestadas en 1
menos 2 oraciones. oración.

La información está La información da La información da La información tiene


claramente respuesta a las respuesta a las poco o nada que ver
relacionada con el preguntas preguntas con las preguntas
Calidad de
tema principal y principales y 1-2 principales, pero no planteadas.
Información proporciona varias ideas secundarias da detalles y/o
ideas secundarias y/o y/o ejemplos. ejemplos.
ejemplos.

4
MANUAL DE PRÁCTICAS DE LA MATERIA “DESARROLLO DE APLICACIONES
PARA DISPOSITIVOS MÓVILES”
Carrera Ingeniería en Tecnologías de la Información y Comunicaciones
Elaborado por: Alejandro Guzmán Zazueta

La información está La información está La información está La información


muy bien organizada organizada con organizada, pero los proporcionada no
con párrafos bien párrafos bien párrafos no están parece estar
Organización redactados y con redactados. bien redactados. organizada.
subtítulos.

5
MANUAL DE PRÁCTICAS DE LA MATERIA “DESARROLLO DE APLICACIONES
PARA DISPOSITIVOS MÓVILES”
Carrera Ingeniería en Tecnologías de la Información y Comunicaciones
Elaborado por: Alejandro Guzmán Zazueta

Unidad 2. Arquitecturas y Entorno de Desarrollo

Competencia específica a desarrollar:

Conoce y aplica los diferentes sistemas operativos, arquitecturas y entornos de programación


para el desarrollo de aplicaciones móviles.

Subtema

2.1 Sistemas operativos para dispositivos ligeros


2.2 Arquitecturas
2.3 Entorno de desarrollo
2.4 Requerimientos de los dispositivos ligeros
2.5 Lenguajes de programación
2.6 Configuraciones
2.7 Perfiles

Sugerencias Didácticas

Conocer la estructura de un proyecto en Android estudio.


Identificar las herramientas del entorno de desarrollo.
El estudiante deberá presentar avance del proyecto a desarrollar durante la materia.
Programar diferentes aplicaciones móviles para familiarizarse con la sintaxis del lenguaje de
programación Kotlin.

6
MANUAL DE PRÁCTICAS DE LA MATERIA “DESARROLLO DE APLICACIONES
PARA DISPOSITIVOS MÓVILES”
Carrera Ingeniería en Tecnologías de la Información y Comunicaciones
Elaborado por: Alejandro Guzmán Zazueta

Práctica 2. Estructura de un Proyecto

Objetivo
El estudiante conocerá la estructura de un proyecto creado en el Entorno de Desarrollo Integrado
de Android Studio.

Introducción
Esta práctica tiene como fin comprender la estructura de archivos de un proyecto en Android
Studio. Esto nos permitirá investigar a fondo la lógica de construcción de una aplicación.

También estudiaremos como está estructurado el archivo AndroidManifest.xml, que contiene la


carpeta «res», veremos la utilidad de los archivos de diseño, los archivos R.java. Y finalmente
daremos un vistazo al código fuente de kotlin.

Correlación con los temas y subtemas del programa de estudio


La práctica apoya al tema 1.2. Introducción a las tecnologías y herramientas móviles, para que el
estudiante conozca la estructura de un proyecto y conocer las herramientas que proporciona el
Entorno de Desarrollo Integrado “IDE” de Android Studio.

Material y equipo necesario


Computadora i3, i5 o i7 con mínimo de 8GB de Ram.
Acceso a Internet, para la creación de nuevo proyecto en Android Studio.

7
MANUAL DE PRÁCTICAS DE LA MATERIA “DESARROLLO DE APLICACIONES
PARA DISPOSITIVOS MÓVILES”
Carrera Ingeniería en Tecnologías de la Información y Comunicaciones
Elaborado por: Alejandro Guzmán Zazueta

Metodología
Crear un proyecto nuevo en Android Studio y revisar su estructura de acuerdo a la siguiente
información:

Estructura de un Proyecto en Android Studio

Cada proyecto en Android Studio contiene uno o más módulos con archivos de código fuente y
archivos de recursos. Entre los tipos de módulos se incluyen los siguientes:

• módulos de apps para Android


• módulos de bibliotecas
• módulos de Google App Engine

De manera predeterminada, Android Studio muestra los archivos de tu proyecto en la vista de


proyectos de Android, como se muestra en la figura 1. Esta vista se organiza en módulos para
proporcionar un rápido acceso a los archivos de origen clave de tu proyecto.

Figura 1

Estructura de proyecto

Nota: Carpetas y archivos de la estructura de un proyecto, (Developers, 2023).

8
MANUAL DE PRÁCTICAS DE LA MATERIA “DESARROLLO DE APLICACIONES
PARA DISPOSITIVOS MÓVILES”
Carrera Ingeniería en Tecnologías de la Información y Comunicaciones
Elaborado por: Alejandro Guzmán Zazueta

Todos los archivos de compilación son visibles en el nivel superior de Secuencias de comando de
Gradle y cada módulo de la aplicación contiene las siguientes carpetas (Developers, 2023):

• manifests: contiene el archivo AndroidManifest.xml. En este archivo se controlan los


permisos para el acceso a internet, GPS entre otros.
• java: contiene los archivos de código fuente de Java o Kotlin.
• res: Contiene todos los recursos, como diseños XML, cadenas de IU e imágenes de mapa
de bits.

Especificaciones (Ardións, 2015):

• manifests: aquí podemos encontrar el AndroidManifest. En este archivo se controlan los


permisos y acceso a recursos del dispositivo. Directorio “/src/main/AndroidManifest.xml”.

• java: en este directorio encontraremos los ficheros.java con el código fuente. Ubicación:
“/src/main/java/”.

• res:

Ø anim: archivos XML que definen las animaciones. Directorio: “/src/main/res/anim”.


Ø drawable: en este directorio se encuentran las imágenes en formato PNG o JPEG (Google
tiene preferencia por las imágenes PNG). Su ubicación es: “/src/main/res/drawable”.
Ø layout: aquí se encuentran todos los layouts de nuestro proyecto. Ya hemos visto qué es
un layout y qué tipos de layouts existen. Se ubican en el directorio “/src/main/res/layout”.
Ø menu: archivos XML que definen las plantillas de los menus del proyecto
“/src/main/res/menu”.
Ø mipmap: contiene los iconos de la aplicación con sus diferentes resoluciones.
Anteriormente se encontraban en el directorio drawable, pero en las últimas versiones de
Android Studio han sido movidos al directorio mipmap. Ubicación
“src/main/res/mipmap/”.

9
MANUAL DE PRÁCTICAS DE LA MATERIA “DESARROLLO DE APLICACIONES
PARA DISPOSITIVOS MÓVILES”
Carrera Ingeniería en Tecnologías de la Información y Comunicaciones
Elaborado por: Alejandro Guzmán Zazueta

Ø raw: en esta carpeta ubicamos los archivos multimedia descomprimidos, de esta manera
Android sabe que no debe procesarlos más tarde. Se encuentra en el directorio
“/src/main/res/raw”.
Ø values: archivos XML que definen valores constantes. Ya hemos detallado qué es y para qué
sirve la carpeta Values, así que solo haremos un pequeño resumen. Se encuentra en:
“src/main/res/values”.
§ strings.xml: este XML contiene las cadenas de texto de nuestra aplicación. Más adelante
veremos cómo nos facilita la tarea de traducir nuestra aplicación a otros idiomas
cómodamente.Ubicación “/src/main/res/values/strings.xml”.
§ styles.xml: en este fichero XML se definen los estilos de nuestro proyecto. Ubicación
“/src/main/res/values/styles.xml”.
§ color.xml: aquí se definen los colores que usaremos en el diseño de nuestra aplicación.
Ubicación “/src/main/res/values/color.xml”.
Ø gradle: por último, encontramos los ficheros gradle de Android Studio. En el módulo de
gradle agregamos las dependencias a librerías que deseamos manejar en nuestro proyecto.

La estructura del proyecto para Android en el disco difiere de esta representación plana. Para ver
la estructura de archivos real del proyecto, selecciona Project en la lista desplegable Project.

También puedes personalizar la vista de los archivos del proyecto para concentrarte en aspectos
específicos del desarrollo de tu app.

10
MANUAL DE PRÁCTICAS DE LA MATERIA “DESARROLLO DE APLICACIONES
PARA DISPOSITIVOS MÓVILES”
Carrera Ingeniería en Tecnologías de la Información y Comunicaciones
Elaborado por: Alejandro Guzmán Zazueta

Interfaz de usuario

La ventana principal de Android Studio consta de varias áreas lógicas que se muestran en la figura
2 (Developers, 2023).

Figura 2

Área de trabajo de Android estudio

Nota: área de trabajo principal de Android Studio, (Developers, 2023)

1. La barra de herramientas te permite realizar una gran variedad de acciones, como la


ejecución de tu app y el inicio de herramientas de Android.
2. La barra de navegación te ayuda a explorar tu proyecto y abrir archivos para editar.
Proporciona una vista más compacta de la estructura visible en la ventana Project.

11
MANUAL DE PRÁCTICAS DE LA MATERIA “DESARROLLO DE APLICACIONES
PARA DISPOSITIVOS MÓVILES”
Carrera Ingeniería en Tecnologías de la Información y Comunicaciones
Elaborado por: Alejandro Guzmán Zazueta

3. La ventana del editor es el área donde puedes crear y modificar código. Según el tipo de
archivo actual, el editor puede cambiar. Por ejemplo, cuando se visualiza un archivo de
diseño, el editor muestra el editor de diseño.
4. La barra de la ventana de herramientas se extiende alrededor de la parte externa de la
ventana del IDE y contiene los botones que te permiten expandir o contraer ventanas de
herramientas individuales.
5. Las ventanas de herramientas te permiten acceder a tareas específicas, como la
administración de proyectos, las búsquedas, los controles de versión, etc. Puedes
expandirlas y contraerlas.
6. En la barra de estado, se muestra el estado de tu proyecto y del IDE en sí, como también
cualquier advertencia o mensaje.

Clase R.java
El archivo R.java es un archivo que se autogenera dentro de la carpeta build, para linkear todos los
recursos que tenemos en nuestro proyecto al código Java o Kotlin.

Si abres el archivo podremos ver un código similar a este:

/*AUTO-GENERATED FILE. DO NOT MODIFY. *


* This class was automatically generated bythe
* aapt tool from the resource data itfound. It
* should not be modified by hand. */

package com.TUPAQUETE.test;

public final class R {


public static final class attr {
}
public static final class dimen {
public static final int activity_horizontal_margin=0x7f040000;
publicstaticfinalint activity_vertical_margin=0x7f040001;
}
public static final class drawable {
publicstaticfinalint ic_launcher=0x7f020000;
}
public static final class id {
public static final int action_settings=0x7f080000;
}

12
MANUAL DE PRÁCTICAS DE LA MATERIA “DESARROLLO DE APLICACIONES
PARA DISPOSITIVOS MÓVILES”
Carrera Ingeniería en Tecnologías de la Información y Comunicaciones
Elaborado por: Alejandro Guzmán Zazueta

public static final class layout {


publicstaticfinalint activity_my=0x7f030000;
}
public static final class menu {
publicstaticfinalint my=0x7f070000;
}
public static final class string {
public static final int action_settings=0x7f050000;
public static final int app_name=0x7f050001;
public static final int hello_world=0x7f050002;
}
public static final class style {
/** Customize your theme here.
*/
public static final int AppTheme=0x7f060000;
}
}

Como ves, la clase R contiene clases anidadas que representan todos los recursos de nuestro
proyecto. Cada atributo tiene una dirección de memoria asociada referenciada a un recurso en
específico. Por ejemplo, la clase string posee el atributo hello_world, el cual representa nuestro
TextView en la actividad principal. Este recurso está ubicado en la posición0x7f050002.

No modifiques el archivo R.java, se actualiza automáticamente al añadir un nuevo elemento al


proyecto.

Pregunta de análisis en el aula

¿Cuál es la ubicación de la interfaz de la app en el proyecto?


¿Cuál es la ubicación de código de Kotlin o java?
¿Para qué sirve el archivo AndroidManifest?
¿Qué finalidad tiene la clase R.java?

Reporte del Estudiante


Presentación del trabajo

a.) Reporte escrito: El estudiante deberá presentar un reporte escrito en forma de resumen
explicando la funcionalidad de las diferentes opciones que se encuentra en la estructura de un
13
MANUAL DE PRÁCTICAS DE LA MATERIA “DESARROLLO DE APLICACIONES
PARA DISPOSITIVOS MÓVILES”
Carrera Ingeniería en Tecnologías de la Información y Comunicaciones
Elaborado por: Alejandro Guzmán Zazueta

proyecto en Android Studio. Este deberá incluir portada e índice, así como referencias
bibliográficas.
b.) Rubrica de evaluación
Categoría 5 Excelente 4 Bueno 3 Regular 2 Deficiente 1 Malo
Demasiado
Demasiado
Se ajustó a la cantidad Se sobrepaso uno o Tres o más extenso, no
Resume según lo corto o
de páginas o palabras dos párrafos más párrafos de supo eliminar
solicitado. extenso el
descritas. de lo solicitado. más o menos. párrafos o
resumen.
frases.

Varios textos sin


Las mayorías de los Resume, pero Textos sin
relación, no
Excelente estructura, textos se falta más cohesión,
utiliza palabras
Coherencia y Sentido. orden y coherencia en complementa, información inicia párrafos
o frases para
el resumen. algún párrafo no para darle de manera
enlazar las
encaja. sentido. incorrecta.
ideas.

La mayoría de
Varios títulos
Justificación del párrafo, Algún párrafo no los párrafos sin No agregó
sin resaltar,
Estilo, formato. espaciado, separación justificado, título justificar, no ningún estilo,
párrafos sin
de textos, etc. sin resaltar, etc. agrega color, justificación.
justificar.
espacio.

Más de 4 faltas Más de 10


Errores 3 a 4faltas
ortográficas faltas
Ningún error ortográfico gramaticales ortográficas.
Ortografía y gramática. bastantes ortográficas o
o de gramática. mínimos. 2 o 3 Varios errores
errores mucho error
faltas ortográficas. gramaticales.
gramaticales. gramatical.

Muestra la
Faltó pequeños
El resumen está idea principal,
detalles para Muy corto o Falta mucha
Completo completo en la cantidad aunque
comprender más lo extenso. información.
de palabras indicadas. faltaron
detallado.
detalles.

14
MANUAL DE PRÁCTICAS DE LA MATERIA “DESARROLLO DE APLICACIONES
PARA DISPOSITIVOS MÓVILES”
Carrera Ingeniería en Tecnologías de la Información y Comunicaciones
Elaborado por: Alejandro Guzmán Zazueta

Práctica 3. Lenguaje de Programación Kotlin

Objetivo
El estudiante conocerá la sintaxis del lenguaje de programación Kotlin.

Introducción
Esta práctica tiene como fin comprender el lenguaje de programación Kotlin.

Correlación con los temas y subtemas del programa de estudio


La práctica apoya al tema 1.2. Introducción a las tecnologías y herramientas móviles, para que el
estudiante conozca el lenguaje de programación Kotlin.

Material y equipo necesario


Computadora i3, i5 o i7 con mínimo de 8GB de Ram.
Acceso a Internet, para la creación de nuevo proyecto en Android Studio.

Metodología
Revisar la siguiente documentación y al final realizar el ejercicio propuesto:

15
MANUAL DE PRÁCTICAS DE LA MATERIA “DESARROLLO DE APLICACIONES
PARA DISPOSITIVOS MÓVILES”
Carrera Ingeniería en Tecnologías de la Información y Comunicaciones
Elaborado por: Alejandro Guzmán Zazueta

Sentencias Bloques y comentarios

Sentencias

• En Kotlin, las sentencias se escriben una en cada línea.


• No es necesario incluir un; al final (podemos seguir usando el; pero no es necesario al
contrario de Java).

Bloques

• Agrupan instrucciones.
• Definen el ámbito de las variables.
• En kotlin las llaves {y} para delimitarlos.

Comentarios en Kotlin

• De una línea, //
• De multiples líneas, /* comentario */
• Se pueden anidar, así están balanceados /*/**/*/
• Los comentarios en kotlin se pueden anidar.

Operador de Asignación

- Copia el contenido de la parte derecha en la parte izquierda


- No devuelve valor
- Hay versiones compuestas, como +=

X=X+1
ó
x += 1

16
MANUAL DE PRÁCTICAS DE LA MATERIA “DESARROLLO DE APLICACIONES
PARA DISPOSITIVOS MÓVILES”
Carrera Ingeniería en Tecnologías de la Información y Comunicaciones
Elaborado por: Alejandro Guzmán Zazueta

Operadores Aritméticos Disponibles en Kotlin


Los operadores aritméticos de Kotlin los puede observar en la figura 3:
Figura 3

Operadores aritméticos

Nota: Operadores aritmeticos de Kotlin, (Jaureguialzo, 2017)

Valores numéricos y lógicos


Los tipos de datos numéricos disponibles en Kotlin los puede observar en la figura 4:

Figura 4

Tipos de datos numéricos en Kotlin

Nota: tipos de datos numéricos en Kotlin, (Jaureguialzo, 2017)

17
MANUAL DE PRÁCTICAS DE LA MATERIA “DESARROLLO DE APLICACIONES
PARA DISPOSITIVOS MÓVILES”
Carrera Ingeniería en Tecnologías de la Información y Comunicaciones
Elaborado por: Alejandro Guzmán Zazueta

Operadores: relacionales y lógicos

Figura 5

Operadores Relacionales en Kotlin

Nota: Operadores en Kotlin, (Jaureguialzo, 2017)

Nota:
== estamos comparando contenido de los objetos
=== Triple igual compara si las referencias son las mismas es decir si se trata del mismo
objeto.

Operadores lógicos

Figura 6

Operadores Lógicos en Kotlin

Nota: Operadores Lógicos del lenguaje de programación Kotlin, (Jaureguialzo, 2017)

18
MANUAL DE PRÁCTICAS DE LA MATERIA “DESARROLLO DE APLICACIONES
PARA DISPOSITIVOS MÓVILES”
Carrera Ingeniería en Tecnologías de la Información y Comunicaciones
Elaborado por: Alejandro Guzmán Zazueta

19
MANUAL DE PRÁCTICAS DE LA MATERIA “DESARROLLO DE APLICACIONES
PARA DISPOSITIVOS MÓVILES”
Carrera Ingeniería en Tecnologías de la Información y Comunicaciones
Elaborado por: Alejandro Guzmán Zazueta

Resumen de cómo podemos expresar los literales numéricos en Kotlin


Figura 7

Literales numéricas en Kotlin

Nota: representación de literales numéricas en Kotlin

Nota: Kotlin no hace conversiones automáticas entre tipos esto ayuda a evitar errores.
Tenemos que expresar la expresión de forma explícita.
Ejemplos:
val b : Byte = 1 //ok
val i : Int = b //error
---------------------------------------------
val i :Int = b.toInt() // Ok: expresada explícitamente

Valores Opcionales
typesafe null
Una característica importante de Kotlin es que maneja seguridad en nulos. Esto es algo que varios
lenguajes han estado implementando últimamente.

Normalmente, una variable de cualquier tipo que sea objeto, acepta null. En Kotlin no es así; para
que una variable acepte null, se necesita especificar de esa forma. Esto no compila:

var x:String = "hola"


x = null

20
MANUAL DE PRÁCTICAS DE LA MATERIA “DESARROLLO DE APLICACIONES
PARA DISPOSITIVOS MÓVILES”
Carrera Ingeniería en Tecnologías de la Información y Comunicaciones
Elaborado por: Alejandro Guzmán Zazueta

Porque x ha sido definida como de tipo String, y no acepta nulos. Para que acepte nulos, se tiene
que definir así:

var x:String? = "hola"


x = null

Los tipos opcionales se pueden usar en parámetros de funciones, tipos de retorno y declaraciones
locales. Cuando se tiene un valor que puede ser null, no se puede usar de manera directa. Hay que
verificar que el objeto exista; esto se puede lograr de varias formas:

var x:String? = "hola"


if (x != null) {
//Aquí dentro, x ya se considera String

Esto nos evita dolores de cabeza porque en vez de tener que lidiar con NullPointerException en
tiempo de ejecución, estos errores se detectan en tiempo de compilación. Sin embargo, Kotlin
tiene un gran problema con esto: integrado con la seguridad de nulos, viene un mecanismo para
desactivarla por completo: Si se agrega una doble admiración al final de una variable opcional, el
compilador deshabilita las verificaciones de nulos y se porta como lo haría el compilador de Java,
permitiendo que sea nulo donde sea:

var x:String? = null


println(x!!.length) //Truena en runtime

//Por otro lado, si se tiene esto...


fun foo(s:String) = println("Hey, $s")

foo(x) //No compila


foo(x!!) //Compila, y truena en runtime

21
MANUAL DE PRÁCTICAS DE LA MATERIA “DESARROLLO DE APLICACIONES
PARA DISPOSITIVOS MÓVILES”
Carrera Ingeniería en Tecnologías de la Información y Comunicaciones
Elaborado por: Alejandro Guzmán Zazueta

Conversiones

Para todos los tipos de datos se tienen tipos de conversiones, solo es necesario poner la variable
con punto y el tipo de dato al que la queremos convertir:

toByte() : Byte

toShort(): Short

toInt() : Int

toLong() : Long

toFloat(): Float

toDouble(): Double

toChar(): Char

toString(): String

por ejemplo:

var num : Int = 32

var cadena : String = num.ToString()

Valores lógicos en Kotlin

(Kotlin proporciona el tipo Booleano para la asignación de True o False)

val orangesAreOrange = true

val turnipsAreDeliciouos: Boolean = false

22
MANUAL DE PRÁCTICAS DE LA MATERIA “DESARROLLO DE APLICACIONES
PARA DISPOSITIVOS MÓVILES”
Carrera Ingeniería en Tecnologías de la Información y Comunicaciones
Elaborado por: Alejandro Guzmán Zazueta

Declaración de variables y constantes

Variables y constantes en Kotlin


Ejemplo
val a : Int = 1 //inmediatamente asignado
val b = 2 //’Int’ type is inferred
val c: Int //Tipo requerido cuando no se inicializo es prohibido
c = 3 // asignación diferida
//Montables
var x = 5// Typo Int es inferido
x += 1

Nota: val las variables son de solo lectura (constantes)


var son mutables podemos cambiar el valor siempre que queramos.
Recomendación: Colocar todas las variables en val y cambiar val cuando sea necesario modificar
el valor pues ayuda a evitar errores

Inferencia de tipos en kotlin (El compilador es capaz de deducir el tipo de variable)

val b = 2 //en este caso b seria de tipo Int

También podemos expresar el tipo de forma explícita colocando la sintaxis

Val c: Int

c=3

Salida por consola ejemplos:

var hora = 9

23
MANUAL DE PRÁCTICAS DE LA MATERIA “DESARROLLO DE APLICACIONES
PARA DISPOSITIVOS MÓVILES”
Carrera Ingeniería en Tecnologías de la Información y Comunicaciones
Elaborado por: Alejandro Guzmán Zazueta

print(“Son las ${hora} en punto”)

println(“, A cenar”)

Tipos de datos anulables

• En Kotlin, el sistema de tipos distingue entre referencias que pueden almacenar null y a las
que no.
• Este mecanismo hace explicito el hecho de que una variable puede ser nula.
• Permite al compilador detectar el uso de referencias nulas.
• ¿Se declaran poniendo? Detrás del nombre del tipo

Ejemplo de variables anulables


var a : String =”abc”
a = null //error de compilación
var b : String? = “abc”
b = null //ok
val l = a.length //ok
val l = b.length //error: variable ‘b’ puede ser nula

Acceso de variables anulables (cuando las hemos declarado nulas)

El manejo de la variables que aceptan valores nulos, lo puede observar en la figura 8:

Figura 8

Variables anulables

24
MANUAL DE PRÁCTICAS DE LA MATERIA “DESARROLLO DE APLICACIONES
PARA DISPOSITIVOS MÓVILES”
Carrera Ingeniería en Tecnologías de la Información y Comunicaciones
Elaborado por: Alejandro Guzmán Zazueta

Nota: Acceso a variables que aceptan nulos, (Jaureguialzo, 2017)

Clases en Kotlin

Para crear una clase en Kotlin, tienes que usar la palabra reservada class. Por ejemplo, una clase
llamada Person:

class Person {

Agregando Propiedades
Una clase generalmente tiene propiedades y función miembro (también llamados métodos).
Agreguemos dos propiedades a la clase Person, name de tipo String y age de tipo Int.

var name: String = ""


var age: Int = 0

Debemos usar la palabra reservada var. Sin embargo, si quieres que tu variable sea una variable de
solo lectura/una única asignación, mejor utiliza la palabra reservada val.

Valores Opcionales uno de los puntos más importantes en android

25
MANUAL DE PRÁCTICAS DE LA MATERIA “DESARROLLO DE APLICACIONES
PARA DISPOSITIVOS MÓVILES”
Carrera Ingeniería en Tecnologías de la Información y Comunicaciones
Elaborado por: Alejandro Guzmán Zazueta

Variables NULL

Por el bien de la seguridad null, Kotlin también hace una distinción entre variables que pueden ser
null y variables que nunca pueden ser null. En nuestro ejemplo previo, ambas variables name y age
nunca pueden ser null. Si son null, el compilador emitirá un error.

Para crear una variable que puede contener null, se necesita añadir un ? después del tipo de la
variable. Por ejemplo:

var college: String? = null

Crear una instancia de clase

Para crear una instancia es bastante sencillo, solo le asignamos a una variable una clase y listo
var jake = Person()

No, Kotlin no tiene la palabra reservada new. Una vez que la instancia ha sido creada, puedes
accesar a sus propiedades de la misma forma que lo harías en Java:

jake.name = "Jake Hill"


jake.age = 24
jake.college = "Stephen's College

26
MANUAL DE PRÁCTICAS DE LA MATERIA “DESARROLLO DE APLICACIONES
PARA DISPOSITIVOS MÓVILES”
Carrera Ingeniería en Tecnologías de la Información y Comunicaciones
Elaborado por: Alejandro Guzmán Zazueta

Constructores

Inicializando las propiedades individuales de nuestra instancia en la forma en que lo acabamos de


hacer no es una buena Ejercicio en la codificación. Una mejor forma de hacer ésto sería utilizando
un constructor. La sintaxis de Kotlin para crear tal constructor es muy compacta:

class Person(var name: String, var age: Int, var college: String?) {

}
Nota: si no se tiene nada que agregar a tu clase, no necesitas las llaves. El siguiente
código funciona bien:
class Person(var name: String, var age: Int, var college: String?)

var jake = Person("Jake Hill", 24, "Stephen's College")

Estructuras de control

Alternativa múltiple: when

Evalúa una variable contra distintos valores y ejecuta las sentencias correspondientes, su
funcionamiento po puede observar en la figura 9:

Características de when

1. Puede utilizarse como sentencia o expresión


2. Si se usa como expresión, el resultado será de la rama seleccionada
3. Sil la rama es un bloque, se asignará el valor de la última expresión
4. Si se usa como expresión debe llevar else

27
MANUAL DE PRÁCTICAS DE LA MATERIA “DESARROLLO DE APLICACIONES
PARA DISPOSITIVOS MÓVILES”
Carrera Ingeniería en Tecnologías de la Información y Comunicaciones
Elaborado por: Alejandro Guzmán Zazueta

Figura 9

Instrucción when

Nota: Instrucción when para evaluar varias alternativas, esta instrucción es similar al switch de otros lenguajes, (Jaureguialzo,
2017)

En un when podemos evaluar múltiples casos separándolos por coma

Ejemplo

when (x){

0,1- > print(“x == 0 or x == 1”)

Else ->print(“otherwise)

Los valores contra los que evaluamos una constante puede ser cualquier expresión

when (x){

parseInt(s)-> print(“s encodes x”)

else-> print(“s does not encode x”)

Podemos evaluar rangos utilizando IN

28
MANUAL DE PRÁCTICAS DE LA MATERIA “DESARROLLO DE APLICACIONES
PARA DISPOSITIVOS MÓVILES”
Carrera Ingeniería en Tecnologías de la Información y Comunicaciones
Elaborado por: Alejandro Guzmán Zazueta

when (x){

In 1..10 -> print(x is in the range)

In validNumbers -> print (“x is valid”)

¡in 10..20 ->print(“x is outside the range”)

Else -> print (none of the above)

Podemos evaluar si una variable es de tipo concreto utilizando is

Ejemplo

fun hasPrefix (x: Any)= when (x){

Is String -> x.startWith(“prefix”)

Else -> false

Estructura de control simple If


Ejemplo de la estructura
If(condicion){
Sentencia1
Sentencia2
}

Sentencia 1 y 2 se ejecutan si la
condición se evalúa a true
También se puede incluir el else
cuando la condición se evalué a
false.

29
MANUAL DE PRÁCTICAS DE LA MATERIA “DESARROLLO DE APLICACIONES
PARA DISPOSITIVOS MÓVILES”
Carrera Ingeniería en Tecnologías de la Información y Comunicaciones
Elaborado por: Alejandro Guzmán Zazueta

En kotlin el if es una variable el cual es decir se puede asignar a una variable


Por ejemplo
var a = 6;
var b = 8;
val max: Int = if (a>b){
a
}else{
b
} //Las ramas pueden ser bloques
Toast.makeText(this, "el mayor es $max", Toast.LENGTH_SHORT).show()
//La última expresión será el valor que asigne el valor que asigne

Operaciones con Rangos

Tenemos disponibles los siguientes operadores:


Punto punto (..) Este operador nos permitirá crear rangos cerrados punto a punto.
Until Tenemos posibilidad escribir un rango abierto con until
downTo Genera un rango descendente
Step nos permite controlar variaciones
Resumiendo las operaciones con rangos las puede observar en la figura 10:

30
MANUAL DE PRÁCTICAS DE LA MATERIA “DESARROLLO DE APLICACIONES
PARA DISPOSITIVOS MÓVILES”
Carrera Ingeniería en Tecnologías de la Información y Comunicaciones
Elaborado por: Alejandro Guzmán Zazueta

Figura 10

Operaciones con rangos

Nota: Resumen de las operaciones con rangos

Ejemplos utilizando rangos


If(i in 1..10){//equivalente a i>=1&&i<=10
println(i)
}
For(i in 1..4) print(i) //prints “1234”
For (i in 4 downTo 1) print(i) //prints “4,3,2,1”
For(i in 1 until 10){ //1,2,3,4,5,6,7,8,9
println(i)
}
//Podemos utilizar los rangos para controlar las repeticiones de los bucles.

Repetitivas

En kotlin tenemos tres tipos repetitivas, las cuales las puede observar en la figura11:

31
MANUAL DE PRÁCTICAS DE LA MATERIA “DESARROLLO DE APLICACIONES
PARA DISPOSITIVOS MÓVILES”
Carrera Ingeniería en Tecnologías de la Información y Comunicaciones
Elaborado por: Alejandro Guzmán Zazueta

Figura 11

Estructuras Repetitivas

Nota: Tres tipos de repetitivas en Kotlin

For es una repetitiva distinta en kotlin no se maneja de la misma manera que en Java pues recorre
los intervalos por colecciones, While y do-While tienen el mismo funcionamiento que en Java.

Declaración de While

Ejecutará el cuerpo del Bucle mientras la condición sea TRUE

Ejemplo:
while(x>0){
x---
}

Declaración de do-While

32
MANUAL DE PRÁCTICAS DE LA MATERIA “DESARROLLO DE APLICACIONES
PARA DISPOSITIVOS MÓVILES”
Carrera Ingeniería en Tecnologías de la Información y Comunicaciones
Elaborado por: Alejandro Guzmán Zazueta

Ejemplo:
Do{
Val y = retrieveData()
}while(y ¡= null)

La única diferencia que se tiene


con respecto a Java es que desde
la declaración del while tenemos
acceso a las variables declaradas
dentro del bucle.

Se ejecutará mientras la condición sea cierta, pero en este caso la condición se evalúa al final, pero
al menos en el cuerpo del bucle se habrá ejecutado una vez.

Declaración de for
Sintaxis
for(ítem in colección) sentencia
Recorre la colección y a cada vuelta del bucle proporciona acceso a cada uno de los
elementos en la variable ítem.
Ejemplo:
for (ítem: Int in ints){
Println (item)
}
Recorrido de un array con índices
Si queremos hacer un recorrido dependiendo a la posición del elemento podmeos recurrir
a la propiedad índices del elemento.

33
MANUAL DE PRÁCTICAS DE LA MATERIA “DESARROLLO DE APLICACIONES
PARA DISPOSITIVOS MÓVILES”
Carrera Ingeniería en Tecnologías de la Información y Comunicaciones
Elaborado por: Alejandro Guzmán Zazueta

for(i in array.indices){
Printl(array[i])
}
Transferencia de control

• Se puede poner break dentro de un bucle para cortar la repetición actual y forzar a que el
bucle termine.
• Se puede utilizar continue dentro de un bucle para terminar la repetición actual y pasar a
la siguiente.
• Se pueden utilizar etiquetas para definir a quien afecta un posible break o continue.

(Jaureguialzo, 2017)

Manejo de Errores usando Excepciones

Existe una regla de oro en el mundo de la programación: en los programas ocurren errores. Esto
es sabido, pero ¿Qué sucede realmente después de que ha ocurrido el error?

¿Cómo se maneja el error? ¿Quién lo maneja?, ¿Puede recuperarlo el programa?.

El lenguaje Kotlin utiliza excepciones para proporcionar capacidades en el manejo de errores. El


término excepción es una forma corta de la expresión “suceso excepcional” y puede definirse
como:

“Una excepción es un evento que ocurre durante la ejecución del programa que interrumpe el
flujo normal de las sentencias”
La captura de errores se realiza incluyendo el código que puede potencialmente contener un
error (o provocar una excepción) entre las llaves de la sentencia try, como en el siguiente código:

try

34
MANUAL DE PRÁCTICAS DE LA MATERIA “DESARROLLO DE APLICACIONES
PARA DISPOSITIVOS MÓVILES”
Carrera Ingeniería en Tecnologías de la Información y Comunicaciones
Elaborado por: Alejandro Guzmán Zazueta

{
// Se ejecuta algo que puede producir una excepción
}
catch (Exception e)
{
// Manejo de una excepción
}
finally
{
// Código a ejecutar haya o no excepción
}

Ejercicio Atrapando de Errores

Para ejemplificar los temas tratados de esta práctica, vamos a crear un nuevo proyecto de nombre
MyAppErrores, en este vamos a utilizar el try para atrapar un error de división por cero.

En este proyecto se va a crear una actividad vacía de nombre MainActivity. Un proyecto de Android
contiene un programa de Kotlin y otros datos en una serie de archivos, que son utilizados por el
programa o por el sistema. Un programa de Kotlin es una colección de clases, contenidas en uno
o varios archivos file1.kt, file2.kt. En Android estos archivos Kotlin se almacenan en Android->app-
>java->com.example.myapperrores. Para nuestro proyecto se crea MainActivity.kt, y un layout con
el nombre activity_main.xml ubicado en app->res->layout, la figura 12 muestra la ubicación de
estos archivos:

35
MANUAL DE PRÁCTICAS DE LA MATERIA “DESARROLLO DE APLICACIONES
PARA DISPOSITIVOS MÓVILES”
Carrera Ingeniería en Tecnologías de la Información y Comunicaciones
Elaborado por: Alejandro Guzmán Zazueta

Figura 12

Ubicación de Archivos Android Estudio

Nota: Ubicación de archivos de un proyecto en Android Estudio

Existe una clase de nombre R que contiene las definiciones de todos los recursos de un paquete
de aplicación. Y es a través de este que vamos a poder declarar variables que referencien a los
controles de nuestras actividades, utilizando la instrucción findViewById.

A continuación, se muestra la estructura básica de una actividad. Esta actividad se llama:


activity_main.xml, y el código se muestra a continuación:

<?xml version="1.0" encoding="utf-8"?>


<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">

36
MANUAL DE PRÁCTICAS DE LA MATERIA “DESARROLLO DE APLICACIONES
PARA DISPOSITIVOS MÓVILES”
Carrera Ingeniería en Tecnologías de la Información y Comunicaciones
Elaborado por: Alejandro Guzmán Zazueta

<TextView
android:id="@+id/ tvTexto"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello World!"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />

</androidx.constraintlayout.widget.ConstraintLayout>

Como puede observar se agregó el id al TextView con el nombre tvTexto, con la finalidad de
poder referenciar este control desde Kotlin.

En la siguiente tabla se muestra el código del archivo: MainActivity.kt, el cual es el código de


kotlin asociado a la interfaz:

package com.example.myapperror

import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle

class MainActivity : AppCompatActivity() {


private lateinit var tvTex : TextView

override fun onCreate(savedInstanceState: Bundle?) {


super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
tvTex = findViewById<TextView>(R.id.tvTexto)
var r: Int
var i: Int
try {
// Se ejecuta algo que puede producir una excepción
i = 57
r = i / 0
tvTex.text = "\n El resultado es:" + r
} catch (e: Exception) {
// Manejo de una excepción
tvTex.append("\n Ocurrio error:" + e)
} finally {
// Código a ejecutar haya o no excepción

37
MANUAL DE PRÁCTICAS DE LA MATERIA “DESARROLLO DE APLICACIONES
PARA DISPOSITIVOS MÓVILES”
Carrera Ingeniería en Tecnologías de la Información y Comunicaciones
Elaborado por: Alejandro Guzmán Zazueta

tvTex.append("\n\n Este código se ejecuta siempre al


final")
// El método append del TextView agrega el texto al text
}
}
}

Este es el modelo que utilizaremos como punto de partida en todos nuestros programas Kotlin.
Examinaremos su estructura:

• El programa contiene una serie de instrucciones o sentencias. Se pueden escribir varias


instrucciones en una línea (separadas por ; punto y coma) o una instrucción en varias
líneas. Los espacios en blanco son ignorados.

• La primera línea package com.example.myapperror indica que esta clase pertenece al


paquete com.example. Cada punto en el nombre de un paquete indica un subdirectorio,
por lo que nuestro programa Kotlin está contenido en el directorio:

\MyAppCurso\app\src\main\java\com\example\myapperror

• Las dos líneas siguientes precedidas por import indican que este programa utiliza dos
clases predefinidas en dos paquetes del sistema Android.

import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle

En este caso, el programa importa la clase Activity del paquete android.app y la clase Bundle
del paquete del paquete android.os. Android contiene numerosos paquetes con miles de
clases. En el editor de Android Studio, cuando escribimos el nombre de una clase, ésta se
subraya en rojo si se requiere añadir un import, por lo que no necesitamos recordar el
nombre del paquete. Basta pulsar Alt-Enter, para que se agregue la importación faltante.

38
MANUAL DE PRÁCTICAS DE LA MATERIA “DESARROLLO DE APLICACIONES
PARA DISPOSITIVOS MÓVILES”
Carrera Ingeniería en Tecnologías de la Información y Comunicaciones
Elaborado por: Alejandro Guzmán Zazueta

• El programa contiene una clase llamada MainActivity cuya definición abarca el bloque
de código comprendido entre la llave inicial y final:

class MainActivity : AppCompatActivity() {

override fun onCreate(savedInstanceState: Bundle?) {


super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
// Este es un comentario

}
}
La declaración finaliza con AppCompatActivity. Esto significa que nuestra clase es una
subclase AppCompatActivity, definida en el paquete android.app y hereda todas sus
propiedades, además de las que nosotros le queramos añadir. Por tanto, myappcurso es
una extensión o una generalización de la clase AppCompatActivity. Se dice que
AppCompatActivity es una superclase de myapperror.

• Dentro de la definición de la clase myapperror encontramos la declaración de un


método de la clase llamado onCreate.

override fun onCreate(savedInstanceState: Bundle?) {


super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
// Este es un comentario

Este método es una función con un parámetro llamado savedInstanceState de tipo Bundle. La
declaración comienza con la clave override, lo que indica que se está redefiniendo o sobre
escribiendo el método onCreate de la super-clase.

• Finalmente, entre dos llaves, tenemos la definición del método, que consiste en dos
instrucciones:

39
MANUAL DE PRÁCTICAS DE LA MATERIA “DESARROLLO DE APLICACIONES
PARA DISPOSITIVOS MÓVILES”
Carrera Ingeniería en Tecnologías de la Información y Comunicaciones
Elaborado por: Alejandro Guzmán Zazueta

super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)

En la primera, el prefijo super indica ejecutar un método de la super-clase Activity. Por


tanto, la instrucción:

super.onCreate(savedInstanceState)

ejecuta el método onCreate() de Activity, aplicado sobre el argumento saveInstanceState. La


última instrucción ejecuta el método setContentView() tomando como argumento la variable
R.layout.activity_main, que es una referencia al archivo main.xml que contiene el layout de la
interfaz de usuario que vemos en la pantalla. Así que de esta manera se asocia el código de
Kotlin al diseño de la interfaz.

A nivel de la clase declaramos un variable tvTex de tipo TextView que se inicializará más tarde,
esto lo hacemos para poder referenciar al TextView de la interfaz.

private lateinit var tvTex : TextView

En el evento onCreate se le asigna a la variable tvTex la referencia de la localidad de memoria


donde se encuentra el TextView de la interfaz en la clase R utilizando el findViewById.

tvTex = findViewById<TextView>(R.id.tvTexto)

asigna a la variable tvTex la referencia del TextView ubicado en la clase R. La clase R que contiene
las definiciones de todos los recursos de un paquete de aplicación, para nuestro ejemplo hacemos
referencia al tvTexto colocado en la interfaz activity_mail.xml.

40
MANUAL DE PRÁCTICAS DE LA MATERIA “DESARROLLO DE APLICACIONES
PARA DISPOSITIVOS MÓVILES”
Carrera Ingeniería en Tecnologías de la Información y Comunicaciones
Elaborado por: Alejandro Guzmán Zazueta

La operación de división por 0 generara un error, el cual será atrapado por el catch, evitando que
la app se interrumpa su ejecución.

La ejecución de la app en el emulador, se muestra en la siguiente figura:

Figura 13

Interfaz gráfica de la aplicación

Nota: Interfaz gráfica de la aplicación en ejecución.

Pregunta de análisis en el aula

¿Qué pasa si no atrapa el Error con try y catch?


¿Para qué se usan el findViewById?
¿Qué es la clase R?

Reporte del Estudiante

El estudiante presentara la App en ejecución en clase, explicando su funcionamiento.

41
MANUAL DE PRÁCTICAS DE LA MATERIA “DESARROLLO DE APLICACIONES
PARA DISPOSITIVOS MÓVILES”
Carrera Ingeniería en Tecnologías de la Información y Comunicaciones
Elaborado por: Alejandro Guzmán Zazueta

Unidad 3. Desarrollo de Aplicaciones Móviles

Competencia específica a desarrollar:

Desarrolla aplicaciones móviles nativas, web e híbridas para atender las necesidades del entorno.

Subtema

3.1 Metodología de desarrollo y ejecución.


3.2 Uso de formularios Web móvil.
3.3 Uso de controles.
3.4 Creación Interfaces de usuario.
3.5 Temas selectos de programación para móviles.

Sugerencias Didácticas

1. El estudiante utilizará los Constraint Layout y Linear Layout para diseñar interfaces de
usuario.
2. Implementara formularios para el ingreso de información validada.
3. Creará un menú para una interfaz de una aplicación móvil, respondiendo al clic del
usuario.

42
MANUAL DE PRÁCTICAS DE LA MATERIA “DESARROLLO DE APLICACIONES
PARA DISPOSITIVOS MÓVILES”
Carrera Ingeniería en Tecnologías de la Información y Comunicaciones
Elaborado por: Alejandro Guzmán Zazueta

Práctica 4. Uso de Layouts

Objetivo
El estudiante aprenderá a usar el Constraint Layout y el Liner Layout en el diseño de una app.

Introducción
Esta práctica tiene como fin comprender el uso de los Layouts, en el diseño de una aplicación
móvil.

Correlación con los temas y subtemas del programa de estudio


Esta práctica abona al contenido de los temas:
3.4 Creación Interfaces de usuario.

Material y equipo necesario


Computadora i3, i5 o i7 con mínimo de 8GB de Ram.
Acceso a Internet, para la creación de nuevo proyecto en Android Studio.

Metodología
El estudiante deberá leer el siguiente material previo a la elaboración de la práctica:

43
MANUAL DE PRÁCTICAS DE LA MATERIA “DESARROLLO DE APLICACIONES
PARA DISPOSITIVOS MÓVILES”
Carrera Ingeniería en Tecnologías de la Información y Comunicaciones
Elaborado por: Alejandro Guzmán Zazueta

Layouts

Son un conjunto de contenedores en donde podemos colocar muchos elementos según el diseño
de nuestra aplicación, por ejemplo, dentro de un Layout puedes colocar, botones, imágenes,
formularios, textos, etc. todos estos deben tener un orden y armonía entre si dentro del diseño,
para esto debemos haber elegido un Layout primero para luego colocar dentro de este los
elementos que necesitemos. (Colectiva, 2018)

Figura 14

ConstraintLayout

Nota: Contenedor ConstraintLayout (Colectiva, 2018)

ConstraintLayout: Permite una edición visual desde el editor.

Este nuevo layout ha sido añadido en una librería de compatibilidad, por lo que se nos anima a
usarlo de forma predeterminada. Nos permite crear complejos diseños sin la necesidad de usar
layout anidados, ver figura 14. El hecho de realizar diseños donde un layout se introduce dentro
de otro y así repetidas veces, ocasionaba problemas de memoria y eficiencia en dispositivos de
pocas prestaciones.

44
MANUAL DE PRÁCTICAS DE LA MATERIA “DESARROLLO DE APLICACIONES
PARA DISPOSITIVOS MÓVILES”
Carrera Ingeniería en Tecnologías de la Información y Comunicaciones
Elaborado por: Alejandro Guzmán Zazueta

Es muy parecido a RelativeLayout, pero más flexible y fácil de usar desde el editor visual de Android
Studio (disponible desde la versión 2.3). De hecho, se recomienda crear tu layout con las
herramientas drag-and-drop, en lugar de editar el fichero XML. El resto de layouts, son más fáciles
de crear desde XML.

Las posiciones de las diferentes vistas dentro de este layout se definen usando constraint (en
castellano restricciones). Un constraint puede definirse en relación al contenedor (parent), a otra
vista o respecto a una línea de guía (guideline). Es necesario definir para cada vista al menos un
constraint horizontal y uno vertical. Pero también podemos definir más de un constraint en el
mismo eje. La figura 15 ilustra el manejo:

Figura 15

Layout constraint

Nota: Restriciones en un contsraintlayout (Developers, 2023)

Observa como la vista A está posicionada con respecto al contenedor. La vista B está posicionada
verticalmente con respecto a la vista A, aunque se ha definido un segundo constraint con respecto
al lado derecho del contenedor.

LinearLayout: Dispone los elementos en una fila o en una columna.

LinearLayout es el Layout más utilizado en la práctica, distribuye los elementos uno detrás de otro,
de forma horizontal o vertical.

45
MANUAL DE PRÁCTICAS DE LA MATERIA “DESARROLLO DE APLICACIONES
PARA DISPOSITIVOS MÓVILES”
Carrera Ingeniería en Tecnologías de la Información y Comunicaciones
Elaborado por: Alejandro Guzmán Zazueta

Linear layout permite acomodar los componentes de tu UI, de manera lineal. Es decir, acomodara
los componentes uno enseguida de otro, así que es muy fácil saber que componente va enseguida
de otro, a diferencia que el en Relative layout, en el cual tienes que especificar en donde irá cada
componente. Aunque esto último es más difícil en el Relative layout, es una ventaja en cuanto a
más maneras de acomodar todo.

Orientación

Uno de los aspectos fundamentales del linear layout es la orientación. Por default usa orientación
horizontal. Y solo puedes alternar entre Horizontal y Vertical.

Si dejamos la orientación como vertical, tendremos lo siguiente en la figura 16:

Figura 16

Linearlayout vertical

Nota: Linearlayout disposición vertical (Developers, 2023)

Si cambiamos la orientación a horizontal entonces se verá como en la figura 17:

Figura 17

Linearlayout horizontal

46
MANUAL DE PRÁCTICAS DE LA MATERIA “DESARROLLO DE APLICACIONES
PARA DISPOSITIVOS MÓVILES”
Carrera Ingeniería en Tecnologías de la Información y Comunicaciones
Elaborado por: Alejandro Guzmán Zazueta

Nota:Linearlayout disposición horizontal

Cálculo del Índice de Masa Corporal usando ConstrainLayout

En el siguiente ejemplo se crea una interfaz para calcular el índice de masa corporal, para lo cual
se pide que se ingrese el peso en Kg y la estatura en Mt, de acuerdo a la siguiente formula:

Se deberán implementar los siguientes rangos, como salida dependiendo del IMC:

Rango del IMC Mensaje

0 a 18 Desnutrición

18 a 25 Normal

25 a 30 Sobrepeso

30 a 40 Obesidad

Otro valor Tu IMC esta fuera de rango verificar datos de entrada

47
MANUAL DE PRÁCTICAS DE LA MATERIA “DESARROLLO DE APLICACIONES
PARA DISPOSITIVOS MÓVILES”
Carrera Ingeniería en Tecnologías de la Información y Comunicaciones
Elaborado por: Alejandro Guzmán Zazueta

en la figura 18 se observa el diseño usando el Constraint Layout:

Figura 18

Diseño con Constraintlayout

Nota: Diseño de IMC con constraintlayout

El código de la interfaz se muestra a continuación:


<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivityIMC">

<TextView
android:id="@+id/textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"

48
MANUAL DE PRÁCTICAS DE LA MATERIA “DESARROLLO DE APLICACIONES
PARA DISPOSITIVOS MÓVILES”
Carrera Ingeniería en Tecnologías de la Información y Comunicaciones
Elaborado por: Alejandro Guzmán Zazueta

android:layout_marginTop="76dp"
android:gravity="center"
android:text="Calculo del IMC"
android:textAppearance="@style/TextAppearance.AppCompat.Large"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />

<com.google.android.material.textfield.TextInputLayout
android:id="@+id/textInputLayout"
android:layout_width="300dp"
android:layout_height="wrap_content"
android:layout_marginTop="80dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/textView">

<com.google.android.material.textfield.TextInputEditText
android:id="@+id/txtPeso"
android:layout_width="300dp"
android:layout_height="wrap_content"
android:hint="Ingresa tu Peso en Kg" />

</com.google.android.material.textfield.TextInputLayout>

<com.google.android.material.textfield.TextInputLayout
android:id="@+id/textInputLayout2"
android:layout_width="300dp"
android:layout_height="wrap_content"
android:layout_marginTop="79dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/textInputLayout">

<com.google.android.material.textfield.TextInputEditText
android:id="@+id/txtEstatura"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="Ingresa tu Estatura en Mt"
android:padding="30dp" />

</com.google.android.material.textfield.TextInputLayout>

<com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="@+id/btnCalcular"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="51dp"
android:clickable="true"
android:onClick="btnCalcularIMC"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"

49
MANUAL DE PRÁCTICAS DE LA MATERIA “DESARROLLO DE APLICACIONES
PARA DISPOSITIVOS MÓVILES”
Carrera Ingeniería en Tecnologías de la Información y Comunicaciones
Elaborado por: Alejandro Guzmán Zazueta

app:layout_constraintTop_toBottomOf="@+id/textInputLayout2"
app:srcCompat="@android:drawable/ic_menu_send"
tools:ignore="SpeakableTextPresentCheck" />

</androidx.constraintlayout.widget.ConstraintLayout>

A continuación, se muestra el código del MainActivity.kt


package com.example.myapplicationimc

import android.content.Intent
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.view.View
import android.widget.Toast
import
com.google.android.material.floatingactionbutton.FloatingActionButton
import com.google.android.material.textfield.TextInputEditText

class MainActivity : AppCompatActivity() {


private lateinit var txtPeso: TextInputEditText
private lateinit var txtAltura: TextInputEditText
var msg : String = ""

override fun onCreate(savedInstanceState: Bundle?) {


super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)

findViewById<FloatingActionButton>(R.id.btnCalcular).setOnClickListener
{
Calcular()
}
}

private fun Calcular()


{
txtPeso = findViewById<TextInputEditText>(R.id.txtPeso)
txtAltura = findViewById<TextInputEditText>(R.id.txtAltura)
if (txtPeso.text.isNullOrEmpty()){
txtPeso.setError("El peso no se puede quedar vacio")
txtPeso.requestFocus()
}
else{
if(txtAltura.text.isNullOrEmpty()){
txtAltura.setError("Error la altura no puede quedar
vacia")
txtAltura.requestFocus()
}
else{
val peso : Double = txtPeso.text.toString().toDouble()
val altura : Double =
txtAltura.text.toString().toDouble()

50
MANUAL DE PRÁCTICAS DE LA MATERIA “DESARROLLO DE APLICACIONES
PARA DISPOSITIVOS MÓVILES”
Carrera Ingeniería en Tecnologías de la Información y Comunicaciones
Elaborado por: Alejandro Guzmán Zazueta

val res : Double = peso / (altura*altura)


when (res){
in 0.0 .. 18.0 ->{ // Enviar a la actividad en Rojo
msg = "Tu IMC es: $res y es Desnutrición "
}
in 18.01 .. 25.0->{ // Enviar a la actividad en
Verde
msg = "Tu IMC es: $res y es Normal"
}
in 25.01 .. 30.0 ->{ // Enviar a la actividad en
Amarillo
msg = "Tu IMC es: $res y es de Sobre Peso"
}
in 30.01 .. 40.0 ->{ // Enviar a la actividad en
Amarillo
msg = "Tu IMC es: $res y es de Obesidad"
}
else ->{ // Enviar a la actividad en Rojo
msg = "Tu IMC esta fuera de rango checar datos
de entrada"
}
}
Toast.makeText(this, msg, Toast.LENGTH_LONG).show();
}
}
}
}

La figura 19 ilustra la aplicación en ejecución:

51
MANUAL DE PRÁCTICAS DE LA MATERIA “DESARROLLO DE APLICACIONES
PARA DISPOSITIVOS MÓVILES”
Carrera Ingeniería en Tecnologías de la Información y Comunicaciones
Elaborado por: Alejandro Guzmán Zazueta

Figura 19

Interfaz de la aplicación IMC

Nota: Diseño de la interfaz de IMC usando constraintlayout

Cálculo del Índice de Masa Corporal usando LinearLayout

En el siguiente ejemplo creamos la interfaz de una aplicación para calcular el índice de masa
corporal, como el ejercicio anterior, para lo cual se pide que se ingrese el peso en Kg y la estatura
en Mt, en la figura 20 se observa el diseño usando el Linearlayout:

52
MANUAL DE PRÁCTICAS DE LA MATERIA “DESARROLLO DE APLICACIONES
PARA DISPOSITIVOS MÓVILES”
Carrera Ingeniería en Tecnologías de la Información y Comunicaciones
Elaborado por: Alejandro Guzmán Zazueta

Figura 20

Diseño de la aplicación IMC

Nota: Diseño de la aplicación IMC usando Linearlayout

Como se puede observar en el recuadro rojo (component Tree), se muestran los elementos que
tiene nuestra interfaz y como están anidados. En primer lugar, tenemos un Linear layout vertical
como contenedor principal, y enseguida colocamos un linear layout horizontal por cada control
que vaya a tener nuestra interfaz.

A continuación, se muestra el código xml de la interfaz:

<?xml version="1.0" encoding="utf-8"?>


<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"

53
MANUAL DE PRÁCTICAS DE LA MATERIA “DESARROLLO DE APLICACIONES
PARA DISPOSITIVOS MÓVILES”
Carrera Ingeniería en Tecnologías de la Información y Comunicaciones
Elaborado por: Alejandro Guzmán Zazueta

android:layout_height="match_parent"
android:orientation="vertical"
android:padding="15dp"
tools:context=".MainActivity" >

<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="40dp"
android:orientation="horizontal">

<TextView
android:id="@+id/textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:gravity="center"
android:padding="30dp"
android:text="Calculo del IMC"
android:textAppearance="@style/TextAppearance.AppCompat.Large" />
</LinearLayout>

<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">

<com.google.android.material.textfield.TextInputLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">

<com.google.android.material.textfield.TextInputEditText
android:id="@+id/txtPeso"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="30dp"
android:hint="Ingresa tu Peso en Kg" />
</com.google.android.material.textfield.TextInputLayout>
</LinearLayout>

<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingTop="40dp"
android:orientation="horizontal">

<com.google.android.material.textfield.TextInputLayout
android:layout_width="match_parent"
android:layout_height="match_parent">

<com.google.android.material.textfield.TextInputEditText
android:id="@+id/txtEstatura"
android:layout_width="match_parent"

54
MANUAL DE PRÁCTICAS DE LA MATERIA “DESARROLLO DE APLICACIONES
PARA DISPOSITIVOS MÓVILES”
Carrera Ingeniería en Tecnologías de la Información y Comunicaciones
Elaborado por: Alejandro Guzmán Zazueta

android:layout_height="wrap_content"
android:hint="Ingresa tu Estatura en Mt"
android:padding="30dp" />
</com.google.android.material.textfield.TextInputLayout>
</LinearLayout>

<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:paddingTop="50dp">

<com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="@+id/btnCalcular"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:clickable="true"
android:onClick="btnCalcularIMC"
app:srcCompat="@android:drawable/ic_menu_send"
tools:ignore="SpeakableTextPresentCheck" />
</LinearLayout>
</LinearLayout>

El código de Kotlin asociado a la interfaz, se muestra a continuación:

package com.example.myapplication

import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.view.View
import android.widget.Toast
import kotlinx.android.synthetic.main.activity_main.*

class MainActivity : AppCompatActivity() {


var peso : Double = 0.0
var estatura : Double = 0.0
var res : Double = 0.0

override fun onCreate(savedInstanceState: Bundle?) {


super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
}

fun btnCalcularIMC(view: View) {


if (txtPeso.text.toString().isEmpty() ){
txtPeso.setError("Error falta de ingresar el peso en Kg")
txtPeso.requestFocus()

55
MANUAL DE PRÁCTICAS DE LA MATERIA “DESARROLLO DE APLICACIONES
PARA DISPOSITIVOS MÓVILES”
Carrera Ingeniería en Tecnologías de la Información y Comunicaciones
Elaborado por: Alejandro Guzmán Zazueta

}
else{
if (txtEstatura.text.toString().isEmpty()){
txtEstatura.setError("Error falta de ingresar la
estatura en Mt")
txtEstatura.requestFocus()
}
else{
peso = txtPeso.text.toString().toDouble()
estatura = txtEstatura.text.toString().toDouble()
res = peso / (estatura * estatura)

when (res){
in 0.0 .. 18.0 ->{ // Enviar a la actividad en Rojo
Toast.makeText(this, "Tu IMC es: $res y es
Desnutrición ", Toast.LENGTH_LONG).show();
}
in 18.01 .. 25.0->{ // Enviar a la actividad en
Verde
Toast.makeText(this, "Tu IMC es: $res y es
Normal", Toast.LENGTH_LONG).show();
}
in 25.01 .. 30.0 ->{ // Enviar a la actividad en
Amarillo
Toast.makeText(this, "Tu IMC es: $res y es de
Sobre Peso", Toast.LENGTH_LONG).show();
}
in 30.01 .. 40.0 ->{ // Enviar a la actividad en
Amarillo
Toast.makeText(this, "Tu IMC es: $res y es de
Obesidad", Toast.LENGTH_LONG).show();
}
else ->{ // Enviar a la actividad en
Rojo
Toast.makeText(this, "Tu IMC esta fuera de
rango checar datos de entrada", Toast.LENGTH_LONG).show();
}
}
}
}
}
}

Al ejecutar la aplicación se visualiza como lo muestra la figura 21:

56
MANUAL DE PRÁCTICAS DE LA MATERIA “DESARROLLO DE APLICACIONES
PARA DISPOSITIVOS MÓVILES”
Carrera Ingeniería en Tecnologías de la Información y Comunicaciones
Elaborado por: Alejandro Guzmán Zazueta

Figura 21

Interfaz de la aplicación IMC

Nota: Diseño de la interfaz de IMC usando Linearlayout

57
MANUAL DE PRÁCTICAS DE LA MATERIA “DESARROLLO DE APLICACIONES
PARA DISPOSITIVOS MÓVILES”
Carrera Ingeniería en Tecnologías de la Información y Comunicaciones
Elaborado por: Alejandro Guzmán Zazueta

Crear un Menú de Opciones


Creamos un nuevo proyecto con una actividad vacía, asegurando que los temas del proyecto no
estén configurados con la opción “NoActionBar”. Los temas se pueden localizar en la carpera
resà valuesàthemes, y cambie el parámetro NoActionBar.

En seguida agregamos un archivo de tipo “Android Resource File” sobre la carpeta ,


mostrando la ventana de la figura 22:
Figura 22

Ventana de New Android Resource File

Nota: Parámetros de configuración de un New Android Resource File

Esto genera que se agregue a la carpeta res la carpeta menu con el archivo menu1.xml
que se agregó, quedando como se muestra en la figura 23:

58
MANUAL DE PRÁCTICAS DE LA MATERIA “DESARROLLO DE APLICACIONES
PARA DISPOSITIVOS MÓVILES”
Carrera Ingeniería en Tecnologías de la Información y Comunicaciones
Elaborado por: Alejandro Guzmán Zazueta

Figura 23

Android Estudio con archivo Menu1.xml

Nota: Android Estudio con el archivo Menu1.xml en modo diseño

Entramos al código del menu1.xml y lo dejamos como a continuación se muestra:


<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<item
android:id="@+id/opcCargar"
android:title="Cargar"
android:icon="@drawable/upload"
app:showAsAction="ifRoom"
/>
<item
android:id="@+id/opcDescargar"
android:title="Descargar"
android:icon="@drawable/dowload"
app:showAsAction="ifRoom"
/>
<item
android:id="@+id/opcVacunas"
android:title="Vacunas"
app:showAsAction="never"
/>
<item
android:id="@+id/opcCartilla"
android:title="Cartilla"
app:showAsAction="never"
/>

</menu>

La figura 24 ilustra como queda el menú:

59
MANUAL DE PRÁCTICAS DE LA MATERIA “DESARROLLO DE APLICACIONES
PARA DISPOSITIVOS MÓVILES”
Carrera Ingeniería en Tecnologías de la Información y Comunicaciones
Elaborado por: Alejandro Guzmán Zazueta

Figura 24

Interfaz gráfica del menu1.xml

Nota diseño de la interfaz gráfica de menú

En seguida agregamos el evento onCreateOptionsMenu (evento para asignar el menú a


la actividad) y el evento onOptionsItemSelected (evento para atrapar la opción en la que
el usuario da clic) al MainActivity.kt como se muestra a continuación:

package com.example.myapplicationmenu

import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.view.Menu
import android.view.MenuInflater
import android.view.MenuItem
import android.widget.Toast

class MainActivity : AppCompatActivity() {


override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
}

override fun onCreateOptionsMenu(menu: Menu?): Boolean {


val asignaMenu : MenuInflater = menuInflater
asignaMenu.inflate(R.menu.menu1, menu)
return true
}

60
MANUAL DE PRÁCTICAS DE LA MATERIA “DESARROLLO DE APLICACIONES
PARA DISPOSITIVOS MÓVILES”
Carrera Ingeniería en Tecnologías de la Información y Comunicaciones
Elaborado por: Alejandro Guzmán Zazueta

override fun onOptionsItemSelected(item: MenuItem): Boolean {


return when (item.itemId){
R.id.opcVacunas -> {
Toast.makeText(this, "Diste clic en opcVacunas",
Toast.LENGTH_LONG).show();
return true
}
R.id.opcCartilla -> {
Toast.makeText(this, "Diste clic en opcCartilla",
Toast.LENGTH_SHORT).show()
return true
}
R.id.opcCargar -> {
Toast.makeText(this, "Diste clic en opcCargar",
Toast.LENGTH_LONG).show();
return true
}
R.id.opcDescargar -> {
Toast.makeText(this, "Diste clic en opcDescargar",
Toast.LENGTH_LONG).show();
return true
}
else ->{
Toast.makeText(this, "Opción Invalida",
Toast.LENGTH_LONG).show();
return true
}
}
}
}

Pregunta de análisis en el aula

¿Qué Layout considera mejor el LinearLayout o ConstraintLayout y por qué?

Reporte del Estudiante

Presentación del trabajo

El estudiante presentará las diferencias de las App con Constraint y Linear Layout.
El estudiante deberá usar el conocimiento de estas prácticas en su proyecto, y mostrar evidencias.

61
MANUAL DE PRÁCTICAS DE LA MATERIA “DESARROLLO DE APLICACIONES
PARA DISPOSITIVOS MÓVILES”
Carrera Ingeniería en Tecnologías de la Información y Comunicaciones
Elaborado por: Alejandro Guzmán Zazueta

Unidad 4. Administración de datos en dispositivos móviles

Competencia específica a desarrollar:

Conoce y aplica tecnologías de conectividad a bases de datos actuales y emergentes para el


desarrollo de aplicaciones móviles.

Subtema

4.1 Introducción.
4.2 Modelo de objetos de acceso a datos.
4.3 Manipulación de datos.
4.4 XML.
4.5 JSON.

Sugerencias Didácticas

1. El estudiante aprenderá almacenar información en bases de datos con SQLite.


2. Aprenderá a llenar controles con información de bases de datos.
3. Utilizará los servicios web para el intercambio de información entre aplicaciones.
4. Aplicará el conocimiento de estas prácticas al proyecto final

62
MANUAL DE PRÁCTICAS DE LA MATERIA “DESARROLLO DE APLICACIONES
PARA DISPOSITIVOS MÓVILES”
Carrera Ingeniería en Tecnologías de la Información y Comunicaciones
Elaborado por: Alejandro Guzmán Zazueta

Práctica 5. Bases de Datos en SQLite y Llenado de Controles

Objetivo
El estudiante aprenderá a usar la librería de base de datos SQLite de Android y el llenado de
controles Spinner y RecyclerView.

Introducción
Esta práctica tiene como fin comprender el uso de la librería SQLite, para almacenar información
persistente en los dispositivos móviles.

Correlación con los temas y subtemas del programa de estudio


Esta práctica abona al contenido de los temas:
4.2 Modelo de objetos de acceso a datos.

Material y equipo necesario


Computadora i3, i5 o i7 con mínimo de 8GB de Ram.
Acceso a Internet, para la creación de nuevo proyecto en Android Studio.

Metodología
El estudiante deberá leer el siguiente material previo a la elaboración de la práctica:

63
MANUAL DE PRÁCTICAS DE LA MATERIA “DESARROLLO DE APLICACIONES
PARA DISPOSITIVOS MÓVILES”
Carrera Ingeniería en Tecnologías de la Información y Comunicaciones
Elaborado por: Alejandro Guzmán Zazueta

¿Qué es SQLite?
Es un motor ligero de bases de datos de código abierto, que se caracteriza por mantener el
almacenamiento de información persistente de forma sencilla (Revelo, 2014).

Dentro de los distintos sistemas de bases de datos tanto privativos como libres/open source
(Oracle, SQLServer, MySQL, etc) existe uno que se adapta perfectamente a las aplicaciones
móviles: SQLite. El principal motivo es que SQLite no requiere más que un simple fichero para
almacenar los datos, ya que la lógica de funcionamiento debe ser implementada por la plataforma
que desee interactuar con los datos.

En nuestro caso concreto el SDK Android incluye soporte completo para SQLite. La mayoría de las
aplicaciones móviles (tanto en Android como en otros sistemas) incluyen bases de datos SQLite,
bien sea para la gestión total de los datos, o bien para al menos gestionar los datos almacenados
localmente cuando las aplicaciones son parte de infraestructuras mayores que incluyen bases de
datos centralizadas online o servicios Web para la obtención de los datos.

El procedimiento recomendado para crear una nueva base de datos SQLite es, de forma
esquemática:

Ø crear una clase que extienda de SQLiteOpenHelper


Ø sobre escribir en ella el método onCreate() , donde se ejecutará un comando de SQLite
para crear las tablas de la base de datos.
Ø También habría que sobre escribir el método onUpgrade() , el cual se ejecutará cada vez
que cambiamos la versión de la base de datos y se usará para migrar los datos de la base
de datos anterior a la nueva versión.

Se creará también el constructor de la clase que no será necesario en principio modificarlo.

64
MANUAL DE PRÁCTICAS DE LA MATERIA “DESARROLLO DE APLICACIONES
PARA DISPOSITIVOS MÓVILES”
Carrera Ingeniería en Tecnologías de la Información y Comunicaciones
Elaborado por: Alejandro Guzmán Zazueta

Bases de Datos con SQLite


A continuación, vamos a crear una base de datos sencilla usando una clase derivada
de SQLiteOpenHelper, para ello vamos a crear un nuevo proyecto de nombre AppSQLite.

En la siguiente tabla se muestran la tabla de producto que se va a crear en la base de datos:

Tabla: Producto
idProd Integer Auto incrementable
NomProd Text
Existencia integer
Precio double

Enseguida agregaremos una clase de Kotlin de nombre AdminBD, a través de la cual gestionaremos
la estructura de la base de datos y los accesos, a la cual llamaremos BDInventario. A continuación,
se muestra el código de la clase:

package com.example.appsqlite

import android.content.Context
import android.database.Cursor
import android.database.sqlite.SQLiteDatabase
import android.database.sqlite.SQLiteOpenHelper
import android.util.Log

class AdminBD(context : Context): SQLiteOpenHelper(context,"BDInventario",null,1) {

// En este método se crean las tablas de la base de datos la primera vez que se
// ejecuta el proyecto, si se hacen cambios deberá desinstalar la App del dispositivo
// para eliminar la base de datos y que vuelva a crear las tablas con los nuevos cambios
override fun onCreate(bd: SQLiteDatabase?) {
if (bd != null) {
bd.execSQL("Create Table Producto(idProd integer primary key AUTOINCREMENT," +
"NomProd text, Existencia integer, Precio double)")
}
}

// función para mandar ejecutar un Insert, Update o Delete regresa un true


// cuando se ejecuta con éxito y un false cuando ocurre un error
fun Ejecuta(sentencia : String): Boolean{

65
MANUAL DE PRÁCTICAS DE LA MATERIA “DESARROLLO DE APLICACIONES
PARA DISPOSITIVOS MÓVILES”
Carrera Ingeniería en Tecnologías de la Información y Comunicaciones
Elaborado por: Alejandro Guzmán Zazueta

try {
val bd = this.writableDatabase
bd.execSQL(sentencia)
bd.close()
return true
}
catch (ex : Exception){
// La siguiente instrucción manda el mensaje a la pestaña de Log,
// cuando estamos depurando
Log.d("Zazu", ex.message.toString() + "-->" + sentencia)
return false
}
}

// Función para mandar ejecutar una consulta a la base de datos, regresando un


// Cursor los registro que regrese la consulta, si ocurre erro regresará un null
fun Consultar(consulta : String): Cursor?{
try {
val bd = this.readableDatabase
return bd.rawQuery(consulta, null)
}
catch (ex : Exception){
// La siguiente instrucción manda el mensaje a la pestaña de Log,
// cuando estamos depurando
Log.d("Zazu", ex.message.toString() + "-->" + consulta)
return null
}
}

override fun onUpgrade(p0: SQLiteDatabase?, p1: Int, p2: Int) {


TODO("Not yet implemented")
}

A continuación, se debe crear la interfaz como se muestra en la figura 25:

66
MANUAL DE PRÁCTICAS DE LA MATERIA “DESARROLLO DE APLICACIONES
PARA DISPOSITIVOS MÓVILES”
Carrera Ingeniería en Tecnologías de la Información y Comunicaciones
Elaborado por: Alejandro Guzmán Zazueta

Figura 25

Interfaz del Catálogo de Productos

Nota: Diseño de la interfaz del Catálogo de Productos

En seguida se muestra el código de la interfaz:

<?xml version="1.0" encoding="utf-8"?>


<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">

<TextView
android:id="@+id/textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Catálogo de Productos"
android:textAppearance="@style/TextAppearance.AppCompat.Large"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.473"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.087" />

<com.google.android.material.textfield.TextInputLayout
android:id="@+id/textInputLayout"

67
MANUAL DE PRÁCTICAS DE LA MATERIA “DESARROLLO DE APLICACIONES
PARA DISPOSITIVOS MÓVILES”
Carrera Ingeniería en Tecnologías de la Información y Comunicaciones
Elaborado por: Alejandro Guzmán Zazueta

android:layout_width="300dp"
android:layout_height="wrap_content"
android:layout_marginTop="44dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/textView">

<com.google.android.material.textfield.TextInputEditText
android:id="@+id/txtidProd"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="Cve Producto"
android:inputType="number" />
</com.google.android.material.textfield.TextInputLayout>

<com.google.android.material.textfield.TextInputLayout
android:id="@+id/textInputLayout2"
android:layout_width="300dp"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/textInputLayout">

<com.google.android.material.textfield.TextInputEditText
android:id="@+id/txtNomProd"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="Nombre del Producto" />
</com.google.android.material.textfield.TextInputLayout>

<com.google.android.material.textfield.TextInputLayout
android:id="@+id/textInputLayout3"
android:layout_width="300dp"
android:layout_height="wrap_content"
android:layout_marginTop="22dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/textInputLayout2">

<com.google.android.material.textfield.TextInputEditText
android:id="@+id/txtExistencia"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="number"
android:hint="Existencia" />
</com.google.android.material.textfield.TextInputLayout>

<com.google.android.material.textfield.TextInputLayout
android:id="@+id/textInputLayout4"
android:layout_width="300dp"
android:layout_height="wrap_content"
android:layout_marginTop="31dp"
app:layout_constraintEnd_toEndOf="parent"

68
MANUAL DE PRÁCTICAS DE LA MATERIA “DESARROLLO DE APLICACIONES
PARA DISPOSITIVOS MÓVILES”
Carrera Ingeniería en Tecnologías de la Información y Comunicaciones
Elaborado por: Alejandro Guzmán Zazueta

app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/textInputLayout3">

<com.google.android.material.textfield.TextInputEditText
android:id="@+id/txtPrecio"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="numberDecimal"
android:hint="Precio" />
</com.google.android.material.textfield.TextInputLayout>

<Button
android:id="@+id/btnInsertar"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="32dp"
android:layout_marginTop="107dp"
android:layout_marginEnd="285dp"
android:onClick="btnInsertar"
android:text="Insert"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/textInputLayout4" />

<Button
android:id="@+id/btnActualizar"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="12dp"
android:layout_marginTop="108dp"
android:layout_marginEnd="150dp"
android:onClick="btnActualizar"
android:text="Update"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@+id/btnInsertar"
app:layout_constraintTop_toBottomOf="@+id/textInputLayout4" />

<Button
android:id="@+id/btnEliminar"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="38dp"
android:layout_marginTop="111dp"
android:layout_marginEnd="45dp"
android:onClick="btnEliminar"
android:text="Delete"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@+id/btnActualizar"
app:layout_constraintTop_toBottomOf="@+id/textInputLayout4" />

<Button
android:id="@+id/btnConsultar"
android:layout_width="wrap_content"
android:layout_height="wrap_content"

69
MANUAL DE PRÁCTICAS DE LA MATERIA “DESARROLLO DE APLICACIONES
PARA DISPOSITIVOS MÓVILES”
Carrera Ingeniería en Tecnologías de la Información y Comunicaciones
Elaborado por: Alejandro Guzmán Zazueta

android:layout_marginTop="30dp"
android:onClick="btnConsultar"
android:text="Select"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.482"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/btnActualizar" />

</androidx.constraintlayout.widget.ConstraintLayout>

El código de Kotlin asociado a la interfaz con los eventos programados, se muestra a continuación:

package com.example.appsqlite
import android.content.Intent
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.view.View
import android.widget.Toast
import com.google.android.material.textfield.TextInputEditText

class MainActivity : AppCompatActivity() {


var admin = AdminBD(this)
private lateinit var txtid : TextInputEditText
private lateinit var txtNomP: TextInputEditText
private lateinit var txtExis : TextInputEditText
private lateinit var txtPrec : TextInputEditText

override fun onCreate(savedInstanceState: Bundle?) {


super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
txtid = findViewById<TextInputEditText>(R.id.txtidProd)
txtNomP = findViewById<TextInputEditText>(R.id.txtNomProd)
txtExis = findViewById<TextInputEditText>(R.id.txtExistencia)
txtPrec = findViewById<TextInputEditText>(R.id.txtPrecio)
}
fun btnInsertar(view: View) {
if (txtNomP.text.toString().isEmpty() ||
txtExis.text.toString().isEmpty() || txtPrec.text.toString().isEmpty()
){
txtNomP.setError("Error fal de ingresar información")
txtNomP.requestFocus()
}
else{
val nom = txtNomP.text.toString()
val exi = txtExis.text.toString()
val pre = txtPrec.text.toString()
val sentencia = "Insert into
Producto(NomProd,existencia,precio)values('$nom',$exi,$pre)"
if (admin.Ejecuta(sentencia)){
Limpiar()

70
MANUAL DE PRÁCTICAS DE LA MATERIA “DESARROLLO DE APLICACIONES
PARA DISPOSITIVOS MÓVILES”
Carrera Ingeniería en Tecnologías de la Información y Comunicaciones
Elaborado por: Alejandro Guzmán Zazueta

Toast.makeText(this, "Registro Insertado",


Toast.LENGTH_LONG).show();
}
else{
Toast.makeText(this, "Error: No se inserto",
Toast.LENGTH_SHORT).show()
}
txtid.requestFocus()
}
}
fun btnActualizar(view: View) {
if (txtNomP.text.toString().isEmpty() ||
txtExis.text.toString().isEmpty()
|| txtPrec.text.toString().isEmpty()
|| txtid.text.toString().isEmpty()){
txtNomP.setError("Error falta de ingresar información")
txtNomP.requestFocus()
}
else{
val idp = txtid.text.toString()
val nom = txtNomP.text.toString()
val exi = txtExis.text.toString()
val pre = txtPrec.text.toString()
val idc = 0
val sentencia = "Update Producto set
NomProd='$nom',existencia=$exi,precio=$pre Where idProd = $idp"
if (admin.Ejecuta(sentencia)){
Limpiar()
Toast.makeText(this, "Registro Actualizado",
Toast.LENGTH_LONG).show();
}
else{
Toast.makeText(this, "Error: No se Modifico el
Producto", Toast.LENGTH_SHORT).show()
}
txtid.requestFocus()
}
}
fun btnEliminar(view: View) {
if (txtid.text.toString().isEmpty() ){
txtid.setError("Error falta de ingresar la clave del
producto a eliminar")
txtid.requestFocus()
}
else{
val idp = txtid.text.toString()
val sentencia = "Delete from Producto where idProd=$idp"
if (admin.Ejecuta(sentencia)){
Limpiar()
Toast.makeText(this, "Registro Eliminado",
Toast.LENGTH_LONG).show();
}
else{
Toast.makeText(this, "Error: No se elimino el

71
MANUAL DE PRÁCTICAS DE LA MATERIA “DESARROLLO DE APLICACIONES
PARA DISPOSITIVOS MÓVILES”
Carrera Ingeniería en Tecnologías de la Información y Comunicaciones
Elaborado por: Alejandro Guzmán Zazueta

producto", Toast.LENGTH_SHORT).show()
}
txtid.requestFocus()
}
}
fun btnConsultar(view: View) {
if (txtid.text.toString().isEmpty()){
txtid.setError("Error para buscar ingresa la clave del
producto")
txtid.requestFocus()
}
else{
val idp = txtid.text.toString()
// 0 1 2 3
val query = "Select idProd,NomProd,existencia,precio from
Producto where idProd=$idp"
val tuplas = admin.Consultar(query)
if (tuplas == null){
Toast.makeText(this, "Producto no encontrado",
Toast.LENGTH_LONG).show();
txtid.requestFocus()
}
else{
if (tuplas.moveToFirst()){
txtNomP.setText(tuplas.getString(1).toString())
txtExis.setText(tuplas.getInt(2).toString())
txtPrec.setText(tuplas.getDouble(3).toString())
txtNomP.requestFocus()
tuplas.close()
}
else
{
Toast.makeText(this, "Producto no encontrado",
Toast.LENGTH_LONG).show();
txtid.requestFocus()
}
}
}
}
fun Limpiar(){
txtid.setText("")
txtNomP.setText("")
txtExis.setText("")
txtPrec.setText("")
txtid.requestFocus()
}
}

En este punto puede probar ejecutar la aplicación de dar de alta algunos productos y buscarlos,
para comprobar su funcionalidad.

72
MANUAL DE PRÁCTICAS DE LA MATERIA “DESARROLLO DE APLICACIONES
PARA DISPOSITIVOS MÓVILES”
Carrera Ingeniería en Tecnologías de la Información y Comunicaciones
Elaborado por: Alejandro Guzmán Zazueta

Spinner
Un spinner es un elemento de la Interfaz de usuario, el cual es como una lista expandible. Se
pueden colocar varios elementos para que el usuario elija uno (Tutoriales, 2020).

El spinner solo mostrará una de las opciones, pero al momento en que el usuario de clic en el
spinner, éste mostrará todas las opciones y el usuario podrá elegir la que desee, ver figura 26. En
otros lenguajes este control es conocido con otro nombre, por ejemplo, en aplicaciones Windows
con C# es un ComboBox, en programación web HTML es un select, etc.

Figura 26

Control Spinner

Nota: Diseño de control Spinner

Para llenar el Spinner con las opciones del usuario, estas deberán provenir de cualquier fuente,
pero deben proporcionarse a través de un SpinnerAdapter, como un ArrayAdapter si las opciones
están disponibles en una matriz o un CursorAdapter si las opciones están disponibles en una
consulta de base de datos.

73
MANUAL DE PRÁCTICAS DE LA MATERIA “DESARROLLO DE APLICACIONES
PARA DISPOSITIVOS MÓVILES”
Carrera Ingeniería en Tecnologías de la Información y Comunicaciones
Elaborado por: Alejandro Guzmán Zazueta

Llenar un Spinner
Para llenar un Spinner vamos a utilizar el Ejercicio de Base de Datos SQLite (anterior), al cual se
agregará una nueva actividad de nombre MainActivity2 y en esta vamos agregar un control spinner
de nombre spProducto, el cual lo llenaremos con los productos que se dieron de alta en la base de
datos, como se muestra en la figura 27:

Figura 27

Spinner de Productos

Nota: Diseño de la interfaz con spinner de productos

El código de esta interfaz se muestra a continuación:

<?xml version="1.0" encoding="utf-8"?>


<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity2">

<Spinner
android:id="@+id/spProducto"
android:layout_width="250dp"
android:layout_height="wrap_content"
android:layout_marginTop="132dp"

74
MANUAL DE PRÁCTICAS DE LA MATERIA “DESARROLLO DE APLICACIONES
PARA DISPOSITIVOS MÓVILES”
Carrera Ingeniería en Tecnologías de la Información y Comunicaciones
Elaborado por: Alejandro Guzmán Zazueta

app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.756"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />

<TextView
android:id="@+id/textView2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="36dp"
android:layout_marginTop="132dp"
android:layout_marginEnd="8dp"
android:text="Producto:"
android:textAppearance="@style/TextAppearance.AppCompat.Medium"
app:layout_constraintEnd_toStartOf="@+id/spProducto"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>

En seguida se va agregar una clase de nombre Producto, donde definiremos las


propiedades del producto, con su constructor:

package com.example.appsqlite

class Producto(idProd : Int,NomProd : String, Existencia : Int, Precio


: Double) {
var idp : Int = 0
var nomp : String = ""
var exist : Int = 0
var pre : Double = 0.0

init {
this.idp = idProd
this.nomp = NomProd
this.exist = Existencia
this.pre = Precio
}
}

Esta clase se va a utilizar para crear una lista de instancias de Productos.

En seguida se muestra el código de Kotlin del MainActivity2:

75
MANUAL DE PRÁCTICAS DE LA MATERIA “DESARROLLO DE APLICACIONES
PARA DISPOSITIVOS MÓVILES”
Carrera Ingeniería en Tecnologías de la Información y Comunicaciones
Elaborado por: Alejandro Guzmán Zazueta

package com.example.appsqlite

import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.view.View
import android.widget.AdapterView
import android.widget.ArrayAdapter
import android.widget.Spinner
import android.widget.Toast

class MainActivity2 : AppCompatActivity() {


private lateinit var spProd : Spinner
var admin = AdminBD(this)
var arregloProducto : MutableList<Producto> = ArrayList() //
Arreglo de instacias de Productos
var arregloNomProd : MutableList<String> = ArrayList() // Arreglo
de nombres de producto que se mostraran en el Spinner
var idprod : Int = 0

override fun onCreate(savedInstanceState: Bundle?) {


super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main2)
spProd = findViewById<Spinner>(R.id.spProducto)
LlenarArreglosProductos()
// Definimos el adaptador del Spinner con el arreglo de nombres
de productos que se van a mostrar
var adaptador =
ArrayAdapter(this,android.R.layout.simple_spinner_item,arregloNomProd)
spProd.adapter = adaptador
// Definimos el evento clic del Spinner, el cual regresa el
indice con el elemento en que
// dimos clic
spProd.onItemSelectedListener = object :
AdapterView.OnItemSelectedListener{
override fun onItemSelected(p0: AdapterView<*>?, p1: View?,
indice: Int, p3: Long) {
idprod = arregloProducto[indice].idprod
val nomc = arregloProducto[indice].nomprod
Toast.makeText(baseContext, "Diste clic en idProd =
$idprod NomProd = $nomc", Toast.LENGTH_LONG).show()
}

override fun onNothingSelected(p0: AdapterView<*>?) {


TODO("Not yet implemented")
}
}
}
// Función que consulta los productos de a base de datos y llena
los dos arreglos
fun LlenarArreglosProductos(){
val sentencia = "Select idProd,NomProd,Existencia,Precio From
Producto" +
" Order By NomProd"
val tuplas = admin.Consultar(sentencia)

76
MANUAL DE PRÁCTICAS DE LA MATERIA “DESARROLLO DE APLICACIONES
PARA DISPOSITIVOS MÓVILES”
Carrera Ingeniería en Tecnologías de la Información y Comunicaciones
Elaborado por: Alejandro Guzmán Zazueta

while (tuplas!!.moveToNext())
{
val idp = tuplas.getInt(0) // idProd
val nomp = tuplas.getString(1) //NomProd
val exi = tuplas.getInt(2) //Existencia
val pre = tuplas.getDouble(3) //Precio
arregloProducto.add(Producto(idp,nomp,exi,pre))
arregloNomProd.add(nomp)
}
}
}

En el activity_main.xml del ejercicio de Base de Datos SQLite(práctica anterior) agregamos un


botón de nombre btnSpinner para abrir la actividad del Spinner, que es el MainActivity2 como se
observa en la figura 28:

Figura 28

Interfaz del Catálogo de Productos

Nota: Interfaz para abrir la actividad del spinner

a continuación, se muestra el código del botón btnSpinner que deberá de colocar en el


MainActivity.kt :

77
MANUAL DE PRÁCTICAS DE LA MATERIA “DESARROLLO DE APLICACIONES
PARA DISPOSITIVOS MÓVILES”
Carrera Ingeniería en Tecnologías de la Información y Comunicaciones
Elaborado por: Alejandro Guzmán Zazueta

fun btnSpinner(view: View) {


var actividad = Intent(this,MainActivity2::class.java)
startActivity(actividad)
}

La interfaz de la aplicación en ejecución se muestra en la siguiente figura 29:

Figura 29

Interfaz del Catálogo de Productos

Nota: Interfaz en ejecución del Catálogo de Productos

78
MANUAL DE PRÁCTICAS DE LA MATERIA “DESARROLLO DE APLICACIONES
PARA DISPOSITIVOS MÓVILES”
Carrera Ingeniería en Tecnologías de la Información y Comunicaciones
Elaborado por: Alejandro Guzmán Zazueta

Recyclerview

¿Qué es RecyclerView?

La clase RecyclerView nos permite mostrar un listado (o bien una grilla) de elementos (PYM, 2017).
Lleva este nombre porque a medida que se renderizan los elementos de la lista, los elementos que
dejan de observarse se reciclan para mostrar los elementos siguientes (PyM, 2023).

RecyclerView es una versión mejorada de la clase ListView, principalmente cuando el número de


elementos es variable, y/o los datos cambian continuamente.

Es posible personalizar un ListView para lograr lo mismo, pero implicaría considerar varios detalles,
a fin de conseguir el mismo rendimiento.

¿Qué es CardView?
Si bien un RecyclerView representa una lista de elementos, cada elemento debe tener una UI
definida.

Al usar Material Design se suele usar la clase CardView para definir la apariencia de cada
elemento de un listado, en la mayoría de los casos.

RecyclerView + CardView, ¿siempre juntos?


No es obligatorio que se usen en conjunto, pero es usual hacerlo.

¿En qué casos no se usarían en conjunto?


Hay ocasiones en que se desea mostrar algo puntual. Entonces un elemento puede ser tan simple
como un TextView, sin usar un CardView como contenedor.

79
MANUAL DE PRÁCTICAS DE LA MATERIA “DESARROLLO DE APLICACIONES
PARA DISPOSITIVOS MÓVILES”
Carrera Ingeniería en Tecnologías de la Información y Comunicaciones
Elaborado por: Alejandro Guzmán Zazueta

Es posible usar CardViews directamente sobre un Activity o Fragment, sin situarlos al interior de
un RecyclerView.

Cuando no se requiere usar tarjetas con bordes y elevaciones, entonces se puede prescindir de la
clase CardView.

Es posible usar cualquier otro componente visual para representar al layout de cada elemento del
RecyclerView.

Funcionamiento del Recyclerview


La funcionalidad del recyclerview la puede observar en la figura 30:

Figura 30

Funcionamiento de Recyclerview

Nota: Representación del funcionamiento de Recyclerview

• RecyclerView: El RecyclerView se va a "pintar" en función al LayoutManager que reciba


como parámetro. También hará uso de un Adapter, que funcionará de acuerdo a un
Dataset.
• LayoutManager: Este "gestor del diseño" va a definir la disposición de los elementos. Es
decir, si van formando una lista vertical u horizontal, si van formando una cuadrícula, u otra
variante.

80
MANUAL DE PRÁCTICAS DE LA MATERIA “DESARROLLO DE APLICACIONES
PARA DISPOSITIVOS MÓVILES”
Carrera Ingeniería en Tecnologías de la Información y Comunicaciones
Elaborado por: Alejandro Guzmán Zazueta

• Adapter: El adaptador se encargará de adaptar el dataset a lo que finalmente verá el


usuario. Es el encargado de traducir datos en la interfaz del suario
• Dataset: Es el conjunto de datos que se espera mostrar en el RecyclerView. Se puede
representar por un simple array de objetos String; o ser algo más elaborado, como
un ArrayList de objetos que presentan múltiples atributos.

Llenar un Recyclerview
Para llenar un Recyclerview vamos a utilizar el ejercicio la Ejercicio 6, al cual se agregará una nueva
actividad de nombre MainActivityRecycler la cual contendrá un Recyclerview con los productos
que están almacenados en la base de datos. La figura 31 ilustra como quedara la interfaz:

Figura 31

Interfaz de la aplicación Llenar Recyclerview

Nota: Diseño de la funcionalidad de la interfaz de la aplicación Llenar Recyclerview

81
MANUAL DE PRÁCTICAS DE LA MATERIA “DESARROLLO DE APLICACIONES
PARA DISPOSITIVOS MÓVILES”
Carrera Ingeniería en Tecnologías de la Información y Comunicaciones
Elaborado por: Alejandro Guzmán Zazueta

Agregaremos el Recyclerview a la interfaz del activity_main_recycler.xml. A continuación, se


muestra el código de la actividad:

activity_main_recycler.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:padding="20dp"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivityRecycler">

<androidx.recyclerview.widget.RecyclerView
android:id="@+id/rvProductosList"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scrollbars="vertical"
tools:layout_editor_absoluteX="1dp"
tools:layout_editor_absoluteY="1dp" />
</androidx.constraintlayout.widget.ConstraintLayout>

En seguida agregamos un archivo dando clic derecho en la carpeta Layout y seleccionamos “Layout
Resource File” y le ponemos el nombre celda_prototipo.xml, en este agregamos una CardView y
un LinearLayout(vertical), dentro de este último agregamos los 2 textview que vamos a desplegar
en cada elemento del RecyclerView, el código se muestra a continuación:

celda_prototipo.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.cardview.widget.CardView
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:orientation="vertical"
android:layout_margin="10dp"
app:cardCornerRadius="40dp">
<LinearLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="30dp">
<TextView
android:id="@+id/tvnomProd"

82
MANUAL DE PRÁCTICAS DE LA MATERIA “DESARROLLO DE APLICACIONES
PARA DISPOSITIVOS MÓVILES”
Carrera Ingeniería en Tecnologías de la Información y Comunicaciones
Elaborado por: Alejandro Guzmán Zazueta

android:textAppearance="@style/TextAppearance.AppCompat.Medium"
android:layout_width="match_parent"
android:text="Alex Lora"
android:textSize="18sp"
android:layout_height="wrap_content"/>
<TextView
android:id="@+id/tvPrecio"

android:textAppearance="@style/TextAppearance.AppCompat.Small"
android:text="Ing. Sistemas Computacionales"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
</LinearLayout>
</androidx.cardview.widget.CardView>

A continuación, agregamos una clase de kotlin de nombre Producto.kt, en esta agregamos las
propiedades y su constructor. Esta clase nos va a servir para crear una Lista de Productos y poder
llenar el RecyclerView, en seguida se muestra el código de la clase (esta clase ya la creamos en el
ejercicio anterior Llenar un Spinner):

Producto.kt
package com.example.appsqlite

class Producto(idProd : Int,NomProd : String, Existencia : Int, Precio


: Double) {
var idprod : Int = 0
var nomprod : String = ""
var existencia : Int = 0
var precio : Double = 0.0

init {
this.idprod = idProd
this.nomprod = NomProd
this.existencia = Existencia
this.precio = Precio
}
}

En seguida agregamos el adapter del Recyclerview. Un adapter es la clase que hace de puente
entre la vista (el recyclerview) y los datos.

Un adapter:

83
MANUAL DE PRÁCTICAS DE LA MATERIA “DESARROLLO DE APLICACIONES
PARA DISPOSITIVOS MÓVILES”
Carrera Ingeniería en Tecnologías de la Información y Comunicaciones
Elaborado por: Alejandro Guzmán Zazueta

• contiene una clase interna ViewHolder, que permite obtener referencias de


los componentes visuales (views) de cada elemento de la lista,
• presenta un constructor y/o métodos para gestionar el Data Set (añadir, editar o
eliminar elementos),
• contiene un método onCreateViewHolder que infla el layout (archivo xml) que
representa a nuestros elementos, y devuelve una instancia de la clase ViewHolder
que antes definimos;
• contiene un método onBindViewHolder que enlaza nuestra data con cada
ViewHolder, y
• contiene un método getItemCount que devuelve un entero indicando la cantidad de
elementos a mostrar en el RecyclerView.

Creamos una nueva clase llamada ProductoAdapter.kt, el código se muestra a continuación:

ProductoAdapter.kt
package com.example.appsqlite

import android.content.Context
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.TextView
import androidx.recyclerview.widget.RecyclerView
//-----------------------------------------------------------
// Adaptador del RecyclerView
// Es la clase que hace de puente entre la vista
// (el recyclerview) y los datos
//
//-----------------------------------------------------------
class ProductoAdapter(private var mLista:List<Producto>,
private val mContext: Context, private val
clickListener: (Producto) -> Unit)
: RecyclerView.Adapter<ProductoAdapter.ProductoViewHolder>() {

/**
* El layout manager invoca este método para renderizar cada
elemento
*/
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int):
ProductoViewHolder {
val layoutInflater = LayoutInflater.from(mContext)
return
ProductoViewHolder(layoutInflater.inflate(R.layout.celda_prototipo,

84
MANUAL DE PRÁCTICAS DE LA MATERIA “DESARROLLO DE APLICACIONES
PARA DISPOSITIVOS MÓVILES”
Carrera Ingeniería en Tecnologías de la Información y Comunicaciones
Elaborado por: Alejandro Guzmán Zazueta

parent, false))
}

/**
* Este método asigna valores para cada elemento de la lista
*
* @param holder Vincular los datos del cursor al ViewHolder
* @param position La posición de los datos en la lista
*/
override fun onBindViewHolder(holder: ProductoViewHolder, position:
Int) {
holder.bind(mLista[position], mContext, clickListener)
}

/**
* El método getItemCount() Cantidad de elementos del RecyclerView
*/
override fun getItemCount(): Int = mLista.size

/**
* Cuando los datos cambian, este metodo actualiza la lista de
Productos
* y notifica al adaptador a usar estos nuevos valores
*/
fun setTask(lista: List<Producto>){
mLista = lista
notifyDataSetChanged()
}

fun getTasks(): List<Producto> = mLista

/*
* Clase interna para asignar los valores a los textView definidos
en la celda_prototipo
*/
class ProductoViewHolder (itemView: View)
:RecyclerView.ViewHolder(itemView) {
val titulo: TextView = itemView.findViewById(R.id.tvnomProd)
val subTitulo: TextView = itemView.findViewById(R.id.tvPrecio)

fun bind (prod:Producto, context: Context, clickListener:


(Producto) -> Unit){
//Asigna los valores a los elementos del la
celda_prototipo_estudiante
titulo.text = prod.nomprod.toString()
subTitulo.text = prod.precio.toString()

itemView.setOnClickListener{ clickListener(prod)}
}
}
}

85
MANUAL DE PRÁCTICAS DE LA MATERIA “DESARROLLO DE APLICACIONES
PARA DISPOSITIVOS MÓVILES”
Carrera Ingeniería en Tecnologías de la Información y Comunicaciones
Elaborado por: Alejandro Guzmán Zazueta

Por último, vamos a agregar el código del MainActivityRecycler.kt, en este propiamente manda
ejecutar la consulta a la base de datos y en seguida se llena una Lista de estudiantes y esta se le da
al adaptador para llenar el RecyclerView:

MainActivityRecycler.kt
package com.example.appsqlite

import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.widget.Toast
import androidx.recyclerview.widget.DividerItemDecoration
import androidx.recyclerview.widget.ItemTouchHelper
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView

class MainActivityRecycler : AppCompatActivity() {


private lateinit var rvProdList : RecyclerView
private lateinit var viewAdapter: ProductoAdapter
private lateinit var viewManager: RecyclerView.LayoutManager
val productoList: List<Producto> = ArrayList()

override fun onCreate(savedInstanceState: Bundle?) {


super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main_recycler)
rvProdList = findViewById<RecyclerView>(R.id.rvProductosList)
viewManager = LinearLayoutManager(this)
viewAdapter = ProductoAdapter(productoList, this, { prod:
Producto -> onItemClickListener(prod) })

rvProdList.apply {
setHasFixedSize(true)
layoutManager = viewManager
adapter = viewAdapter

addItemDecoration(DividerItemDecoration(this@MainActivityRecycler,
DividerItemDecoration.VERTICAL))
}

// Metodo para implementar la eliminación de un estudiante,


cuando el ususario da un onswiped en
// el recyclerview
ItemTouchHelper(object : ItemTouchHelper.SimpleCallback(0,
ItemTouchHelper.LEFT or ItemTouchHelper.RIGHT) {
override fun onMove(recyclerView: RecyclerView, viewHolder:
RecyclerView.ViewHolder, target: RecyclerView.ViewHolder): Boolean {
return false
}

override fun onSwiped(viewHolder: RecyclerView.ViewHolder,


swipeDir: Int) {
val position = viewHolder.adapterPosition

86
MANUAL DE PRÁCTICAS DE LA MATERIA “DESARROLLO DE APLICACIONES
PARA DISPOSITIVOS MÓVILES”
Carrera Ingeniería en Tecnologías de la Información y Comunicaciones
Elaborado por: Alejandro Guzmán Zazueta

val prod= viewAdapter.getTasks()


val admin = AdminBD(baseContext)
if (admin.Ejecuta("DELETE From Producto WHERE idProd="
+ prod[position].idprod)){
retrieveProductos()
}
}
}).attachToRecyclerView(rvProdList)
} // Fin del OnCreate----------------------------------------

// Evento clic cuando damos clic en un elemento del Recyclerview


private fun onItemClickListener(Prod: Producto) {
Toast.makeText(this, "Clicked item" + Prod.nomprod,
Toast.LENGTH_LONG).show()
}

override fun onResume() {


super.onResume()
retrieveProductos()
}

private fun retrieveProductos() {


val productox = getProductos()
viewAdapter.setTask(productox!!)
}

fun getProductos(): MutableList<Producto>{


var ListaProductos:MutableList<Producto> = ArrayList()
val admin = AdminBD(this)

// 0 1 2
3
val tupla = admin.Consultar("SELECT
idProd,NomProd,Existencia,Precio FROM Producto ORDER BY nomProd")
while (tupla!!.moveToNext()) {
val idp = tupla.getString(0).toInt()
val nomp = tupla.getString(1)
val exi = tupla.getString(2).toInt()
val pre = tupla.getInt(3).toDouble()

ListaProductos.add(Producto(idp,nomp,exi,pre))
}
tupla.close()
admin.close()
return ListaProductos
}
}

87
MANUAL DE PRÁCTICAS DE LA MATERIA “DESARROLLO DE APLICACIONES
PARA DISPOSITIVOS MÓVILES”
Carrera Ingeniería en Tecnologías de la Información y Comunicaciones
Elaborado por: Alejandro Guzmán Zazueta

La figura 32 ilustra como se ve la aplicación una vez que presionamos clic en el botón de llenar
recyclerview:

Figura 32

Interfaz de la actividad MainActivityRecycler

Nota: Ejecución de la actividad MainActivityRecycler.kt

88
MANUAL DE PRÁCTICAS DE LA MATERIA “DESARROLLO DE APLICACIONES
PARA DISPOSITIVOS MÓVILES”
Carrera Ingeniería en Tecnologías de la Información y Comunicaciones
Elaborado por: Alejandro Guzmán Zazueta

Práctica 6. Servicios Web

Objetivo
El estudiante aprenderá a usar servicios web para que intercambiar información entre las
aplicaciones móviles y servidores web.

Introducción
Esta práctica tiene como fin comprender el uso de los servicios web para el intercambio de
información entre aplicaciones.

Correlación con los temas y subtemas del programa de estudio


Esta práctica abona al contenido de los temas:
4.4 XML.
4.5 JSON.

Material y equipo necesario


Computadora i3, i5 o i7 con mínimo de 8GB de Ram.
Acceso a Internet, para la creación de nuevo proyecto en Android Studio.

Metodología
El estudiante deberá leer el siguiente material previo a la elaboración de la práctica:

89
MANUAL DE PRÁCTICAS DE LA MATERIA “DESARROLLO DE APLICACIONES
PARA DISPOSITIVOS MÓVILES”
Carrera Ingeniería en Tecnologías de la Información y Comunicaciones
Elaborado por: Alejandro Guzmán Zazueta

Servicios Web

Figura 33

Elementos de Servicios Web

Nota: Representación de los elementos en Servicios Web

Un Web Service o Servicio Web es una aplicación que facilita la comunicación entre varios sistemas
independientemente del lenguaje de programación o plataforma en que fueron desarrollados,
como se observa en la figura 33. Este debe tener una interfaz basada en un formato estándar
entendible por las maquinas como lo es XML o JSON.

Dos alternativas para programar los servicios web SOAP(XML) o REST(Json) (Naeem, 2020).

¿Qué es SOAP “Simple Object Access Protocol”?


SOAP es un protocolo estándar que define cómo dos objetos en diferentes procesos pueden
comunicarse por medio de intercambio de datos XML. Este protocolo deriva de un protocolo

90
MANUAL DE PRÁCTICAS DE LA MATERIA “DESARROLLO DE APLICACIONES
PARA DISPOSITIVOS MÓVILES”
Carrera Ingeniería en Tecnologías de la Información y Comunicaciones
Elaborado por: Alejandro Guzmán Zazueta

creado por Dave Winer en 1998, llamado XML-RPC. SOAP fue creado por Microsoft, IBM y otros.
Está actualmente bajo el auspicio de la W3C.

¿Qué significa REST(transferencia de estado representacional)?

REST es una interfaz para conectar varios sistemas basados en el protocolo HTTP (uno de los
protocolos más antiguos) y nos sirve para obtener y generar datos y operaciones, devolviendo esos
datos en formatos muy específicos, como XML y JSON.

El formato más usado en la actualidad es el formato JSON, ya que es más ligero y legible en
comparación al formato XML. Elegir uno será cuestión de la lógica y necesidades de cada proyecto.

REST se apoya en HTTP, los verbos que utiliza son exactamente los mismos, con ellos se puede
hacer GET, POST, PUT y DELETE. De aquí surge una alternativa a SOAP.

Cuando hablamos de SOAP hablamos de una arquitectura divididas por niveles que se utilizaba
para hacer un servicio, es más complejo de montar como de gestionar y solo trabajaba con XML.

Ahora bien, REST llega a solucionar esa complejidad que añadía SOAP, haciendo mucho más fácil
el desarrollo de una API REST, en este caso de un servicio en el cual nosotros vamos a almacenar
nuestra lógica de negocio y vamos servir los datos con una serie de recursos URL y una serie de
datos que nosotros los limitaremos, es decir, será nuestro BACKEND nuestra lógica pura de
negocios que nosotros vamos a utilizar.

¿Qué es y para qué sirve JSON? (Perez, 2016)

JSON (JavaScript Object Notation) es un formato para el intercambio de datos, básicamente JSON
describe los datos con una sintaxis dedicada que se usa para identificar y gestionar los datos. JSON

91
MANUAL DE PRÁCTICAS DE LA MATERIA “DESARROLLO DE APLICACIONES
PARA DISPOSITIVOS MÓVILES”
Carrera Ingeniería en Tecnologías de la Información y Comunicaciones
Elaborado por: Alejandro Guzmán Zazueta

nació como una alternativa a XML, el fácil uso en javascript ha generado un gran número de
seguidores de esta alternativa. Una de las mayores ventajas que tiene el uso de JSON es que puede
ser leído por cualquier lenguaje de programación. Por lo tanto, puede ser usado para el
intercambio de información entre distintas tecnologías.

Imaginemos que tenemos una frutería y que queremos obtener el nombre y la cantidad de fruta y
verdura que tenemos. En un principio vamos a suponer que tenemos lo siguiente:

Ø Fruta:

• 10 manzanas
• 20 peras
• 30 naranjas

Ø Verduras

• 80 lechugas
• 15 tomates
• 50 pepinos

Para empezar, nos tenemos que familiarizar con la sintaxis de Json:

JSON Nombre/Par de Valores

Para asignar a un nombre un valor debemos usar los dos puntos ':' este separador es el
equivalente al igual ('=') de cualquier lenguaje.

{"Nombre" : "Alex Lora"}

Los tipos de valores que podemos encontrar en Json son los siguientes:

92
MANUAL DE PRÁCTICAS DE LA MATERIA “DESARROLLO DE APLICACIONES
PARA DISPOSITIVOS MÓVILES”
Carrera Ingeniería en Tecnologías de la Información y Comunicaciones
Elaborado por: Alejandro Guzmán Zazueta

• Un número (entero o float)


• Un string (entre comillas simples)
• Un booleano (true o false)
• Un array (entre corchetes [] )
• Un objeto (entre llaves {})
• Null

Objetos JSON

Los objetos JSON se identifican entre llaves, un objeto puede ser en nuestro caso una fruta
o una verdura.

{ "NombreFruta":"Manzana" , "Cantidad":20 }

Arrays JSON

En un JSON puedes incluir arrays, para ellos el contenido del array debe ir entre corchetes
[ ]:

"Frutas": [

{ "NombreFruta":"Manzana" , "cantidad":10 },

{ "NombreFruta":"Pera" , "cantidad":20 },

{ "NombreFruta":"Naranja" , "cantidad":30 }

93
MANUAL DE PRÁCTICAS DE LA MATERIA “DESARROLLO DE APLICACIONES
PARA DISPOSITIVOS MÓVILES”
Carrera Ingeniería en Tecnologías de la Información y Comunicaciones
Elaborado por: Alejandro Guzmán Zazueta

Una vez explicado el funcionamiento de la sintaxis JSON, vamos a aplicar nuestro ejemplo
de la frutería:

{"Fruteria":
[
{"Fruta":
[

{"Nombre":"Manzana","Cantidad":10},

{"Nombre":"Pera","Cantidad":20},

{"Nombre":"Naranja","Cantidad":30}

},

{"Verdura":

{"Nombre":"Lechuga","Cantidad":80},

{"Nombre":"Tomate","Cantidad":15},

{"Nombre":"Pepino","Cantidad":50}

Como podemos observar, hemos creado un objeto llamado frutería y, dentro de ese objeto
hemos almacenado un array de dos elementos. El primer elemento del array contiene un

94
MANUAL DE PRÁCTICAS DE LA MATERIA “DESARROLLO DE APLICACIONES
PARA DISPOSITIVOS MÓVILES”
Carrera Ingeniería en Tecnologías de la Información y Comunicaciones
Elaborado por: Alejandro Guzmán Zazueta

objeto llamado fruta y el segundo elemento del array contiene otro objeto llamado
verdura. Estos objetos a su vez contienen un array cuyo contenido es el nombre y la
cantidad de cada fruta o verdura.

Existen herramientas online que ayudan a visualizar mejor un JSON. Una de las mejores
herramientas es la página JSON Viewer, como se observa en la figura 34. Si introducimos
nuestro ejemplo observamos lo siguiente:

Figura 34

Visor de JSON

Nota: Aplicación Web para visualizar jSON

¿Por qué debemos utilizar REST?

REST no es solo una moda, y es por las siguientes razones que esta interfaz está teniendo
tanto protagonismo en los últimos años:

• Crea una petición HTTP que contiene toda la información necesaria, es decir, un
REQUEST a un servidor tiene toda la información necesaria y solo espera una
RESPONSE, ósea una respuesta en concreto.

95
MANUAL DE PRÁCTICAS DE LA MATERIA “DESARROLLO DE APLICACIONES
PARA DISPOSITIVOS MÓVILES”
Carrera Ingeniería en Tecnologías de la Información y Comunicaciones
Elaborado por: Alejandro Guzmán Zazueta

• Se apoya sobre un protocolo que es el que se utiliza para las páginas web, que es
HTTP, es un protocolo que existe hace muchos años y que ya está consolidado, no
se tiene que inventar ni realizar cosas nuevas.

• Se apoya en los métodos básicos de HTTP, como son:

• Post: Para crear recursos nuevos.


• Get: Para obtener un recurso en concreto.
• Put: Para modificar.
• Delete: Para borrar un recurso, un dato por ejemplo de nuestra base de datos.

• Todos los objetos se manipulan mediante URI, por ejemplo, si tenemos un recurso usuario
y queremos acceder a un usuario en concreto nuestra URI seria
/user/identificadordelobjeto, con eso ya tendríamos un servicio USER preparado para
obtener la información de un usuario, dado un ID.

Ventajas de REST

• Nos permite separar el cliente del servidor. Esto quiere decir que nuestro servidor se puede
desarrollar en Node y Express, y nuestra API REST con Vue por ejemplo, no tiene por qué
estar todos dentro de un mismo.
• En la actualidad tiene una gran comunidad como proyecto en Github.
• Podemos crear un diseño de un microservicio orientado a un dominio (DDD)
• Es totalmente independiente de la plataforma, así que podemos hacer uso de REST tanto
en Windows, Linux, Mac o el sistema operativo que nosotros queramos.
• Podemos hacer nuestra API pública, permitiendo darnos visibilidad si la hacemos pública.
• Nos da escalabilidad, porque tenemos la separación de conceptos de CLIENTE y SERVIDOR,
por tanto, podemos dedicarnos exclusivamente a la parte del servidor.

96
MANUAL DE PRÁCTICAS DE LA MATERIA “DESARROLLO DE APLICACIONES
PARA DISPOSITIVOS MÓVILES”
Carrera Ingeniería en Tecnologías de la Información y Comunicaciones
Elaborado por: Alejandro Guzmán Zazueta

¿Quién usa REST?

Muchas empresas como Twitter, Facebook, Google, Netflix, LinkedIn y miles de startups y
empresas usan REST. Todos estas empresas y servicios tienen su API REST por un lado con su lógica
de negocio y por otro lado su parte front-end, con lo cual nos permite centrarnos también un poco
más en lo que es nuestra lógica de negocio haciendo una API REST potente.

Los servicios web responden con códigos de estado de respuesta HTTP, los cuales indican si se ha
completado satisfactoriamente una solicitud HTTP específica. Las respuestas se agrupan en cinco
clases:

Respuestas informativas (100–199),

Respuestas satisfactorias (200–299)

200 OK. La solicitud ha tenido éxito. El significado de un éxito varía dependiendo del
método HTTP:

201 Created. La solicitud ha tenido éxito y se ha creado un nuevo recurso como resultado
de ello. Ésta es típicamente la respuesta enviada después de una petición PUT.

Redirecciones (300–399)

Errores de los clientes (400–499)

400 Bad Request. Esta respuesta significa que el servidor no pudo interpretar la solicitud
dada una sintaxis inválida.

401 Unauthorized. Es necesario autenticar para obtener la respuesta solicitada. Esta es


similar a 403, pero en este caso, la autenticación es posible.

97
MANUAL DE PRÁCTICAS DE LA MATERIA “DESARROLLO DE APLICACIONES
PARA DISPOSITIVOS MÓVILES”
Carrera Ingeniería en Tecnologías de la Información y Comunicaciones
Elaborado por: Alejandro Guzmán Zazueta

404 Not Found. El servidor no pudo encontrar el contenido solicitado. Este código de
respuesta es uno de los más famosos dada su alta ocurrencia en la web.

Errores de los servidores (500–599).

500 Internal Server Error. El servidor ha encontrado una situación que no sabe cómo
manejarla.

501 Not Implemented. El método solicitado no está soportado por el servidor y no puede
ser manejado. Los únicos métodos que los servidores requieren soporte (y por lo tanto no
deben retornar este código) son GET y HEAD.

98
MANUAL DE PRÁCTICAS DE LA MATERIA “DESARROLLO DE APLICACIONES
PARA DISPOSITIVOS MÓVILES”
Carrera Ingeniería en Tecnologías de la Información y Comunicaciones
Elaborado por: Alejandro Guzmán Zazueta

Generación de Servicios Web


Para ejemplificar el uso de servicios web en Android, se va a crear un App que cargue un catálogo
de productos desde un servidor web y que permita agregar, actualizar y eliminar productos del
servidor web directamente. Para lo cual vamos a requerir tener instalado un servidor web, se
recomienda usar Xampp y enseguida se va a crear una base de datos en mysql de nombre
inventario y dentro una tabla de nombre producto, con la estructura que se ve en la figura 35:

Figura 35

Tabla de Producto

Nota: Estructura de la tabla de producto

Una vez creada la tabla vamos a insertar unos 8 productos, como a continuación se muestra:

A continuación, creamos dentro de la carpeta de htdocs una carpeta de nombre WSAndroid, con
los siguientes servicios web:

getProducto.php Consulta un producto


getProductos.php Consulta todos los productos
insertProducto.php Inserta un producto
updateProducto.php Actualiza un producto

99
MANUAL DE PRÁCTICAS DE LA MATERIA “DESARROLLO DE APLICACIONES
PARA DISPOSITIVOS MÓVILES”
Carrera Ingeniería en Tecnologías de la Información y Comunicaciones
Elaborado por: Alejandro Guzmán Zazueta

deleteProducto.php Elimina un producto


resProductos.php Respalda Productos

A continuación, se muestra el código fuente de cada uno de estos servicios web:


El servicio web getProducto.php recibe el id de un producto, lo busca en la base de datos y lo
regresa en formato jSON. Las entradas y salidas ser servicio web las puede observar en la figura
36:

Figura 36

Servicio web getProducto.php

{“idprod”: “2”} {
getProducto.php "success": 200,
"message": "Registro encontrado",
"productos": [
{
"idp": "4",
"nom": "Moto Bomba",
"exi": "5",
"pre": "450.00"
}
]
}

Nota: Entradas y salidas del servicio web getProducto.ohp

getProducto.php
<?php
/*
* El siguiente código localiza un producto
* AGZ Junio 2023
*/
$Cn = mysqli_connect("localhost","root","","android")or die ("server no
encontrado");
mysqli_set_charset($Cn,"utf8");
if ($_SERVER['REQUEST_METHOD']== "POST"){
$objson = json_decode(file_get_contents("php://input"), true);
$idp = $objson["idprod"];
$sentencia = "Select idProd idp,nomProd nom,existencia exi,Precio pre
From Producto Where idProd =$idp";
$res = mysqli_query($Cn,$sentencia);

100
MANUAL DE PRÁCTICAS DE LA MATERIA “DESARROLLO DE APLICACIONES
PARA DISPOSITIVOS MÓVILES”
Carrera Ingeniería en Tecnologías de la Información y Comunicaciones
Elaborado por: Alejandro Guzmán Zazueta

if (mysqli_num_rows($res)>0){
$respuesta["success"] = 200;
$respuesta["message"] = "Registro encontrado";
$respuesta["productos"] = array();
$tupla = mysqli_fetch_array($res,MYSQLI_ASSOC);
$respuesta["productos"] = $tupla;

}
else{
$respuesta["success"] = 404;
$respuesta["message"] = "No hay registros";
}
}
else{
$respuesta["success"] = 400;
$respuesta["message"] = "Método incorrecto";
}
echo json_encode($respuesta);
mysqli_close($Cn);
?>

Para probar el servicio web, vamos a usar el software Insomnia, como se muestra en la figura 37:
Figura 37

Servicio web getProducto.php en Insomnia

Nota: Prueba del servicio web getProducto.php en Insomnia.

101
MANUAL DE PRÁCTICAS DE LA MATERIA “DESARROLLO DE APLICACIONES
PARA DISPOSITIVOS MÓVILES”
Carrera Ingeniería en Tecnologías de la Información y Comunicaciones
Elaborado por: Alejandro Guzmán Zazueta

Servicio web getProductos.php, este se encarga de regresar todos los productos que hay en la base
de datos en formato JSON, la figura 38 ilustra las salidas en formato JSON:
Figura 38

Servicio web getProductos.php

getProductos.php {
"success": 200,
"message": "Registros encontrados",
"productos": [
{
"idp": "2",
"nom": "Desarmador Plano",
"exi": "12",
"pre": "50.00"
},
{
"idp": "1",
"nom": "Taladro",
"exi": "7",
"pre": "850.00"
}
]
}

Nota: Salidas del servicio web getProducto.php

getProductos.php
<?php
/*
* El siguiente código consulta todos los productos
* AGZ Junio 2023
*/
$Cn = mysqli_connect("localhost","root","","android")or die ("server no
encontrado");
mysqli_set_charset($Cn,"utf8");
if ($_SERVER['REQUEST_METHOD']== "POST"){
$sentencia = "Select idProd idp,nomProd nom,existencia exi,Precio pre
From Producto Order by nomProd";
$res = mysqli_query($Cn,$sentencia);
if (mysqli_num_rows($res)>0){
$respuesta["success"] = 200;

102
MANUAL DE PRÁCTICAS DE LA MATERIA “DESARROLLO DE APLICACIONES
PARA DISPOSITIVOS MÓVILES”
Carrera Ingeniería en Tecnologías de la Información y Comunicaciones
Elaborado por: Alejandro Guzmán Zazueta

$respuesta["message"] = "Registros encontrados";


$respuesta["productos"] = array();
while ($tupla = mysqli_fetch_array($res,MYSQLI_ASSOC)){
$Producto = Array();
$Producto = $tupla;
array_push($respuesta["productos"], $Producto);
}
}
else{
$respuesta["success"] = 404;
$respuesta["message"] = "No hay registros";
}
}
else{
$respuesta["success"] = 400;
$respuesta["message"] = "Método incorrecto";
}
echo json_encode($respuesta);
mysqli_close($Cn);
?>

A continuación la figura 39 muestra la prueba del servicio web en insomnia:

Figura 39

Servicio web getProductos.php en Insomnia

Nota: Prueba del servicio web getProductos.php en Insomnia

103
MANUAL DE PRÁCTICAS DE LA MATERIA “DESARROLLO DE APLICACIONES
PARA DISPOSITIVOS MÓVILES”
Carrera Ingeniería en Tecnologías de la Información y Comunicaciones
Elaborado por: Alejandro Guzmán Zazueta

Servicio web insertProducto.php. este servicio web recibe los datos de unproducto en formato
JSON y los inserta en la base de datos, regresando el estado de la ejecución del servicio. La figura
40 ilustra las entradas y salidas del servicio web:

Figura 40

Servicio web insertProducto.php

{ "idprod": "8", {“success”:”200”,


insertProducto.php
"nomp": "Pala", “message”:” Registro Insertado”

"exi": "12", }

"pre": "150.00"

}
Nota: Representación de las entradas y salidas del servicio web insertProducto.php

insertProducto.php
<?php
/*
* El siguiente código Inserta un producto
* AGZ Junio 2023
*/
$Cn = mysqli_connect("localhost","root","","android")or die ("server no
encontrado");
mysqli_set_charset($Cn,"utf8");
if ($_SERVER['REQUEST_METHOD']== "POST"){
$objson = json_decode(file_get_contents("php://input"), true);
$nom = $objson["nom"];
$exi = $objson["exi"];
$pre = $objson["pre"];
$sentencia = "Insert into Producto(nomProd,existencia,Precio)
values ('$nom',$exi,$pre)";

$res = mysqli_query($Cn,$sentencia);
if ($res){
$respuesta["success"] = 200;
$respuesta["message"] = "Registro Insertado";
$respuesta["id"]=$Cn->insert_id;
} else {

104
MANUAL DE PRÁCTICAS DE LA MATERIA “DESARROLLO DE APLICACIONES
PARA DISPOSITIVOS MÓVILES”
Carrera Ingeniería en Tecnologías de la Información y Comunicaciones
Elaborado por: Alejandro Guzmán Zazueta

$respuesta["success"] = 404;
$respuesta["message"] = "No se inserto el Producto";
}
}
else{
$respuesta["success"] = 400;
$respuesta["message"] = "Método incorrecto";
}
echo json_encode($respuesta);
mysqli_close($Cn);
?>

A continuación la figura 41 muestra la prueba del servicio web en insomnia:

Figura 41

Servicio web insertProducto.php en Insomnia

Nota: Prueba del servicio web insertProducto.php en Insomnia

105
MANUAL DE PRÁCTICAS DE LA MATERIA “DESARROLLO DE APLICACIONES
PARA DISPOSITIVOS MÓVILES”
Carrera Ingeniería en Tecnologías de la Información y Comunicaciones
Elaborado por: Alejandro Guzmán Zazueta

Servicio web updateProducto.php, que recibe los datos de un producto en formato JSON y lo
actualiza en la base de datos, regresando el estado de la ejecución. La figura 42 ilustra lasentradas
y salidas del servicio web:

Figura 42

Servicio web updateProducto.php

{ "idprod": "2", { “success”:”200”,


updateProducto.php
"nomp": "Desarmador", “message”:” Registro Actualizado”

"exi": "12", }

"pre": "150.00"

}
Nota: Representación de las entradas y salidas del servicio web updateProducto.php

updateProducto.php
<?php
/*
* El siguiente código Actualiza un producto
* AGZ Junio 2023
*/
$Cn = mysqli_connect("localhost","root","","android")or die ("server no
encontrado");
mysqli_set_charset($Cn,"utf8");
if ($_SERVER['REQUEST_METHOD']== "POST"){
$objson = json_decode(file_get_contents("php://input"), true);
$idp = $objson["idp"];
$nom = $objson["nom"];
$exi = $objson["exi"];
$pre = $objson["pre"];
$sentencia = "Update Producto set
nomProd='$nom',existencia=$exi,Precio=$pre Where idProd=$idp";
$res = mysqli_query($Cn,$sentencia);
if ($res){
if (mysqli_affected_rows($Cn) > 0){
$respuesta["success"] = 200;
$respuesta["message"] = "Registro Actualizado";

106
MANUAL DE PRÁCTICAS DE LA MATERIA “DESARROLLO DE APLICACIONES
PARA DISPOSITIVOS MÓVILES”
Carrera Ingeniería en Tecnologías de la Información y Comunicaciones
Elaborado por: Alejandro Guzmán Zazueta

}
else{
$respuesta["success"] = 404;
$respuesta["message"] = "No se actualizo el Producto";
}
} else {
$respuesta["success"] = 404;
$respuesta["message"] = "No se actualizo el Producto";
}
}
else{
$respuesta["success"] = 400;
$respuesta["message"] = "Método incorrecto";
}
echo json_encode($respuesta);
mysqli_close($Cn);
?>

A continuación la figura 43 muestra la prueba del servicio web en insomnia:

Figura 43

Servicio web updateProducto.php en Insomnia

Nota: Prueba del servicio web updateProducto.php en Insomnia

107
MANUAL DE PRÁCTICAS DE LA MATERIA “DESARROLLO DE APLICACIONES
PARA DISPOSITIVOS MÓVILES”
Carrera Ingeniería en Tecnologías de la Información y Comunicaciones
Elaborado por: Alejandro Guzmán Zazueta

Servicio web deleteProducto.php, este recibe el id de un producto en formato JSON y lo elimina


de la base de datos, regresando el estado de la ejecución. La figura 44 ilustra las entradas y salidas:

Figura 44

Servicio web deleteProducto.php

{“idp”: “8”} {
"success": 200,
deleteProducto.php "message": "Registro Eliminado",

Nota: Representación de las entradas y salidas del servicio web deleteProducto.php

deleteProducto.php

<?php
/*
* El siguiente código Elimina un producto
* AGZ Junio 2023
*/
$Cn = mysqli_connect("localhost","root","","android")or die ("server no
encontrado");
mysqli_set_charset($Cn,"utf8");
if ($_SERVER['REQUEST_METHOD']== "POST"){
$objson = json_decode(file_get_contents("php://input"), true);
$idp = $objson["idp"];

$sentencia = "Delete From Producto Where idProd=$idp";


$res = mysqli_query($Cn,$sentencia);
if ($res){
if (mysqli_affected_rows($Cn) > 0){
$respuesta["success"] = 200;
$respuesta["message"] = "Registro Eliminado";
}
else{
$respuesta["success"] = 404;
$respuesta["message"] = "No se elimino el Producto";
}
} else {
$respuesta["success"] = 404;
$respuesta["message"] = "No se elimino el Producto";
}

108
MANUAL DE PRÁCTICAS DE LA MATERIA “DESARROLLO DE APLICACIONES
PARA DISPOSITIVOS MÓVILES”
Carrera Ingeniería en Tecnologías de la Información y Comunicaciones
Elaborado por: Alejandro Guzmán Zazueta

}
else{
$respuesta["success"] = 400;
$respuesta["message"] = "Método incorrecto";
}
echo json_encode($respuesta);
mysqli_close($Cn);
?>

A continuación la figura 45 muestra la prueba del servicio web en insomnia:

Figura 45

Servicio web deleteProducto.php en Insomnia

Nota: Prueba del servicio web deleteProducto.php en Insomnia

109
MANUAL DE PRÁCTICAS DE LA MATERIA “DESARROLLO DE APLICACIONES
PARA DISPOSITIVOS MÓVILES”
Carrera Ingeniería en Tecnologías de la Información y Comunicaciones
Elaborado por: Alejandro Guzmán Zazueta

Servicio web resProductos.php, este recibe un JSON con los productos y los inserta en la base de
datos. La figura 46 ilustra las entradas y salidas del servicio web:
Figura 46

Servicio web resProductos.php

{ {
"correo": "agz@gmail.com", resProductos.php "success": 200,
"contra": "hola", "message": "Se Respaldaron Correctamente"
"productos": [ }
{
"idp": "2",
"nom": "Desarmador Plano ",
"exi": "12",
"pre": "50.00"
},
{
"idp": "3",
"nom": "Martillo",
"exi": "8",
"pre": "45.00"
}
}
Nota: Representación de las entradas y salidas del servicio web resProductos.php

resProductos.php

<?php
/*
* El siguiente recibe un Json con los productos del dispositivo
* y los inserta en mysql con la finalidad de respaldarlos
* AGZ Junio 2023
*/
$Cn = mysqli_connect("localhost","root","","android")or die ("server no
encontrado");
mysqli_set_charset($Cn,"utf8");
header('Content-type: application/json; charset=utf-8');
if ($_SERVER['REQUEST_METHOD']== "POST"){
$response = array();
$obj = json_decode( file_get_contents('php://input'),true );

$objArr = (array)$obj;
if (empty($objArr))
{
$response["success"] = 422; //No encontro información
$response["message"] = "Error: checar json de entrada";
}
else

110
MANUAL DE PRÁCTICAS DE LA MATERIA “DESARROLLO DE APLICACIONES
PARA DISPOSITIVOS MÓVILES”
Carrera Ingeniería en Tecnologías de la Información y Comunicaciones
Elaborado por: Alejandro Guzmán Zazueta

{
$Productos = array();
$corr= $objArr['correo'];
$cont= $objArr['contra'];
$Productos= $objArr['productos'];

foreach ($Productos as $value)


{
$idp = $value['idp'];
$nom = $value['nom'];
$exi = $value['exi'];
$prec = $value['pre'];

$sentencia = "Insert into


Producto(idProd,nomProd,existencia,precio)
values($idp,'$nom',$exi,$prec)";
//echo "$sentencia";
$result = mysqli_query($Cn,$sentencia);
if ($result)
{
$response["success"] = 200;
$response["message"] = "Se Respaldaron Correctamente";
}
else
{
$response["success"] = 500;
$response["message"] = "Error: No se puedo respaldar los
productos";
}
}
}
}
else{
$respuesta["success"] = 400;
$respuesta["message"] = "Método incorrecto";
}
echo json_encode($response);
mysqli_close($Cn);
?>

A continuación la figura 47 muestra la prueba del servicio web en insomnia:


111
MANUAL DE PRÁCTICAS DE LA MATERIA “DESARROLLO DE APLICACIONES
PARA DISPOSITIVOS MÓVILES”
Carrera Ingeniería en Tecnologías de la Información y Comunicaciones
Elaborado por: Alejandro Guzmán Zazueta

Figura 47

Servicio web resProductos.php en Insomnia

Nota: Prueba del servicio web resProductos.php en Insomnia

En este punto podemos confiar en que nuestros servicios web están funcionando, ahora solo falta
probarlos desde Android.

112
MANUAL DE PRÁCTICAS DE LA MATERIA “DESARROLLO DE APLICACIONES
PARA DISPOSITIVOS MÓVILES”
Carrera Ingeniería en Tecnologías de la Información y Comunicaciones
Elaborado por: Alejandro Guzmán Zazueta

Aplicación en Android

Vamos a crear un nuevo proyecto de nombre My ApplicationWS y enseguida vamos a agregar la


librería para que se incluya en nuestro proyecto la librería Volley, que nos permite ejecutar
servicios web en Android. Para esto abrimos el archivo : build.gradle(Module:app)
Y agregamos la siguiente línea al final de la lista de dependencies y le damos sincronizar:

implementation 'com.android.volley:volley:1.2.0'

Ahora vamos a editar el archivo de AndroidManifest.xml y agregamos los permisos para que
nuestra aplicación pueda acceder a internet, el archivo se muestra a continuación:

AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.myproducts">

<uses-permission android:name="android.permission.INTERNET">
</uses-permission>

<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme"
android:usesCleartextTraffic="true">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />

<category android:name="android.intent.category.LAUNCHER" />


</intent-filter>
</activity>
</application>

113
MANUAL DE PRÁCTICAS DE LA MATERIA “DESARROLLO DE APLICACIONES
PARA DISPOSITIVOS MÓVILES”
Carrera Ingeniería en Tecnologías de la Información y Comunicaciones
Elaborado por: Alejandro Guzmán Zazueta

</manifest>

El código que se agregó se encuentra remarcado en amarillo.

A continuación, nos ubicamos en la carpeta de los archivos de Kotlin de nuestro proyecto(ver figura
48) y agregaremos una clase de kotlin de nombre VolleySingleton:

Figura 48

Carpeta de archivos de Kotlin

Nota: Ubicación de la carpeta de los archivos de Kotlin

el código de la clase se muestra a continuación:

VolleySingleton.kt
package com.example.myapplicationws
import android.content.Context
import com.android.volley.Request
import com.android.volley.RequestQueue
import com.android.volley.toolbox.Volley

// Clase que se implementa, para aplicar el patron de diseño Singleton,


// que permite una sola instancia de esta clase
class VolleySingleton constructor(context: Context) {
companion object {

114
MANUAL DE PRÁCTICAS DE LA MATERIA “DESARROLLO DE APLICACIONES
PARA DISPOSITIVOS MÓVILES”
Carrera Ingeniería en Tecnologías de la Información y Comunicaciones
Elaborado por: Alejandro Guzmán Zazueta

@Volatile
private var INSTANCE: VolleySingleton? = null
fun getInstance(context: Context) =
INSTANCE ?: synchronized(this) {
INSTANCE ?: VolleySingleton(context).also {
INSTANCE = it
}
}
}

val requestQueue: RequestQueue by lazy {


Volley.newRequestQueue(context.applicationContext)
}
fun <T> addToRequestQueue(req: Request<T>) {
requestQueue.add(req)
}
}

Esta clase implementa el patrón de diseño singleton, el cual nos permite generar una sola instancia
de la clase volley, siendo más eficiente de esta manera.
El código del layout del activity_main.xml se muestra a continuación:

activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">

<TextView
android:id="@+id/textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Catálogo de Productos"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintVertical_bias="0.06"
android:textAppearance="@style/TextAppearance.AppCompat.Large"
/>

<EditText
android:id="@+id/etIdProd"
android:layout_width="wrap_content"
android:layout_height="wrap_content"

115
MANUAL DE PRÁCTICAS DE LA MATERIA “DESARROLLO DE APLICACIONES
PARA DISPOSITIVOS MÓVILES”
Carrera Ingeniería en Tecnologías de la Información y Comunicaciones
Elaborado por: Alejandro Guzmán Zazueta

android:layout_marginTop="24dp"
android:ems="10"
android:hint="Clave Producto"
android:inputType="numberSigned"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.858"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/textView" />

<EditText
android:id="@+id/etPrecio"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="56dp"
android:ems="10"
android:hint="Precio"
android:inputType="numberDecimal"
android:text="0"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.858"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/etNomProd" />

<EditText
android:id="@+id/etExistencia"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:ems="10"
android:hint="Existencia"
android:inputType="numberSigned"
android:text="0"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.853"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/etPrecio"
app:layout_constraintVertical_bias="0.129" />

<EditText
android:id="@+id/etNomProd"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="44dp"
android:ems="10"
android:hint="Nombre Producto"
android:inputType="textPersonName"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.858"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/etIdProd" />

<Button
android:id="@+id/btnBorrar"
android:layout_width="wrap_content"

116
MANUAL DE PRÁCTICAS DE LA MATERIA “DESARROLLO DE APLICACIONES
PARA DISPOSITIVOS MÓVILES”
Carrera Ingeniería en Tecnologías de la Información y Comunicaciones
Elaborado por: Alejandro Guzmán Zazueta

android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginTop="20dp"
android:layout_marginEnd="8dp"
android:text="Borrar"
android:onClick="Borrar"
app:layout_constraintEnd_toStartOf="@+id/btnActualizar"
app:layout_constraintHorizontal_bias="0.485"
app:layout_constraintStart_toEndOf="@+id/btnAgregar"
app:layout_constraintTop_toBottomOf="@+id/etExistencia" />

<Button
android:id="@+id/btnAgregar"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="48dp"
android:layout_marginTop="20dp"
android:onClick="Agregar"
android:text="Agregar"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/etExistencia" />

<Button
android:id="@+id/btnLimpiar"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
android:layout_marginEnd="100dp"
android:text="Limpiar"
android:onClick="Limpiar"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toBottomOf="@+id/btnBorrar" />

<Button
android:id="@+id/btnActualizar"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
android:layout_marginEnd="28dp"
android:onClick="Actualiza"
android:text="Actualizar"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toBottomOf="@+id/etExistencia" />

<Button
android:id="@+id/btnConsultar"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="100dp"
android:layout_marginTop="20dp"
android:onClick="Consultar"
android:text="Consultar"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/btnBorrar" />

117
MANUAL DE PRÁCTICAS DE LA MATERIA “DESARROLLO DE APLICACIONES
PARA DISPOSITIVOS MÓVILES”
Carrera Ingeniería en Tecnologías de la Información y Comunicaciones
Elaborado por: Alejandro Guzmán Zazueta

<Button
android:id="@+id/btnCarga"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginTop="4dp"
android:layout_marginEnd="8dp"
android:onClick="getAllProductos"
android:text="Carga Productos"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.476"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/btnConsultar" />

<TextView
android:id="@+id/textView2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="112dp"
android:text="Clave Producto:"
app:layout_constraintEnd_toStartOf="@+id/etIdProd"
app:layout_constraintHorizontal_bias="0.328"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />

<TextView
android:id="@+id/textView3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="72dp"
android:text="Nombre Producto:"
app:layout_constraintEnd_toStartOf="@+id/etNomProd"
app:layout_constraintHorizontal_bias="0.432"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/textView2" />

<TextView
android:id="@+id/textView4"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="64dp"
android:text="Precio:"
app:layout_constraintEnd_toStartOf="@+id/etPrecio"
app:layout_constraintHorizontal_bias="0.253"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/textView3" />

<TextView
android:id="@+id/textView5"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="60dp"
android:text="Existencia:"

118
MANUAL DE PRÁCTICAS DE LA MATERIA “DESARROLLO DE APLICACIONES
PARA DISPOSITIVOS MÓVILES”
Carrera Ingeniería en Tecnologías de la Información y Comunicaciones
Elaborado por: Alejandro Guzmán Zazueta

app:layout_constraintEnd_toStartOf="@+id/etExistencia"
app:layout_constraintHorizontal_bias="0.316"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/textView4" />

<Button
android:id="@+id/btnRespaldar"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="163dp"
android:layout_marginTop="4dp"
android:layout_marginEnd="154dp"
android:onClick="btnRespaldar"
android:text="Respaldar Productos"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/btnCarga" />

</androidx.constraintlayout.widget.ConstraintLayout>

Si se ejecuta la aplicación, la interfaz queda como lo muestra la figura 49:

Figura 49

Interfaz de la aplicación

Nota: Interfaz de la aplicación en ejecución

119
MANUAL DE PRÁCTICAS DE LA MATERIA “DESARROLLO DE APLICACIONES
PARA DISPOSITIVOS MÓVILES”
Carrera Ingeniería en Tecnologías de la Información y Comunicaciones
Elaborado por: Alejandro Guzmán Zazueta

Ahora agregamos una clase de Kotlin de nombre AdminBD, para gestionar la base de datos del
dispositivo, el código se muestra a continuación:
AdminBD.kt
package com.example.myapplicationws

import android.content.Context
import android.database.Cursor
import android.database.sqlite.SQLiteDatabase
import android.database.sqlite.SQLiteOpenHelper
import java.lang.Exception

class AdminBD(context: Context):


SQLiteOpenHelper(context,"inventario",null,1) {
override fun onCreate(bd: SQLiteDatabase?) {
bd?.execSQL("Create Table Producto(" +
"idProd INTEGER NOT NULL primary key," +
"nomProd TEXT," +
"Existencia INTEGER," +
"Precio REAL)")
}

// Permite ejecutar Insert, Update o Delete


fun Ejecuta(sentencia: String): Boolean{
try {
val bd = this.writableDatabase
bd.execSQL(sentencia)
bd.close()
return true
}
catch (ex:Exception){
return false
}
}

// Permir ejecutar una consulta


fun Consulta(query: String):Cursor?{
try {
val bd = this.readableDatabase
return bd.rawQuery(query,null)
}
catch (ex:Exception){
return null
}
}

override fun onUpgrade(bd: SQLiteDatabase?, p1: Int, p2: Int) {


TODO("not implemented") //To change body of created functions
use File | Settings | File Templates.
}
}

120
MANUAL DE PRÁCTICAS DE LA MATERIA “DESARROLLO DE APLICACIONES
PARA DISPOSITIVOS MÓVILES”
Carrera Ingeniería en Tecnologías de la Información y Comunicaciones
Elaborado por: Alejandro Guzmán Zazueta

A continuación, se muestra el código de Kotlin del MainActivity.kt:

MainActivity.kt
package com.example.myapplicationws

import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.util.Log
import android.view.View
import android.widget.TextView
import android.widget.Toast
import com.android.volley.Request
import com.android.volley.Response
import com.android.volley.toolbox.JsonObjectRequest
import com.google.android.material.textfield.TextInputEditText
import org.json.JSONArray
import org.json.JSONObject

class MainActivity : AppCompatActivity() {


private lateinit var txtidProd : TextView
private lateinit var txtNomP : TextView
private lateinit var txtExis : TextView
private lateinit var txtPrec : TextView
val IP = "http://192.168.8.6" // Dirección IP del servidor web que
almacena los servicios web
var bandera : Boolean = false
var idProd = 0

override fun onCreate(savedInstanceState: Bundle?) {


super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
txtidProd = findViewById<TextView>(R.id.etIdProd)
txtNomP = findViewById<TextView>(R.id.etNomProd)
txtExis = findViewById<TextView>(R.id.etExistencia)
txtPrec = findViewById<TextView>(R.id.etPrecio)
}

// Este boton elimina los productos de la base de datos local y


ejecuta el servicio web getProductos.php
//Que consulta todos los producto del servidor web, para
insertarlos en la base de datos local
fun getAllProductos(view: View) {
val wsURL = IP + "/Android/getProductos.php"
val admin = AdminBD(this)
admin.Ejecuta("DELETE FROM Producto")
val jsonObjectRequest = JsonObjectRequest(
Request.Method.POST,wsURL,null,
Response.Listener { response ->
val succ = response["success"]
val msg = response["message"]
val sensadoJson = response.getJSONArray("productos")
for (i in 0 until sensadoJson.length()){
// Los nombres del getString son como los arroja el
servicio web

121
MANUAL DE PRÁCTICAS DE LA MATERIA “DESARROLLO DE APLICACIONES
PARA DISPOSITIVOS MÓVILES”
Carrera Ingeniería en Tecnologías de la Información y Comunicaciones
Elaborado por: Alejandro Guzmán Zazueta

val idprod =
sensadoJson.getJSONObject(i).getString("idp")
val nomprod =
sensadoJson.getJSONObject(i).getString("nom")
val existencia =
sensadoJson.getJSONObject(i).getString("exi")
val precio =
sensadoJson.getJSONObject(i).getString("pre")

val sentencia = "Insert into


Producto(idProd,nomProd,Existencia,Precio) values (${idprod},
'${nomprod}',${existencia}, ${precio})"
val res = admin.Ejecuta(sentencia)
}
},
Response.ErrorListener { error ->
Toast.makeText(this, "Error getAllProductos: " +
error.message.toString() , Toast.LENGTH_LONG).show();
Log.d("Zazueta",error.message.toString() )
}
)

VolleySingleton.getInstance(this).addToRequestQueue(jsonObjectRequest)
}

// Esta consulta se hace en la base de datos local, partiendo de


que la información ya se cargo
// ejecutando el boton de Carga Productos del servidor web
fun Consultar(view: View) {
if (txtidProd.text.toString().isEmpty()){
txtidProd.setError("Falta ingresar clave del producto")
Toast.makeText(this, "Falta información del id",
Toast.LENGTH_SHORT).show();
txtidProd.requestFocus()
}
else{
val admin = AdminBD(this)
val id:String = txtidProd.text.toString()
// 0 1 2
3
val cur = admin.Consulta("select
idProd,nomProd,Existencia,Precio from Producto where idProd=$id")
if (cur!!.moveToFirst()){
txtNomP.setText(cur.getString(1))
txtExis.setText(cur.getString(2))
txtPrec.setText(cur.getString(3))
}
else
{
Toast.makeText(this, "No existe la Clave del Producto",
Toast.LENGTH_LONG).show();
txtidProd.requestFocus()
}
}

122
MANUAL DE PRÁCTICAS DE LA MATERIA “DESARROLLO DE APLICACIONES
PARA DISPOSITIVOS MÓVILES”
Carrera Ingeniería en Tecnologías de la Información y Comunicaciones
Elaborado por: Alejandro Guzmán Zazueta

fun Actualiza(view: View) {


if (txtidProd.text.isNullOrEmpty()||
txtNomP.text.isNullOrEmpty()||
txtExis.text.isNullOrEmpty()||
txtPrec.text.isNullOrEmpty()){
txtidProd.setError("Falta información de Ingresar")
Toast.makeText(this, "Falta información de Ingresar",
Toast.LENGTH_LONG).show();
txtidProd.requestFocus()
}
else
{
val idp = txtidProd.text.toString()
val nom = txtNomP.text.toString()
val existencia = txtExis.text.toString()
val precio = txtPrec.text.toString()
var jsonEntrada = JSONObject()
jsonEntrada.put("idp", idp)
jsonEntrada.put("nom", nom)
jsonEntrada.put("exi", existencia)
jsonEntrada.put("pre",precio)
sendRequest(IP + "/Android/updateProducto.php",jsonEntrada)
}
}

fun Limpiar(view: View) {


txtidProd.setText("")
txtNomP.setText("")
txtExis.setText("0")
txtPrec.setText("0")
txtidProd.requestFocus()
}

fun Agregar(view: View) {


if (txtNomP.text.isNullOrEmpty()||
txtExis.text.isNullOrEmpty()||
txtPrec.text.isNullOrEmpty()){
txtNomP.setError("Falta información de Ingresar")
Toast.makeText(this, "Falta información de Ingresar",
Toast.LENGTH_LONG).show();
txtidProd.requestFocus()
}
else
{
val nom = txtNomP.text.toString()
val existencia = txtExis.text.toString()
val precio = txtPrec.text.toString()
var jsonEntrada = JSONObject()
jsonEntrada.put("nom", nom)
jsonEntrada.put("exi", existencia)
jsonEntrada.put("pre",precio)
sendRequest(IP + "/Android/insertProducto.php",jsonEntrada)

123
MANUAL DE PRÁCTICAS DE LA MATERIA “DESARROLLO DE APLICACIONES
PARA DISPOSITIVOS MÓVILES”
Carrera Ingeniería en Tecnologías de la Información y Comunicaciones
Elaborado por: Alejandro Guzmán Zazueta

}
}

fun Borrar(view: View) {


if (txtidProd.text.isNullOrEmpty()){
txtidProd.setError("Falta información de Ingresar")
Toast.makeText(this, "Falta información de Ingresar",
Toast.LENGTH_LONG).show();
txtidProd.requestFocus()
}
else
{
val idp = txtidProd.text.toString()

var jsonEntrada = JSONObject()


jsonEntrada.put("idp", idp)

sendRequest(IP + "/Android/deleteProducto.php",jsonEntrada)
}
}

//Rutina para mandar ejecutar un web service de tipo Insert, Update


o Delete
fun sendRequest( wsURL: String, jsonEnt: JSONObject){
val jsonObjectRequest = JsonObjectRequest(
Request.Method.POST, wsURL,jsonEnt,
Response.Listener { response ->
val succ = response["success"]
val msg = response["message"]
if (succ == 200){
txtidProd.setText("")
txtNomP.setText("")
txtExis.setText("0")
txtPrec.setText("0")
txtidProd.requestFocus()
Toast.makeText(this, "Success:${succ}
Message:${msg} Se Inserto Producto en el Servidor Web",
Toast.LENGTH_SHORT).show();
}
},
Response.ErrorListener{error ->
Toast.makeText(this, "${error.message}",
Toast.LENGTH_SHORT).show();
Log.d("ERROR","${error.message}");
Toast.makeText(this, "Error de capa 8 checa URL",
Toast.LENGTH_SHORT).show();
}
)

VolleySingleton.getInstance(this).addToRequestQueue(jsonObjectRequest)
}

fun btnRespaldar(view: View) {


var jsonParam = JSONObject()

124
MANUAL DE PRÁCTICAS DE LA MATERIA “DESARROLLO DE APLICACIONES
PARA DISPOSITIVOS MÓVILES”
Carrera Ingeniería en Tecnologías de la Información y Comunicaciones
Elaborado por: Alejandro Guzmán Zazueta

var jsonArray: JSONArray = JSONArray()


// 0 1 2
3
var sentencia : String = "Select idProd, nomProd, existencia,
precio from Producto"
jsonParam.put("correo","alex@gmail.com")
jsonParam.put("contra","hola")
val admin = AdminBD(this)
val tuplas = admin.Consulta(sentencia)

while (tuplas!!.moveToNext())
{
var productoJson = JSONObject()
productoJson.put("idp", tuplas.getInt(0))
productoJson.put("nom", tuplas.getString(1))
productoJson.put("exi", tuplas.getInt(2))
productoJson.put("pre", tuplas.getDouble(3))
jsonArray.put(productoJson)
}
jsonParam.put("productos", jsonArray)
putProductos(jsonParam)
}

fun putProductos(jsonEntrada : JSONObject)


{
val wsURL = IP + "/Android/resProductos.php"

val jsonObjectRequest = JsonObjectRequest(


Request.Method.POST,
wsURL,
jsonEntrada,
Response.Listener { response ->
val succ = response["success"]
val msg = response["message"]
if (succ == 200){
Toast.makeText(this, "Success=$succ
message=$msg", Toast.LENGTH_LONG).show();
}
},
Response.ErrorListener { error ->
Log.d("Zazueta", error.message.toString())
Toast.makeText(this, "Error:" +
error.message.toString() , Toast.LENGTH_LONG).show();
}
)

VolleySingleton.getInstance(this).addToRequestQueue(jsonObjectRequest)
}
}

125
MANUAL DE PRÁCTICAS DE LA MATERIA “DESARROLLO DE APLICACIONES
PARA DISPOSITIVOS MÓVILES”
Carrera Ingeniería en Tecnologías de la Información y Comunicaciones
Elaborado por: Alejandro Guzmán Zazueta

Nota: Si no corre, cheque la dirección del servidor web y actualice en el Mainactivity.kt, de igual
manera asegúrese que el dispositivo en donde se corre la app este en la misma red que el servidor
web.

Pregunta de análisis en el aula

1. ¿Porque son importantes los servicios web en las aplicaciones móviles?


2. ¿Para qué va usar los servicios web en su proyecto final?

Reporte del alumno

Presentación del trabajo

a.) Reporte escrito: El estudiante deberá presentar un reporte escrito con el avance de su
proyecto, aplicando los servicios web.
b.) Rubrica de evaluación:

CATEGORÍA 4 Sobresaliente 3 Notable 2 Aprobado 1 Insuficiente

El reporte detallado es El reporte incluye El reporte incluye la Al reporte le falta


presentado toda la información mayoría de la información requerida
ordenadamente que requerida y es información requerida y es difícil de leer.
El Reporte incluye toda la legible. y es legible.
información requerida.

Todos los párrafos La mayor parte de Los párrafos incluyen La estructura del
incluyen una los párrafos incluye información párrafo no estaba
Construcción de introducción, una introducción, relacionada pero no clara y las oraciones
Párrafos explicaciones o explicaciones o fueron generalmente no estaban
detalles y una detalles y una bien organizados. generalmente
conclusión. conclusión. relacionadas.

No hay errores de Casi no hay errores Unos pocos errores Muchos errores de
gramática, ortografía o de gramática, de gramática, gramática, ortografía o
puntuación. ortografía o ortografía o puntuación.
Redacción puntuación. puntuación.

126
MANUAL DE PRÁCTICAS DE LA MATERIA “DESARROLLO DE APLICACIONES
PARA DISPOSITIVOS MÓVILES”
Carrera Ingeniería en Tecnologías de la Información y Comunicaciones
Elaborado por: Alejandro Guzmán Zazueta

Todos los temas Todos los temas Todos los temas Uno o más temas no
tratados y todas las tratados y la mayor tratados y la mayor están tratados.
Cantidad de preguntas fueron parte de las parte de las
Información contestadas en al preguntas fueron preguntas fueron
menos 2 oraciones. contestadas en al contestadas en 1
menos 2 oraciones. oración.

La información está La información da La información da La información tiene


claramente respuesta a las respuesta a las poco o nada que ver
relacionada con el preguntas preguntas con las preguntas
Calidad de
tema principal y principales y 1-2 principales, pero no planteadas.
Información proporciona varias ideas secundarias da detalles y/o
ideas secundarias y/o y/o ejemplos. ejemplos.
ejemplos.

La información está La información está La información está La información


muy bien organizada organizada con organizada, pero los proporcionada no
con párrafos bien párrafos bien párrafos no están parece estar
Organización redactados y con redactados. bien redactados. organizada.
subtítulos.

127
MANUAL DE PRÁCTICAS DE LA MATERIA “DESARROLLO DE APLICACIONES
PARA DISPOSITIVOS MÓVILES”
Carrera Ingeniería en Tecnologías de la Información y Comunicaciones
Elaborado por: Alejandro Guzmán Zazueta

Práctica 7. Generación de PDF en Android

Objetivo
El estudiante aprenderá a generar informes pdf en Android.

Introducción
Esta práctica es opcional y deberá usarla si su proyecto final requiere la generación de informes
en pdf.

Correlación con los temas y subtemas del programa de estudio


Esta práctica abona a la funcionalidad del proyecto final.

Material y equipo necesario


Computadora i3, i5 o i7 con mínimo de 8GB de Ram.

Acceso a Internet, para la creación de nuevo proyecto en Android Studio.

Metodología
El estudiante deberá leer el siguiente material y enseguida implementarla en Android Estudio:

128
MANUAL DE PRÁCTICAS DE LA MATERIA “DESARROLLO DE APLICACIONES
PARA DISPOSITIVOS MÓVILES”
Carrera Ingeniería en Tecnologías de la Información y Comunicaciones
Elaborado por: Alejandro Guzmán Zazueta

En este ejemplo vamos a abordar como crear un archivo PDF, que incluya títulos, subtitulos, tablas,
marcas de agua, imágenes, fecha de creación y demás objetos característicos de estos
documentos. Para su creación, este ejemplo se apoya en la librería droidText.0.4. jar
implementada en Android Studio. iText. Creamos un nuevo Proyecto de nombre MyApplicationPDF
y agregamos los permisos al AndroidManifest, para leer y escribir en el dispositivo:

<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />


<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

Enseguida se va a crear nuestra interface el cual consistirá en una caja de texto de nombre etTexto
y un botón al que llamaremos btnGenerar, la figura 50 la ilustra:

Figura 50

Interfaz de la Aplicación MyApplicationPDF

Nota: Representación de la interfaz de la aplicación MyApplicationPDF

El código del activity_main.xml se muestra a continuación:


<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout

129
MANUAL DE PRÁCTICAS DE LA MATERIA “DESARROLLO DE APLICACIONES
PARA DISPOSITIVOS MÓVILES”
Carrera Ingeniería en Tecnologías de la Información y Comunicaciones
Elaborado por: Alejandro Guzmán Zazueta

xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">

<EditText
android:id="@+id/etTexto"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginTop="32dp"
android:layout_marginEnd="8dp"
android:ems="10"
android:hint="TEXTO"
android:inputType="textMultiLine"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />

<Button
android:id="@+id/btnGenerar"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginTop="32dp"
android:layout_marginEnd="8dp"
android:text="Generar pdf"
android:onClick="btnGenerar"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/etTexto" />

</androidx.constraintlayout.widget.ConstraintLayout>

Ahora antes de empezar con el código, tendremos que utilizar una librería de tipo .jar el cual nos
permitirá utilizar colores tipo de letras y demás herramientas para crear nuestro archivo pdf.
Descarga la siguiente librería: droidText0.4.jar, dando clic en este vínculo.

Esta librería debe estar dentro de la carpeta lib, para ello en el paso 1 seleccionemos Project,
enseguida entra a la carpeta app, después copia la librería droidText.0.4.jar dentro de la carpeta
libs, como se ilustra en la figura 51:
130
MANUAL DE PRÁCTICAS DE LA MATERIA “DESARROLLO DE APLICACIONES
PARA DISPOSITIVOS MÓVILES”
Carrera Ingeniería en Tecnologías de la Información y Comunicaciones
Elaborado por: Alejandro Guzmán Zazueta

Figura 51

Ubicación de librería droidText.0.4.jar

Nota: Ubicación en Android Estudio de la librería droidText0.4.jar

Después tenemos que agregar la siguiente línea a nuestro Modulo de build.gradle al final de las
dependencies.

implementation files('libs/droidText.0.4.jar')

y presione sincronizar, en la esquina superior derecha.

Debes agregar una imagen pequeña con el nombre logo.png dentro de tu carpeta Drawable como
lo muestra la figura 52:

131
MANUAL DE PRÁCTICAS DE LA MATERIA “DESARROLLO DE APLICACIONES
PARA DISPOSITIVOS MÓVILES”
Carrera Ingeniería en Tecnologías de la Información y Comunicaciones
Elaborado por: Alejandro Guzmán Zazueta

Figura 52

Ubicación de la imagen

Nota: Ubicación de la imagen en Android Estudio

A continuación, se muestra el código del MainActivity.kt.


package com.example.myapplicationpdf
import android.Manifest
import android.content.pm.PackageManager
import android.graphics.Bitmap
import android.graphics.Bitmap.CompressFormat.PNG
import android.graphics.BitmapFactory
import android.os.Bundle
import android.os.Environment
import android.view.View
import android.widget.EditText
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import androidx.core.app.ActivityCompat
import com.lowagie.text.*
import com.lowagie.text.pdf.ColumnText
import com.lowagie.text.pdf.PdfPTable
import com.lowagie.text.pdf.PdfWriter
import com.lowagie.text.Paragraph
import harmony.java.awt.Color
import java.io.ByteArrayOutputStream
import java.io.File
import java.io.FileOutputStream
import java.io.IOException

class MainActivity : AppCompatActivity() {


var NOMBRE_DIRECTORIO = "MisPDFs"
var NOMBRE_DOCUMENTO = "MiPDF.pdf"
lateinit var etText : EditText

override fun onCreate(savedInstanceState: Bundle?) {


super.onCreate(savedInstanceState)

132
MANUAL DE PRÁCTICAS DE LA MATERIA “DESARROLLO DE APLICACIONES
PARA DISPOSITIVOS MÓVILES”
Carrera Ingeniería en Tecnologías de la Información y Comunicaciones
Elaborado por: Alejandro Guzmán Zazueta

setContentView(R.layout.activity_main)
etText = findViewById<EditText>(R.id.etTexto)

// Confirma los permisos para leer y escribir en el dispositivo


if (ActivityCompat.checkSelfPermission(this,
Manifest.permission.WRITE_EXTERNAL_STORAGE) !=
PackageManager.PERMISSION_GRANTED &&
ActivityCompat.checkSelfPermission(this,
Manifest.permission.WRITE_EXTERNAL_STORAGE) !=
PackageManager.PERMISSION_GRANTED
) {
ActivityCompat.requestPermissions(
this, arrayOf(Manifest.permission.WRITE_EXTERNAL_STORAGE),
1000
)
}
}

// Generaremos el documento al hacer click sobre el boton.


fun btnGenerar(v: View?) {
crearPDF()
Toast.makeText(this@MainActivity, "SE CREO EL PDF",
Toast.LENGTH_LONG).show()
}

fun crearPDF() {
// Creamos el documento.
val documento = Document()
try {
// Creamos el flujo de datos de salida para el fichero donde
// guardaremos el pdf.
val file: File? = crearFichero(NOMBRE_DOCUMENTO)
val ficheroPDF = FileOutputStream(file!!.absoluteFile)
val writer = PdfWriter.getInstance(documento, ficheroPDF)

// Incluimos el pie de pagina y una cabecera


val cabecera = HeaderFooter(Phrase(
"Esta es mi cabecera"), false)
val pie = HeaderFooter(Phrase(
"Este es mi pie de pagina"), false)

documento.setHeader(cabecera)
documento.setFooter(pie)

documento.open()

// Añadimos un título con la fuente por defecto.


documento.add(Paragraph("Título 1"))

val font: Font = FontFactory.getFont(FontFactory.HELVETICA,


28.0f,
Font.BOLD, Color.RED)
documento.add(Paragraph("Título personalizado", font))

133
MANUAL DE PRÁCTICAS DE LA MATERIA “DESARROLLO DE APLICACIONES
PARA DISPOSITIVOS MÓVILES”
Carrera Ingeniería en Tecnologías de la Información y Comunicaciones
Elaborado por: Alejandro Guzmán Zazueta

// Insertamos una imagen que se encuentra en los recursos de


la
// aplicacion.
val bitmap : Bitmap =
BitmapFactory.decodeResource(this.resources, R.drawable.logo)
val stream = ByteArrayOutputStream()
bitmap.compress(PNG, 100, stream )
val imagen : Image = Image.getInstance(stream.toByteArray())
documento.add(imagen)

documento.add(Paragraph("TABLA \n\n"))
documento.add(
Paragraph(
"""
${etText.text}

""".trimIndent()
)
)

// Insertamos una tabla


val tabla = PdfPTable(5)
for (i in 0..14) {
tabla.addCell("CELDA $i")
}
documento.add(tabla)

// Agregar marca de agua

val font2 = FontFactory.getFont(FontFactory.HELVETICA, 42.0f,


Font.BOLD,
Color.GRAY)

ColumnText.showTextAligned(writer.directContentUnder,Element.ALIGN_CENTER,
Paragraph("www.tecnm.mx",font2), 297.5f, 421f, if (writer.pageNumber % 2
=== 1) 45.0f else -45.0f)

} catch (e: DocumentException) {


} catch (e: IOException) {
} finally {
documento.close()
}
}

fun crearFichero(nombreFichero: String?): File? {


val ruta: File? = getRuta()
var fichero: File? = null
if (ruta != null) {
fichero = File(ruta, nombreFichero)
}
return fichero
}

134
MANUAL DE PRÁCTICAS DE LA MATERIA “DESARROLLO DE APLICACIONES
PARA DISPOSITIVOS MÓVILES”
Carrera Ingeniería en Tecnologías de la Información y Comunicaciones
Elaborado por: Alejandro Guzmán Zazueta

/**
* Obtenemos la ruta donde vamos a almacenar el fichero.
*
* @return
*/
fun getRuta(): File? {
var ruta: File? = null
if
(Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState()))
{
ruta = File(getExternalFilesDir(null), NOMBRE_DIRECTORIO)
if (ruta != null) {
if (!ruta.mkdirs()) {
if (!ruta.exists()) {
return null
}
}
}
}
return ruta
}
}

Para localizar el reporte hay que abrir el Device File Explorer como se muestra en la figura 53:

Figura 53

Ubicación de Archivo MiPDF.pdf

Nota: Ubicación del archivo pdf en el Device File Explorer de Android Estudio

135
MANUAL DE PRÁCTICAS DE LA MATERIA “DESARROLLO DE APLICACIONES
PARA DISPOSITIVOS MÓVILES”
Carrera Ingeniería en Tecnologías de la Información y Comunicaciones
Elaborado por: Alejandro Guzmán Zazueta

En la ruta: /storage/emulated/0/Android/data/com.example.myapplicationpdf/files/MisPDFs
La figura 54 ilustra el reporte que se genero:

Figura 54

Archivo PDF Generado

Nota: Archivo MiPDF.pgf generado

A continuación, con la finalidad de abrir directamente el archivo pdf, agregaremos los siguientes
cambios:
Agregamos un archivo a la carpeta XML de res, dando clic derecho – new – XML Resource File,
como se muestra en la figura 55:

136
MANUAL DE PRÁCTICAS DE LA MATERIA “DESARROLLO DE APLICACIONES
PARA DISPOSITIVOS MÓVILES”
Carrera Ingeniería en Tecnologías de la Información y Comunicaciones
Elaborado por: Alejandro Guzmán Zazueta

Figura 55

Interfaz de Nuevo Archivo de Recursos

Nota: Parametros del Nuevo Arhcivo de Recursos en Android Estudio

Y enseguida dejamos el código como a continuación se muestra:


<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<external-path
name="external_files"
path="Android/data/com.example.myapppdf/files/MisPDFs" />
</paths>

El texto en rojo debe ser cambiado por que es el nombre del proyecto en minúsculas.

A continuación, abrimos en archivo AndroidManifest.xml y agregamos la sección <provider que


enseguida se muestra antes de cerrar la etiqueta </application>:

137
MANUAL DE PRÁCTICAS DE LA MATERIA “DESARROLLO DE APLICACIONES
PARA DISPOSITIVOS MÓVILES”
Carrera Ingeniería en Tecnologías de la Información y Comunicaciones
Elaborado por: Alejandro Guzmán Zazueta

<provider
android:authorities="${applicationId}.provider"
android:name="androidx.core.content.FileProvider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/file_paths" />
</provider>
</application>

</manifest>

En seguida modificamos el código del botón btnGenarar en el MainActivity, quedando como a


continuación se muestra:

fun btnGenerar(view: View) {


crearPDF()
val file = File(Environment.getExternalStorageDirectory(),
"Android/data/com.example.myapppdf/files/MisPDFs/MiPDF.pdf" )
val URI = FileProvider.getUriForFile(this, getPackageName()
+ ".provider", file)
val intent = Intent(Intent.ACTION_VIEW)
intent.setDataAndType(URI, "application/pdf")
intent.flags= Intent.FLAG_GRANT_READ_URI_PERMISSION
try {
startActivity(intent)
}
catch (e : ActivityNotFoundException){
Toast.makeText(this, "No se encontro App para leer PDFs",
Toast.LENGTH_LONG).show();
}
}

Cambiar el nombre myappdf por el nombre de su proyecto en minúsculas.

Al ejecutar la aplicación y dar clic en el botón de generar aparece ya el informe en PDF.

138
MANUAL DE PRÁCTICAS DE LA MATERIA “DESARROLLO DE APLICACIONES
PARA DISPOSITIVOS MÓVILES”
Carrera Ingeniería en Tecnologías de la Información y Comunicaciones
Elaborado por: Alejandro Guzmán Zazueta

Práctica 8. Generación de una Gráficas en Android

Objetivo
El estudiante aprenderá a generar gráficas en Android.

Introducción
Esta práctica es opcional y deberá usarla si su proyecto final requiere la generación de una
gráfica.

Correlación con los temas y subtemas del programa de estudio


Esta práctica abona a la funcionalidad del proyecto final.

Material y equipo necesario


Computadora i3, i5 o i7 con mínimo de 8GB de Ram.

Acceso a Internet, para la creación de nuevo proyecto en Android Studio.

Metodología
El estudiante deberá leer el siguiente material y enseguida implementarla en Android Estudio:

139
MANUAL DE PRÁCTICAS DE LA MATERIA “DESARROLLO DE APLICACIONES
PARA DISPOSITIVOS MÓVILES”
Carrera Ingeniería en Tecnologías de la Información y Comunicaciones
Elaborado por: Alejandro Guzmán Zazueta

En este ejercicio se va a generar una gráfica de barras a partir de la información almacenada en


una base de datos en SQLite, como se muestra en la figura 56:

Figura 56

Interfaz de la aplicación AppGrafica

Nota: Interfaz de la aplicación AppGrafica en ejecución

En primer lugar, vamos a crear un nuevo proyecto de nombre AppGrafica, con una actividad vacía.
Enseguida vamos a importar las librerías al archivo build.gradle(Module:app), para es esto vamos
agregar el siguiente(líneas resaltadas en amarillo), en la sección de dependencias:

dependencies {
implementation fileTree(dir:"libs", include:["*.jar"])
implementation 'androidx.core:core-ktx:1.7.0'
implementation 'androidx.appcompat:appcompat:1.5.1'
implementation 'com.google.android.material:material:1.7.0'
implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
testImplementation 'junit:junit:4.13.2'
androidTestImplementation 'androidx.test.ext:junit:1.1.4'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.0'
implementation 'com.github.PhilJay:MPAndroidChart:v2.2.4'

140
MANUAL DE PRÁCTICAS DE LA MATERIA “DESARROLLO DE APLICACIONES
PARA DISPOSITIVOS MÓVILES”
Carrera Ingeniería en Tecnologías de la Información y Comunicaciones
Elaborado por: Alejandro Guzmán Zazueta

Y le damos sincronizar en la esquina superior derecha, para proceder a descargarlas de internet.

A continuación, abrimos el archivo “Settings.gradle” y lo modificamos para quedar como a


continuación se muestra:
pluginManagement {
repositories {
gradlePluginPortal()
google()
mavenCentral()
}
}
dependencyResolutionManagement {
repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
repositories {
google()
mavenCentral()
maven {url 'https://jitpack.io'}
maven {url 'https://maven.google.com'}
}
}
rootProject.name = "My ApplicationGrafica"
include ':app'

Y le damos sincronizar en la esquina superior derecha, para proceder a descargarlas las librerías de
internet.

A continuación, mostramos el código XML del activity_main.xml:


<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<EditText
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:inputType="textPersonName"
android:ems="10"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent" android:id="@+id/etNom"
app:layout_constraintTop_toTopOf="parent" android:layout_marginTop="112dp"
android:hint="Nombre del Empleado"/>
<EditText

141
MANUAL DE PRÁCTICAS DE LA MATERIA “DESARROLLO DE APLICACIONES
PARA DISPOSITIVOS MÓVILES”
Carrera Ingeniería en Tecnologías de la Información y Comunicaciones
Elaborado por: Alejandro Guzmán Zazueta

android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:inputType="numberDecimal"
android:ems="10"
android:id="@+id/etVtas" app:layout_constraintEnd_toEndOf="parent"
android:layout_marginEnd="8dp" app:layout_constraintStart_toStartOf="parent"
android:layout_marginStart="8dp" app:layout_constraintTop_toBottomOf="@+id/etNom"
android:layout_marginTop="80dp" tools:text="0" android:hint="Importe Ventas"/>
<Button
android:text="Guardar"
android:layout_width="wrap_content"
android:layout_height="wrap_content" app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
android:id="@+id/gtnGuardar" app:layout_constraintStart_toStartOf="parent"
android:layout_marginStart="8dp"
app:layout_constraintEnd_toStartOf="@+id/btnGraficar" android:layout_marginEnd="8dp"
android:onClick="guardarClic" tools:text="Guardar"/>
<Button
android:text="Graficar"
android:layout_width="wrap_content"
android:layout_height="wrap_content" app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
android:id="@+id/btnGraficar" app:layout_constraintEnd_toEndOf="parent"
android:layout_marginEnd="60dp"
app:layout_constraintVertical_bias="0.499" android:onClick="graficaClic"/>
</androidx.constraintlayout.widget.ConstraintLayout>

La actividad queda como se muestra:


Figura 57

Interfaz de la actividad de la activity_main.xml

Nota: Diseño de la actividad del activity_main.xml

Agregamos una nueva actividad vacía de nombre MainActivityGrafica y una clase de Kotlin de
nombre AdminBD.
142
MANUAL DE PRÁCTICAS DE LA MATERIA “DESARROLLO DE APLICACIONES
PARA DISPOSITIVOS MÓVILES”
Carrera Ingeniería en Tecnologías de la Información y Comunicaciones
Elaborado por: Alejandro Guzmán Zazueta

A continuación, se muestra el código de la clase AdminBD:


import android.content.Context
import android.database.Cursor
import android.database.sqlite.SQLiteDatabase
import android.database.sqlite.SQLiteOpenHelper

class AdminBD (context: Context): SQLiteOpenHelper(context, DATABASE, null,1)


{
companion object{
val DATABASE = "Ventas"
}

override fun onCreate(db: SQLiteDatabase?) {


db?.execSQL(
"Create Table Empleado(" +
"_id int primary key, " +
"NomEmp text, " +
"Ventas float)"
)
}

override fun onUpgrade(db: SQLiteDatabase?, oldVersion: Int, newVersion:


Int) {
TODO("not implemented") //To change body of created functions use File
| Settings | File Templates.
}

fun Ejecuta(sentencia: String):Boolean


{
try{
val db = this.writableDatabase
db.execSQL(sentencia)
db.close()
return true
}
catch (ex:Exception){
return false
}
}

fun Consulta(select: String): Cursor?


{
try{
val db = this.readableDatabase
return db.rawQuery(select,null)
}
catch (ex:Exception){
return null
}
}
}

143
MANUAL DE PRÁCTICAS DE LA MATERIA “DESARROLLO DE APLICACIONES
PARA DISPOSITIVOS MÓVILES”
Carrera Ingeniería en Tecnologías de la Información y Comunicaciones
Elaborado por: Alejandro Guzmán Zazueta

Como se observa se crea la tabla:


Create Table Empleado(
_id int primary key,
NomEmp text,
Ventas float)

La llave primaria es _id y el guion bajo indica que ese campo es auto numérico.
En seguida mostramos el código del MainActivity.kt:
package com.example.myapplicationgrafica
import android.content.Intent
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.view.View
import android.widget.EditText
import android.widget.Toast

class MainActivity : AppCompatActivity() {


lateinit var etNom : EditText
lateinit var etVtas : EditText

override fun onCreate(savedInstanceState: Bundle?) {


super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
etNom = findViewById<EditText>(R.id.etNom)
etVtas = findViewById<EditText>(R.id.etVtas)
}

fun graficaClic(v:View){
val intGraf = Intent(this, MainActivityGrafica::class.java)
startActivity(intGraf)
}

fun guardarClic(v: View){


if (etNom.text.isEmpty() || etVtas.text.isEmpty()){
etNom.setError("Falta información de ingresar")
etNom.requestFocus()
}
else
{
val admin = AdminBD(this)
val nom = etNom.text.toString()
val vta = etVtas.text.toString().toFloat()
val sentencia = "Insert into Empleado(NomEmp,Ventas) values
" +
"('${nom}',${vta})"
if (admin.Ejecuta(sentencia)){

144
MANUAL DE PRÁCTICAS DE LA MATERIA “DESARROLLO DE APLICACIONES
PARA DISPOSITIVOS MÓVILES”
Carrera Ingeniería en Tecnologías de la Información y Comunicaciones
Elaborado por: Alejandro Guzmán Zazueta

Toast.makeText(this, "Empleado Guardado",


Toast.LENGTH_SHORT).show();
etVtas.setText("0")
etNom.setText("")
etNom.requestFocus()
}
else
{
Toast.makeText(this, "Error de capa 8 No Guardo",
Toast.LENGTH_SHORT).show();
}
}
}
}

Es importante agregar unos empleados con sus Ventas, para tener información que graficar, de lo
contrario el botón de Graficar no mostrara nada.

A continuación, se muestra el código del archivo activity_main_grafica.xml:


<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivityGrafica">

<com.github.mikephil.charting.charts.BarChart
android:id="@+id/barChart"
android:layout_width="match_parent"
android:layout_height="match_parent" />

</androidx.constraintlayout.widget.ConstraintLayout>

En seguida se muestra el código del MainActivityGrafica.kt:


package com.example.myapplicationgrafica
import android.database.Cursor
import android.graphics.Color
import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import com.github.mikephil.charting.charts.BarChart
import com.github.mikephil.charting.data.BarData
import com.github.mikephil.charting.data.BarDataSet

145
MANUAL DE PRÁCTICAS DE LA MATERIA “DESARROLLO DE APLICACIONES
PARA DISPOSITIVOS MÓVILES”
Carrera Ingeniería en Tecnologías de la Información y Comunicaciones
Elaborado por: Alejandro Guzmán Zazueta

import com.github.mikephil.charting.data.BarEntry
import com.github.mikephil.charting.utils.ColorTemplate

class MainActivityGrafica : AppCompatActivity() {


val entries = ArrayList<BarEntry>() // Arreglo para cargar las
ventas de los empleados eje de las Y
val labels = ArrayList<String>() // Arreglo para cargar los nombres
de empleados en el eje de las X
var cursor : Cursor?= null
lateinit var barChart : BarChart

override fun onCreate(savedInstanceState: Bundle?) {


super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main_grafica)

barChart = findViewById<BarChart>(R.id.barChart)
cargarDatos()
setBarChart()
}

fun cargarDatos(){
val admin = AdminBD(this)
cursor = admin.Consulta("Select * from Empleado Order by
Ventas")
}

fun setBarChart() {
var i: Int = 0
if (cursor!!.moveToFirst()){
do {
val nom = cursor!!.getString(1)
val vtas = cursor!!.getFloat(2)
entries.add(BarEntry(vtas,i )) // Agregamos Ventas
labels.add(nom) // Agregamos nomEmp
i++
} while (cursor!!.moveToNext())
val barDataSet = BarDataSet(entries, "Datos")
val data = BarData(labels,barDataSet)
barChart.data = data

barDataSet.setColors(ColorTemplate.JOYFUL_COLORS,250)
barDataSet.valueTextColor = Color.BLACK
barDataSet.valueTextSize = 15f

barChart.animateY(5000)
}
}
}

A continuación, ejecutamos la aplicación, damos de alta unos empleados y se da clic en el botón


de Graficar, mostrando la interfaz de la figura 58:

146
MANUAL DE PRÁCTICAS DE LA MATERIA “DESARROLLO DE APLICACIONES
PARA DISPOSITIVOS MÓVILES”
Carrera Ingeniería en Tecnologías de la Información y Comunicaciones
Elaborado por: Alejandro Guzmán Zazueta

Figura 58

Ejecución de la aplicación AppGrafica

Nota: Interfaz de la aplicación AppGrafica en ejecución

147
MANUAL DE PRÁCTICAS DE LA MATERIA “DESARROLLO DE APLICACIONES
PARA DISPOSITIVOS MÓVILES”
Carrera Ingeniería en Tecnologías de la Información y Comunicaciones
Elaborado por: Alejandro Guzmán Zazueta

Práctica 9. Mapas y Marcas en Android

Objetivo
El estudiante aprenderá a usar los mapas en Android y colocar marcas.

Introducción
Esta práctica es opcional y deberá usarla si su proyecto final requiere el uso de mapas.

Correlación con los temas y subtemas del programa de estudio


Esta práctica abona a la funcionalidad del proyecto final.

Material y equipo necesario


Computadora i3, i5 o i7 con mínimo de 8GB de Ram.
Acceso a Internet, para la creación de nuevo proyecto en Android Studio.

Metodología
El estudiante deberá leer el siguiente material y enseguida implementarla en Android Estudio:

148
MANUAL DE PRÁCTICAS DE LA MATERIA “DESARROLLO DE APLICACIONES
PARA DISPOSITIVOS MÓVILES”
Carrera Ingeniería en Tecnologías de la Información y Comunicaciones
Elaborado por: Alejandro Guzmán Zazueta

Google Maps, es una herramienta que es capaz de hacer muchas más cosas que se ven simples a
la vista. En este tema vamos a crear nuestro primer mapa en Android y añadiremos un marcador.

Api Key de Google Maps


Para poder trabajar con Google Maps necesitamos un api key. Esto no es más que un código para
verificar que el usuario que crea un proyecto es el creador de la app.

Debemos crear un proyecto en Google Cloud, para entrar da clic a este vínculo. Si es
necesario entra con una cuenta de Google y su respectiva contraseña. Una vez accedas a este,
verás que en la esquina superior derecha podemos crear un nuevo proyecto. Haremos clic y
seleccionaremos un nombre. No es necesario seleccionar Ubicación, como se muestra en la figura
59:

Figura 59

Creación de Proyecto en Google Cloud

Nota: Parametros de la creación de Proyecto en Google cloud

Ya creado el proyecto, en el menú lateral seleccionaremos APIs y servicios y una vez dentro en la
parte superior pulsamos HABILITAR APIS Y SERVICIOS. Apareceremos en un buscador donde están
todas las APIs de Google, en nuestro caso tenemos que buscar Maps SDK for Android, como se
observa en la figura 60:

149
MANUAL DE PRÁCTICAS DE LA MATERIA “DESARROLLO DE APLICACIONES
PARA DISPOSITIVOS MÓVILES”
Carrera Ingeniería en Tecnologías de la Información y Comunicaciones
Elaborado por: Alejandro Guzmán Zazueta

Figura 60

Selección de APIs y Servicios

Nota: Interfaz de la selección de APIs y Servicios a Utilizar en el Proyecto

Seleccionamos el API y dentro nos saldrá un botón azul para habilitarla, pulsamos en HABILITAR.
Ya tenemos habilitado los mapas en Android en nuestro proyecto, el siguiente paso será generar
una API KEY que deberemos añadir en nuestro proyecto. Para ello volvemos al panel de control de
nuestro proyecto de Google Cloud y esta vez hacemos clic en el menú lateral APIs y servicios >
Credenciales, como se observa en la figura 61.

En la parte superior central pulsaremos en CREAR CREDENCIALES > Clave de API.

Figura 61

Creación de Credenciales Clave API Key

Nota: Creación de API Key

La imagen 62, muestra una ventana con el api key creada:

150
MANUAL DE PRÁCTICAS DE LA MATERIA “DESARROLLO DE APLICACIONES
PARA DISPOSITIVOS MÓVILES”
Carrera Ingeniería en Tecnologías de la Información y Comunicaciones
Elaborado por: Alejandro Guzmán Zazueta

Figura 62

Creación de Clave API

Nota: API Key creada

Creamos un nuevo proyecto, con el nombre My Project Android. Como siempre seleccionaremos
empty activity (Guimerá, Google Maps en Android con Kotlin, 2020).

Para poder utilizar Google Maps dentro de nuestro proyecto tenemos que añadir una librería, así
que iremos a Build.Gradle y dentro de la sección dependencies añadimos la siguiente línea.

implementation 'com.google.android.gms:play-services-maps:18.0.0'

A continuación damos clic en Sync Now (esquina superior derecha), para iniciar la descarga de las
librerías, ya que termino la sincronización, vamos a proceder a añadir el api key que creamos. En
seguida vamos agregar un archivo de tipo Values Resource File, en la carpeta res>values, de
nombre google_maps_api.xml.

151
MANUAL DE PRÁCTICAS DE LA MATERIA “DESARROLLO DE APLICACIONES
PARA DISPOSITIVOS MÓVILES”
Carrera Ingeniería en Tecnologías de la Información y Comunicaciones
Elaborado por: Alejandro Guzmán Zazueta

Figura 63

Creación de Nuevo Values Resource File

Nota: Ubicación para la creación de Nuevo Values Resource File

En seguida se muestra el código del archivo google_maps_api.xml:

<?xml version="1.0" encoding="utf-8"?>


<resources>
<string name="google_maps_key" templateMergeStrategy="preserve"
translatable="false">xxxxxxxxxxxxxxxxxxxxxxxxxxxx</string>
</resources>

En donde están las xxxxxxxxxxxxxxxxxxxxxx deberá poner su api key.

Una vez creado el recurso, debemos indicarle a nuestro proyecto android que ya tenemos una api
key válida, es por ello que iremos al fichero AndroidManifest.xml y dentro de la etiqueta
<application> añadiremos nuestra la referencia al archivo gogle_maps_api, como se indica en el
siguiente código resaltado en amarillo:

<?xml version="1.0" encoding="utf-8"?>


<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">

<application
android:allowBackup="true"
android:dataExtractionRules="@xml/data_extraction_rules"
android:fullBackupContent="@xml/backup_rules"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@style/Theme.MyProjectAndroid"
tools:targetApi="31">

152
MANUAL DE PRÁCTICAS DE LA MATERIA “DESARROLLO DE APLICACIONES
PARA DISPOSITIVOS MÓVILES”
Carrera Ingeniería en Tecnologías de la Información y Comunicaciones
Elaborado por: Alejandro Guzmán Zazueta

<meta-data
android:name="com.google.android.geo.API_KEY"
android:value="@string/google_maps_key" />
<activity
android:name=".MainActivity"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />

<category
android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>

</manifest>

En seguida trabajaremos con el diseño de la aplicación para ello entremos al código del
activity_main.xml y sustituiremos el contenido del layout que nos viene por defecto por un
componente fragment, el siguiente código muestra cómo debe quedar:

<?xml version="1.0" encoding="utf-8"?>


<fragment xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/fragmentMap"
android:name="com.google.android.gms.maps.SupportMapFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity" />

A continuación vamos a crear un fragment desde el layout, pero le estamos diciendo que sea de
tipo com.google.android.gms.maps.SupportMapFragment, que es un fragment que viene dentro
de la librería que instalamos anteriormente.

En seguida trabajaremos con el código de Kotlin “MainActivity.kt”. en primer lugar vamos a crear
una función llamada createMapFragment() que será la encargada de inicializar el fragment que
hemos creado en el layout. Esta función la llamaremos desde el método onCreate().

override fun onCreate(savedInstanceState: Bundle?) {


super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)

153
MANUAL DE PRÁCTICAS DE LA MATERIA “DESARROLLO DE APLICACIONES
PARA DISPOSITIVOS MÓVILES”
Carrera Ingeniería en Tecnologías de la Información y Comunicaciones
Elaborado por: Alejandro Guzmán Zazueta

createMapFragment()
}

private fun createMapFragment() {


val mapFragment =
supportFragmentManager.findFragmentById(R.id.fragmentMap) as
SupportMapFragment
mapFragment.getMapAsync(this)
}

Creamos una variable y le decimos a supportFragmentManager que busque un fragment que tenga
una id llamada fragmentMap, que será la id del fragment que añadimos en activity_main.xml, luego
a nuestra variable que contiene un SupportMapFragment (fragment de tipo mapa) la inicializamos
con la función getMapAsync(this).

Hay un error en la última línea de la función. Esto es porque getMapAsync(this) necesita que
nuestra activity implemente la función onMapReady() y para ello tenemos que añadir la interfaz
OnMapReadyCallback en la declaración de la clase.

class MainActivity : AppCompatActivity(), OnMapReadyCallback {

Esta interfaz que hemos implementado nos obliga a sobrescribir la función onMapReady(), que se
llamará automáticamente cuando el mapa haya cargado. Es por eso que nuestra activity nos marca
un error, pues no hemos sobrescrito el método todavía.

override fun onMapReady(googleMap: GoogleMap) {

Esta función nos devolverá un objeto GoogleMap que será muy útil, es por ello que debemos
guardarlo en una variable. Para ello creamos una variable en la parte superior de la clase y le
asignaremos el objeto GoogleMap cuando lo recibamos.

private lateinit var map: GoogleMap

154
MANUAL DE PRÁCTICAS DE LA MATERIA “DESARROLLO DE APLICACIONES
PARA DISPOSITIVOS MÓVILES”
Carrera Ingeniería en Tecnologías de la Información y Comunicaciones
Elaborado por: Alejandro Guzmán Zazueta

override fun onMapReady(googleMap: GoogleMap) {


map = googleMap
}

Ahora agregaremos un Markers y efectuaremos un zoom en el mapa.

Google nos permite añadir markers, pequeñas etiquetas para marcar un lugar a través
de sus coordenadas. Para ello crearemos una nueva función de nombre createMarker()
que la llamaremos cuando el método onMapReady() se ejecute.

Los markers se crean de una forma muy sencilla, basta con crear una instancia de un objeto
LatLng() que recibirá dos parámetros, la latitud y la longitud. Para este ejemplo se han colocado las
coordenadas del TecNm en Roque.

val coordenadas = LatLng(20.577997, -100.825393)


val marca : MarkerOptions =
MarkerOptions().position(coordenadas).title("TecNM en Roque")

Una vez creado el objeto con las coordenadas, llamaremos a nuestro mapa y con la función
addMarker() le añadiremos:

MarkerOptions().position(favoritePlace).title(“TecNm en Roque”)

simplemente le hemos puesto las coordenadas anteriormente creadas y hemos asignado un title
que se mostrará cuando el usuario pulse el marker. El title es opcional.

Terminaremos añadiendo una animación para que el mapa haga zoom donde creamos el marker.

map.animateCamera(CameraUpdateFactory.newLatLngZoom(coordenadas,18f),
4000,
null
)

La función animateCamera() recibirá tres parámetros:

155
MANUAL DE PRÁCTICAS DE LA MATERIA “DESARROLLO DE APLICACIONES
PARA DISPOSITIVOS MÓVILES”
Carrera Ingeniería en Tecnologías de la Información y Comunicaciones
Elaborado por: Alejandro Guzmán Zazueta

Un CameraUpdateFactory que a su vez llevará otros dos parámetros, el primero las coordenadas
donde queremos hacer zoom y el segundo valor (es un float) será la cantidad de zoom que
queremos hacer en dichas coordenadas.

La duración de la animación en milisegundos, por ejemplo 4000 milisegundos son 4 segundos.

Un listener que no vamos a utilizar, simplemente añadimos null.

Nuestra MainActivity se muestra a continuación:

package com.example.myprojectandroid

import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import com.google.android.gms.maps.CameraUpdateFactory
import com.google.android.gms.maps.GoogleMap
import com.google.android.gms.maps.OnMapReadyCallback
import com.google.android.gms.maps.SupportMapFragment
import com.google.android.gms.maps.model.LatLng
import com.google.android.gms.maps.model.MarkerOptions

class MainActivity : AppCompatActivity(), OnMapReadyCallback {


private lateinit var map: GoogleMap

override fun onCreate(savedInstanceState: Bundle?) {


super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
createMapFragment()
}

private fun createMapFragment() {


val mapFragment =
supportFragmentManager.findFragmentById(R.id.fragmentMap) as
SupportMapFragment
mapFragment.getMapAsync(this)
}

override fun onMapReady(googleMap: GoogleMap) {


map = googleMap
createMarker()
}

private fun createMarker() {


val coordenadas = LatLng(20.577997, -100.825393)
val marca : MarkerOptions =
MarkerOptions().position(coordenadas).title("TecNM en Roque")
map.addMarker(marca)

map.animateCamera(CameraUpdateFactory.newLatLngZoom(coordenadas,18f),
4000,

156
MANUAL DE PRÁCTICAS DE LA MATERIA “DESARROLLO DE APLICACIONES
PARA DISPOSITIVOS MÓVILES”
Carrera Ingeniería en Tecnologías de la Información y Comunicaciones
Elaborado por: Alejandro Guzmán Zazueta

null
)
}
}

La figura 64 muestra la interfaz de la aplicación:

Figura 64

Ejecución de la Aplicación My Project Android

Nota: Interfaz en ejecución de la aplicación de mapas

157
MANUAL DE PRÁCTICAS DE LA MATERIA “DESARROLLO DE APLICACIONES
PARA DISPOSITIVOS MÓVILES”
Carrera Ingeniería en Tecnologías de la Información y Comunicaciones
Elaborado por: Alejandro Guzmán Zazueta

Práctica 10. Geolocalización en Tiempo Real Android

Objetivo
El estudiante aprenderá a usar obtener la geolocalización del dispositivo móvil en tiempo real.

Introducción
Esta práctica es opcional y deberá usarla si su proyecto final requiere el uso de mapas.

Correlación con los temas y subtemas del programa de estudio


Esta práctica abona a la funcionalidad del proyecto final.

Material y equipo necesario


Computadora i3, i5 o i7 con mínimo de 8GB de Ram.
Acceso a Internet, para la creación de nuevo proyecto en Android Studio.

Metodología
El estudiante deberá leer el siguiente material y enseguida implementarla en Android Estudio:

Para este ejercicio utilizaremos el código del ejercicio “12. Mapas y marcas” (Guimerá, Google
Maps en Android con Kotlin [Parte 2] – Localización en tiempo real, 2021).

158
MANUAL DE PRÁCTICAS DE LA MATERIA “DESARROLLO DE APLICACIONES
PARA DISPOSITIVOS MÓVILES”
Carrera Ingeniería en Tecnologías de la Información y Comunicaciones
Elaborado por: Alejandro Guzmán Zazueta

Al proyecto anterior le vamos a agregar 3 nuevos permisos, ya que obviamente si queremos saber
la localización en tiempo real tendremos que tener acceso a dicha localización a través del permiso.
Iremos al AndroidManifest.xml y añadiremos los permisos resaltados en amarillo:

<?xml version="1.0" encoding="utf-8"?>


<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">

<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission
android:name="android.permission.ACCESS_FINE_LOCATION"/>
<uses-permission
android:name="android.permission.ACCESS_COARSE_LOCATION"/>

<application
android:allowBackup="true"
android:dataExtractionRules="@xml/data_extraction_rules"
android:fullBackupContent="@xml/backup_rules"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@style/Theme.MyProjectAndroid"
tools:targetApi="31">
<meta-data
android:name="com.google.android.geo.API_KEY"
android:value="@string/google_maps_key" />
<activity
android:name=".MainActivity"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />

<category
android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>

</manifest>

Una vez añadidos los permisos, nos cambiamos al código del MainActivity.kt y crearemos una
función de nombre isPermissionsGranted que usaremos a lo largo de nuestra app para comprobar
si el permiso ha sido aceptado o no.

159
MANUAL DE PRÁCTICAS DE LA MATERIA “DESARROLLO DE APLICACIONES
PARA DISPOSITIVOS MÓVILES”
Carrera Ingeniería en Tecnologías de la Información y Comunicaciones
Elaborado por: Alejandro Guzmán Zazueta

private fun isPermissionsGranted() = ContextCompat.checkSelfPermission(


this, android.Manifest.permission.ACCESS_FINE_LOCATION
) == PackageManager.PERMISSION_GRANTED

A través de esta función el programa sabrá si los permisos están activados o no, en seguida
creamos una nueva función de nombre enableMyLocation que compruebe si el mapa ha sido
inicializado, si no es así saldrá de la función con el return, si por el contrario map ya ha sido
inicializada, es decir que el mapa ya ha cargado, se comprobaran los permisos.
private fun enableMyLocation() {
if (!::map.isInitialized) return
if (isPermissionsGranted()) {
map.isMyLocationEnabled = true
} else {
requestLocationPermission()
}
}

Si los permisos están aceptados, llamaremos a la función map.isMyLocationEnabled = true


(Android Studio la subraya en rojo pero no es error), que nos activará la ubicación a tiempo real,
pero si por el contrario no están aceptados llamaremos a requestLocationPermission(), que será la
encargará de solicitar los permisos.
Obviamente te dará error porque todavía no la hemos creado, así que simplemente crearemos la
función requestLocationPermission().
// Este companion de declara a nivel de la clase
companion object {
const val REQUEST_CODE_LOCATION = 0
}

private fun requestLocationPermission() {


if (ActivityCompat.shouldShowRequestPermissionRationale(this,
android.Manifest.permission.ACCESS_FINE_LOCATION)) {
Toast.makeText(this, "Ve a ajustes y acepta los permisos",
Toast.LENGTH_SHORT).show()
} else {
ActivityCompat.requestPermissions(this,
arrayOf(android.Manifest.permission.ACCESS_FINE_LOCATION),
REQUEST_CODE_LOCATION)
}
}

160
MANUAL DE PRÁCTICAS DE LA MATERIA “DESARROLLO DE APLICACIONES
PARA DISPOSITIVOS MÓVILES”
Carrera Ingeniería en Tecnologías de la Información y Comunicaciones
Elaborado por: Alejandro Guzmán Zazueta

Se crea el companion object con una variable constante, que será el código de respuesta para
saber si al aceptarse permisos ha sido el nuestro.
Si entra en el if significa que ya había rechazado los permisos antes y por ello le mostramos un
toast avisándole de que vaya a los ajustes de la app y modifique los permisos. Si por el contrario
entra por el else significará que nunca le hemos pedido los permisos y lo haremos a través de la
función ActivityCompat.requestPermissions, pasándole la activity (this), el permiso o los permisos
que queremos que acepte (en este caso uno) y el código de localización que creamos en el
companion object.
El siguiente paso será crear el método que nos avise si al pedirle los permisos los ha aceptado. Para
ello tendremos que sobre escribir el método onRequestPermissionsResult().
La instrucción map.isMyLocationEnabled = true la subraya en rojo, pero no es error.
override fun onRequestPermissionsResult(
requestCode: Int,
permissions: Array<out String>,
grantResults: IntArray)
{
when(requestCode){
REQUEST_CODE_LOCATION -> if(grantResults.isNotEmpty() &&
grantResults[0]==PackageManager.PERMISSION_GRANTED){
map.isMyLocationEnabled = true
}else{
Toast.makeText(this, "Para activar la localización ve a
ajustes y acepta los permisos", Toast.LENGTH_SHORT).show()
}
else -> {}
}
}

El evento onRequestPermissionsResult se llamará automáticamente cuando el usuario acepte o


rechace los permisos, si los acepta volver a llamar a map.isMyLocationEnabled = true, si por el
contrario los rechaza le mostraremos un toast avisando que si quiere la ubicación a tiempo real
vaya a los ajustes y acepte los permisos.
El flujo de los permisos ya está terminado, pero si se fijan la primera función que hicimos
enableLocation() que será la que inicie todo el flujo de los permisos. ¿Dónde se va a llamar? Pues
en la función onMapReady() ya que tendremos que utilizarlo cuando el mapa esté funcionando.

161
MANUAL DE PRÁCTICAS DE LA MATERIA “DESARROLLO DE APLICACIONES
PARA DISPOSITIVOS MÓVILES”
Carrera Ingeniería en Tecnologías de la Información y Comunicaciones
Elaborado por: Alejandro Guzmán Zazueta

override fun onMapReady(googleMap: GoogleMap) {


map = googleMap
createMarker()
enableMyLocation()
}

Sin embargo ¿Qué pasaría si ahora salgo de la app, voy a ajustes y desactivo los permisos?
Obviamente nuestra app los necesita y eso provocaría que la aplicación falle y es por eso que
tenemos que añadir un último método onResumeFragments.
override fun onResumeFragments() {
super.onResumeFragments()
if (!::map.isInitialized) return
if(!isPermissionsGranted()){
map.isMyLocationEnabled = false
Toast.makeText(this, "Para activar la localización ve a ajustes
y acepta los permisos", Toast.LENGTH_SHORT).show()
}

Este código se ejecuta cuando regresamos a la app, después de hacer alguna otra cosa en el
dispositivo y lo primero que debemos hacer es comprobar si el mapa ha cargado, si no es así
salimos del método. Luego volvemos a comprobar si los permisos siguen activos, si no siguen
activos, desactivamos la localización en tiempo real y le mostramos un toast.

162
MANUAL DE PRÁCTICAS DE LA MATERIA “DESARROLLO DE APLICACIONES
PARA DISPOSITIVOS MÓVILES”
Carrera Ingeniería en Tecnologías de la Información y Comunicaciones
Elaborado por: Alejandro Guzmán Zazueta

Figura 65

Botón de Ubicación en Tiempo Real

Nota La flecha roja indica el botón de ubicación en tiempo real

Con lo que hemos programado de la app hasta aquí ya podríamos decir que tenemos la localización
en tiempo real completa.
Para empezar ¿Recuerdas el botón que apareció en el mapa? (ver figura 65) ¿El que te lleva a tu
posición (señalado con flecha roja)? pues podemos modificar su comportamiento, para que nos
lleve a la localización de nuestro dispositivo y si el usuario da clic no mande un mensaje con la
localización en función de Latitud y Longitud. Para ello iremos a la parte superior de nuestra activity
y añadiremos las implementaciónes OnMyLocationButtonClickListener y
OnMyLocationClickListener.
class MainActivity : AppCompatActivity(), OnMapReadyCallback,
OnMyLocationButtonClickListener,OnMyLocationClickListener {

Al añadir las implementaciones nos saldrá un error en el nombre de nuestra clase, porque hemos
implementado una función, pero no la hemos añadido en el código así que añadimos los siguientes
métodos.

163
MANUAL DE PRÁCTICAS DE LA MATERIA “DESARROLLO DE APLICACIONES
PARA DISPOSITIVOS MÓVILES”
Carrera Ingeniería en Tecnologías de la Información y Comunicaciones
Elaborado por: Alejandro Guzmán Zazueta

override fun onMyLocationButtonClick(): Boolean {


Toast.makeText(this, "Boton pulsado", Toast.LENGTH_SHORT).show()
return false
}
override fun onMyLocationClick(p0: Location) {
Toast.makeText(this, "Estás en ${p0.latitude}, ${p0.longitude}",
Toast.LENGTH_SHORT).show()
}

La función onMyLocationButtonClick se llamará automáticamente al pulsar el botón de centrarnos


(marcado con flecha roja en la imagen anterior), se añadió un toast para mostrar cada vez que se
pulse. Además, hay que devolver un Boolean, si devolvemos false el botón nos centrará en nuestra
ubicación, si por el contrario devolvemos true al pulsar el botón no nos llevará a nuestra
localización.
En la segunda función de nombre onMyLocationClick que se agregó, no regresa nada, pero
recibimos un parámetro de localización, este se dispara cuando el usuario da clic en el punto del
mapa que marca su localización (punto azul), mostrándonos en un mensaje la ubicación en latitud
y longitud.
Para terminar, tenemos que decir que nuestra clase implementa las funciones, es decir, que al
pulsar el botón la función que se llame sea la nuestra, para ello las añadimos en el método
onMapReady como se muestra en el siguiente código:
override fun onMapReady(googleMap: GoogleMap) {
map = googleMap
createMarker()
map.setOnMyLocationButtonClickListener(this)
map.setOnMyLocationClickListener(this)
enableMyLocation()
}

El código del MainActivity.kt, se muestra a continuación:


package com.example.myprojectandroid

import android.content.pm.PackageManager
import android.location.Location
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.widget.Toast
import androidx.core.app.ActivityCompat

164
MANUAL DE PRÁCTICAS DE LA MATERIA “DESARROLLO DE APLICACIONES
PARA DISPOSITIVOS MÓVILES”
Carrera Ingeniería en Tecnologías de la Información y Comunicaciones
Elaborado por: Alejandro Guzmán Zazueta

import androidx.core.content.ContextCompat
import com.google.android.gms.maps.CameraUpdateFactory
import com.google.android.gms.maps.GoogleMap
import
com.google.android.gms.maps.GoogleMap.OnMyLocationButtonClickListener
import com.google.android.gms.maps.GoogleMap.OnMyLocationClickListener
import com.google.android.gms.maps.OnMapReadyCallback
import com.google.android.gms.maps.SupportMapFragment
import com.google.android.gms.maps.model.LatLng
import com.google.android.gms.maps.model.MarkerOptions

class MainActivity : AppCompatActivity(), OnMapReadyCallback,


OnMyLocationButtonClickListener,OnMyLocationClickListener {
private lateinit var map: GoogleMap
companion object {
const val REQUEST_CODE_LOCATION = 0
}

override fun onCreate(savedInstanceState: Bundle?) {


super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
createMapFragment()
}

private fun createMapFragment() {


val mapFragment =
supportFragmentManager.findFragmentById(R.id.fragmentMap) as
SupportMapFragment
mapFragment.getMapAsync(this)
}

override fun onMapReady(googleMap: GoogleMap) {


map = googleMap
createMarker()
map.setOnMyLocationButtonClickListener(this)
map.setOnMyLocationClickListener(this)
enableMyLocation()
}

private fun createMarker() {


val coordenadas = LatLng(20.577997, -100.825393)
val marca : MarkerOptions =
MarkerOptions().position(coordenadas).title("TecNM en Roque")
map.addMarker(marca)

map.animateCamera(CameraUpdateFactory.newLatLngZoom(coordenadas,18f),
4000,
null
)
}

private fun isPermissionsGranted() =


ContextCompat.checkSelfPermission(
this, android.Manifest.permission.ACCESS_FINE_LOCATION

165
MANUAL DE PRÁCTICAS DE LA MATERIA “DESARROLLO DE APLICACIONES
PARA DISPOSITIVOS MÓVILES”
Carrera Ingeniería en Tecnologías de la Información y Comunicaciones
Elaborado por: Alejandro Guzmán Zazueta

) == PackageManager.PERMISSION_GRANTED

private fun enableMyLocation() {


if (!::map.isInitialized) return
if (isPermissionsGranted()) {
map.isMyLocationEnabled = true
} else {
requestLocationPermission()
}
}

override fun onRequestPermissionsResult(


requestCode: Int,
permissions: Array<out String>,
grantResults: IntArray)
{
when(requestCode){
REQUEST_CODE_LOCATION -> if(grantResults.isNotEmpty() &&
grantResults[0]==PackageManager.PERMISSION_GRANTED){
map.isMyLocationEnabled = true
}else{
Toast.makeText(this, "Para activar la localización ve a
ajustes y acepta los permisos", Toast.LENGTH_SHORT).show()
}
else -> {}
}
}

private fun requestLocationPermission() {


if (ActivityCompat.shouldShowRequestPermissionRationale(this,
android.Manifest.permission.ACCESS_FINE_LOCATION)) {
Toast.makeText(this, "Ve a ajustes y acepta los permisos",
Toast.LENGTH_SHORT).show()
} else {
ActivityCompat.requestPermissions(this,

arrayOf(android.Manifest.permission.ACCESS_FINE_LOCATION),
REQUEST_CODE_LOCATION)
}
}

override fun onResumeFragments() {


super.onResumeFragments()
if (!::map.isInitialized) return
if(!isPermissionsGranted()){
map.isMyLocationEnabled = false
Toast.makeText(this, "Para activar la localización ve a
ajustes y acepta los permisos", Toast.LENGTH_SHORT).show()
}
}

override fun onMyLocationButtonClick(): Boolean {


Toast.makeText(this, "Boton pulsado",
Toast.LENGTH_SHORT).show()

166
MANUAL DE PRÁCTICAS DE LA MATERIA “DESARROLLO DE APLICACIONES
PARA DISPOSITIVOS MÓVILES”
Carrera Ingeniería en Tecnologías de la Información y Comunicaciones
Elaborado por: Alejandro Guzmán Zazueta

return false
}

override fun onMyLocationClick(p0: Location) {


Toast.makeText(this, "Estás en ${p0.latitude},
${p0.longitude}", Toast.LENGTH_SHORT).show()
}
}

Al ejecutar la aplicación damos clic en el punto de la esquina superior derecha, para que nos lleve
a nuestra ubicación y si damos clic en ella, nos mostrara las coordenadas, como se muestra en la
siguiente figura:

Figura 66

Ejecución de Ubicación en Tiempo Real

Nota: Interfaz en ejecución de la aplicación, mostrando ubicación en tiempo real

167
MANUAL DE PRÁCTICAS DE LA MATERIA “DESARROLLO DE APLICACIONES
PARA DISPOSITIVOS MÓVILES”
Carrera Ingeniería en Tecnologías de la Información y Comunicaciones
Elaborado por: Alejandro Guzmán Zazueta

Bibliografía
Ardións, A. (19 de Abril de 2015). AS.com. Obtenido de AS.com:
https://androidstudiofaqs.com/conceptos/cual-es-la-estructura-de-un-proyecto-en-android-
studio

Colectiva, N. (15 de 08 de 2018). Que son los Layouts y cuales existen en Android Studio. Obtenido de
https://blog.nubecolectiva.com/que-son-los-layouts-y-cuales-existen-en-android-studio/

Developers, A. (6 de 03 de 2023). Android para Desarroladores. Obtenido de


https://developer.android.com/studio/intro?hl=es-419

Google Developers. (14 de Junio de 2018). Developers. Obtenido de Developers:


https://developer.android.com/studio/intro?hl=es-419

Guimerá, A. (12 de 11 de 2020). Google Maps en Android con Kotlin. Obtenido de


https://cursokotlin.com/capitulo-28-google-maps-en-android-con-kotlin/

Guimerá, A. (28 de 01 de 2021). Google Maps en Android con Kotlin [Parte 2] – Localización en tiempo
real. Obtenido de https://cursokotlin.com/capitulo-30-google-maps-en-android-con-kotlin-
parte-2-localizacion-en-tiempo-real-kotlin/

Jaureguialzo, I. (21 de 05 de 2017). Curso de Kotlin. Obtenido de


https://www.youtube.com/watch?v=IghzY7R2nhI&list=PLxL0ASjNO0ggH-k3AeNh9H8E8EXxj-
1XC&index=1

Naeem, T. (20 de 01 de 2020). Comprender los conceptos básicos de las API REST. Obtenido de
https://www.astera.com/es/type/blog/rest-api-definition/

Perez, M. (03 de 01 de 2016). Geeky Theory JSON I - ¿Qué es y para qué sirve JSON? Obtenido de
https://geekytheory.com/json-i-que-es-y-para-que-sirve-json/

PYM. (17 de 03 de 2017). Programación y Más "Android: Listas dinámicas usando RecyclerView".
Obtenido de https://programacionymas.com/blog/listas-dinamicas-android-usando-recycler-
view-card-view

PyM. (04 de 07 de 2023). Programación y Mas. Obtenido de https://programacionymas.com/blog/listas-


dinamicas-android-usando-recycler-view-card-view

Revelo, J. (13 de 11 de 2014). Tutorial de Bases de datos SQLite en Aplicaciones Android. Obtenido de
https://es.paperblog.com/tutorial-de-bases-de-datos-sqlite-en-aplicaciones-android-2926645/

Tutoriales, A. G. (10 de 04 de 2020). Spinner en Android Studio. Obtenido de


https://appgametutoriales.com/spinner-en-android-studio/

168

También podría gustarte