Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                

Primeros Pasos en Android: 1.1. Cómo Las Aplicaciones Proporcionan Puntos de Entrada

Descargar como docx, pdf o txt
Descargar como docx, pdf o txt
Está en la página 1de 32

1.

Primeros Pasos en Android


En este capítulo vamos una aplicación para Android simple. Primero, aprenderemos como crear y ejecutar un
proyecto “Hola, ¡Mundo!" con Android Studio. Luego, crearás una nueva interfaz para las aplicaciones que
requiere la entrada del usuario y cambia a una nueva pantalla en la aplicación a fin de mostrarla.

Antes de comenzar, analizaremos dos conceptos fundamentales que debemos comprender sobre las aplicaciones
en Android: cómo las aplicaciones proporcionan puntos de entrada y cómo estas se adaptan a los diferentes
dispositivos.

1.1. Cómo las aplicaciones proporcionan puntos de entrada

Las aplicaciones para Android se compilan como una combinación de componentes que pueden invocarse de
manera individual. Por ejemplo, una actividad es un tipo de componente de aplicación que proporciona una
interfaz de usuario (IU).

La actividad "principal" (Main Activity) comienza cuando el usuario presiona el ícono de la aplicación.
También podemos dirigir al usuario a una actividad de otro lugar, como una notificación o incluso una
aplicación diferente.

Otros componentes, como los receptores de emisión y los servicios, permiten que nuestra aplicación realice
tareas en segundo plano sin una IU.

1.2. Cómo las aplicaciones se adaptan a los diferentes dispositivos

Android nos permite proporcionar diferentes recursos para distintos dispositivos. Por ejemplo, podemos crear
diferentes diseños para distintos tamaños de pantalla. El sistema determina qué diseño usar en función del
tamaño de la pantalla del dispositivo actual.

Si alguna de las funciones de nuestra aplicación necesita hardware específico, como una cámara, durante el
tiempo de ejecución, podemos consultar si el dispositivo tiene ese hardware o no, y luego inhabilitar las
funciones correspondientes si no lo tiene. Podemos especificar que nuestra aplicación requiera ciertos tipos de
hardware a fin de que Google Play no permita que se instale la aplicación en dispositivos que no los tengan.

1.3. Desarrollando una aplicación simple “Hola Mundo”

Ahora veremos cómo crear una aplicación simple en Android. Nuestra aplicación contará de una única pantalla
(Activity) en la cual mostraremos el mensaje “Hola Mundo”. Lo primero que debemos saber es que la estructura
de un proyecto de una Aplicación Android está dividida en secciones. Una sección sirve para alojar todo el
código JAVA, mientras que otra sección sirve para alojar recursos como imágenes, sonidos, definiciones de
interfaces, etc. Esta sección de recursos a su vez también se divide en diferentes secciones según lo
necesitemos, como layouts, menus, drawable, etc. También hay una sección que permite definir las cualidades
de nuestra aplicación en un archivo de manifiesto (AndroidManifest). La estructura típica de un proyecto se
puede apreciar en la figura 1.1.
Figura 1.1: Estructura de un proyecto Android

En la imagen se puede apreciar la carpeta manifests, java, y res. En la carpeta manifests solamente se
encuentran el archivo AndroidManifest.xml. En la carpeta Java encontramos los archivos de código Java. Y en
la carpeta res (resources – Recursos) están las diferentes categorías de recursos que nuestra aplicación puede
necesitar. Algunas de las que mas vamos a necesitar son la carpeta de layout y la carpeta de values.

Para crear nuestra aplicación simple hemos creado un proyecto que contiene una archivo MainActivity.java en
la carpeta java en el paquete hn.edu.unah.holamundo. También se ha creado un archivo activity_main.xml en la
carpeta de layout de la carpeta res tal como se muestra en la figura 1.2.

Figura 1.2: Ubicación de Actividad Principal

NOTA: En la imagen se puede apreciar que en la carpeta de java el archivo MainActivity no se muestra la
extensión (es decir que no se muestra como MainActivity.java sino como MainActivity). Esto es así porque
aquí solo se muestra el nombre de la clase no el nombre del archivo recordemos que en java una clase publica
debe estar guardada en un archivo con el mismo nombre y la extensión java.

Ahora vamos a analizar el código de nuestros archivos activity_main.xml y MainActivity.java En primer lugar
vamos a revisar el código de nuestra interfaz, es decir el archivo activity_main.xml.

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


<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">
    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Hola Mundo" />
</LinearLayout>
En este archivo hemos definido una simple pantalla con un esquema lineal vertical (LinearLayout
orientation=”vertical”) el cual contiene una única vista de texto (TextView) que muestra el texto “Hola mundo”
en pantalla. Analicemos este código por partes. En primer lugar, estamos utilizando un LinearLayout con los
atributos layout_width, con el valor de “match_parent” al igual que el atributo de layout_height. Estos atributos
pueden tener como valor las contantes, “match_parent” para indicar que el tamaño se ajusta al del contenedor o
“wrap_content” para indicar que el tamaño de la vista se ajusta al contenido esta. También hemos establecido el
atributo orientation en “vertical”. Este atributo puede tener el valor “vertical” u “horizontal”.

Dentro de nuestro LinearLayout hemos incluido un TextView al cual le hemos establecido el atributo text con el
valor de “Hola Mundo”. También hemos establecido los atributos layout_width y layout_height con el valor de
“wrap_content”.

Ahora vamos a revisar el código de nuestro archivo MainActivity.java. Realmente para este ejemplo nosotros
no hemos modificado nada ya que este es el código que genera Android estudio al momento de crear nuestra
aplicación.
package hn.edu.unah.holamundo;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
public class MainActivity extends AppCompatActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }
}
Los mas resaltable de este código es que nuestra clase debe extender de la clase Activity o de una clase que
extienda de Activity, en este caso extiende de AppCompatActivity. Dentro de esta clase se ha sobrescrito
(@Override) el método onCreate en el cual solamente se incluyen dos líneas de código. La primera línea solo
hace una invocación a la versión onCreate de la clase base. La segunda línea es la que indica de donde se toma
la interfaz de nuestra actividad. En este caso es del archivo activity_main. El resultado de ejecutar esta apliacion
es el que se muestra en la figura 1.3.

Figura 1.3: Hola mundo en Android.

1.4. Desarrollando una aplicación con eventos

La aplicación que hemos creado permite apreciar algunas características del desarrollo de aplicaciones Android.
Ahora vamos a darle un poco mas de vida permitiendo que el usuario interactúe con ella. Vamos a agregar un
botón que el usuario podrá presionar y nuestra aplicación reaccionará a esa acción. Al momento que el usuario
presione el botón la aplicación mostrará un mensaje dando la bienvenida.

Lo primero que haremos será trabajar nuestra interfaz de usuario, en la cual agregaremos un botón. Los botones
en Android, al igual que los TextView, son vistas (Views). Las vistas son los componentes que utilizaremos
para crear nuestras interfaces de usuario UI. El LinearLayout también es una vista al igual que las anteriores
mencionadas. Abordaremos esto más adelante.  El código de nuestro activity_main.xml es el que se muestra a
continuación:

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


<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
android:orientation="vertical">
    <Button
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Saludar"
        android:onClick="saludar"/>
</LinearLayout>
Lo nuevo en este código es que hemos utilizado la vista botón (Button) a la cual le hemos asignado el valor
“Saludar” al atributo text. También hemos asignado un método que será el que realizará el trabajo cuando el
usuario haga click sobre el botón. Para estos hemos asignado el método “saludar” al atributo onClick. Para que
esto funcione correctamente en nuestra clase java debemos incluir un método llamado saludar que reciba como
parámetro un objeto de la clase android.view.View. este método debe ser public y tener como tipo de retorno
void. Esto lo podemos apreciar en el siguiente código java de nuestro MainActivity.java:
package hn.edu.unah.bienvenido;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Toast;

public class MainActivity extends AppCompatActivity {


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }
public void saludar(View view) {
        Toast.makeText(this, "Bienvenido", Toast.LENGTH_SHORT).show();
    }
}
Como se puede apreciar el método saludar muestra una pequeña notificación utilizando la clase Toast y su
método makeText. Este método necesita tres parámetros. El primero es el contexto, que por lo general es el
mismo contexto que la actividad en la que se encuentra por eso utilizamos la palabra this para indicar que se
utilice el contexto actual, el segundo parámetro es el mensaje que queremos que el usuario reciba y por último
el tercer parámetro es la duración que tendrá el mensaje en pantalla. La duración puede ser larga
(Toast.LENGTH_LONG) o corta (Toas.LENGTH_SHORT).  Por último, utilizamos el método show para
mostrar el mensaje. El resultado de esta aplicación es el que se aprecia en la figura 1.4:

Figura 1.4: Mensaje simple

1.5. Conclusión

Como pudimos ver en este capítulo, desarrollar aplicaciones en Android son bastante sencillo ya que los
proyectos en Android Studio aplicaciones separan apropiadamente los recurso (imágenes, interfaces de usuario,
sonidos) del código java lo que permite manipular más fácilmente cada uno de estos elementos enfocándonos
solamente en lo que compete a cada elemento sin mezclar, por ejemplo, el código que define la funcionalidad de
la aplicación con la interfaz de esta. 

2. Recurso y AndroidManifest
En este capitulo trataremos algunos aspectos conceptuales que necesitamos saber para poder
desarrollar aplicaciones en Android. Estos son los recursos y el archivo de manifiesto de Android
(AndroidManifest)

Los recursos son los archivos adicionales y el contenido estático que usa nuestro código, como
mapas de bits, definiciones de diseño, strings de interfaz de usuario, instrucciones de animación, etc.
Siempre debemos externalizar los recursos para aplicaciones, como imágenes y strings del resto de
nuestro código, para que podamos mantenerlos de forma independiente. También debemos
proporcionar recursos alternativos para configuraciones de dispositivos específicos, agrupándolos en
directorios de recursos con un nombre especial. Durante la ejecución, Android utiliza el recurso
adecuado según la configuración actual. Por ejemplo, podemos proporcionar un diseño de interfaz
de usuario (IU) diferente según el tamaño de la pantalla o strings diferentes según la configuración
de idioma.

Una vez que externalizas los recursos para nuestra aplicación, podemos acceder a ellos a través los
ID de recursos que se generan en la clase R de nuestro proyecto. En este capítulo veremos cómo
podemos agrupar los recursos en un proyecto de Android y acceder a ellos desde el código de
nuestra aplicación u otros archivos XML posteriormente.

3.1. Recursos de la Aplicación

Los recursos de nuestra aplicación pueden ser de diferentes tipos y es necesario ubicarlos
apropiadamente dentro de la carpeta correspondiente. Todas las carpetas de recursos los
colocaremos dentro de la carpeta res. La tabla 3.1 muestra los diferentes tipos de carpetas que
podemos tener dentro de nuestra carpeta de recursos.

Directorio Tipo de recurso


animator/ Archivos XML que definen animaciones de propiedades.
Archivos XML que definen animaciones de interpolación de movimiento. En
este directorio, también se pueden guardar animaciones de propiedades,
anim/
pero se prefiere el directorio animator/ para las animaciones de
propiedades, a fin de distinguir entre los dos tipos.
Archivos XML que definen una lista de estados de colores. Consulta la
color/
sección Recurso de lista de estado de colores.
Archivos de mapas de bits (.png, .9.png, .jpg y .gif) o archivos XML que se
han compilado en los siguientes subtipos de recursos de elemento de
diseño:

 Archivos de mapas de bits


drawable/  Nueve parches (mapas de bits reajustables)
 Listas de estados
 Formas
 Elementos de diseño de animaciones
 Otros elementos de diseño

Consulta la sección Recursos dibujables.


Archivos de elementos de diseño para diferentes densidades de los íconos
de selectores. Para obtener más información sobre la administración de los
mipmap/
íconos de selectores con carpetas mipmap/, consulta la
sección Información general sobre la administración de proyectos.
Archivos XML que definen el diseño de una interfaz de usuario. Consulta la
layout/
sección Recurso de diseño.
Archivos XML que definen menús de aplicaciones, como un menú de
menu/ opciones, un menú contextual o un submenú. Consulta la sección Recurso
de menú.
raw/ Archivos arbitrarios para guardar sin procesar. Para abrir estos recursos
con un objeto InputStream sin procesar, llama
a Resources.openRawResource() con el ID del recurso, que
es R.raw.filename.
Sin embargo, si necesitas acceder a los nombres de los archivos originales
y a la jerarquía de archivos, puedes considerar la posibilidad de guardar
algunos recursos en el directorio assets/ (en lugar de res/raw/). A los
archivos de assets/ no se les asigna un ID de recurso, por lo cual puedes
leerlos solamente mediante AssetManager.
Archivos XML que contienen valores simples, como strings, valores enteros
y colores.
Los archivos de recursos XML en otros subdirectorios res/ definen un único
recurso basado en el nombre del archivo XML, mientras que los archivos
del directorio values/ describen varios recursos. En el caso de un archivo
de este directorio, cada campo secundario del
elemento <resources> define un único recurso. Por ejemplo, un
elemento <string> crea un recurso R.string, y un elemento <color> crea un
recurso R.color.
Dado que cada recurso se define con su propio elemento XML, puedes
asignar el nombre que desees al archivo y colocar diferentes tipos de
recursos en un archivo. Sin embargo, para mayor claridad, es
values/ recomendable que coloques tipos de recursos únicos en diferentes
archivos. Por ejemplo, a continuación, se incluyen algunas convenciones
de asignación de nombres de archivos para los recursos que puedes crear
en este directorio:

 arrays.xml para matrices de recursos (matrices escritas).


 colors.xml para valores de color.
 dimens.xml para valores de dimensión.
 strings.xml para valores de strings.
 styles.xml para estilos.

Consulta las secciones Recursos de strings, Recursos de estilo y Más tipos de


recursos.
Archivos XML arbitrarios que se pueden leer en tiempo de ejecución
llamando a Resources.getXML(). Aquí se deben guardar diversos archivos
xml/
de configuración XML, por ejemplo, una configuración que permite
búsqueda.
Archivos de fuentes, con extensiones como .ttf, .otf o .ttc, o archivos XML
font/ que incluyan un elemento <font-family>. Para obtener más información
sobre las fuentes como recursos, ve a Fuentes en XML.
Tabla 3.1: Tipos de recursos carpetas de recursos.

Para saber un poco mas sobre los recursos visite la


dirección: https://developer.android.com/guide/topics/resources/providing-resources.

3.2. Archivo de Manifiesto

Todos los proyectos de aplicaciones deben tener un archivo AndroidManifest.xml (con ese mismo
nombre) en la raíz de la fuente del proyecto. El archivo de manifiesto describe información esencial
de nuestra aplicación para las herramientas de creación de Android, el sistema operativo Android y
Google Play.
Entre muchas otras cosas, el archivo de manifiesto debe declarar lo siguiente:

 El nombre del paquete de la aplicación, que normalmente coincide con el espacio de nombres de tu
código. Las herramientas de compilación de Android usan esto para determinar la ubicación de las
entidades de código cuando se compila el proyecto. Al empaquetar la aplicación, las herramientas de
compilación sustituyen este valor por el ID de aplicación de los archivos de compilación de Gradle, que
se utiliza como identificador único de la aplicación en el sistema y en Google Play. Obtén más
información sobre el nombre del paquete y el ID de la aplicación.
 Los componentes de la aplicación, que incluyen todas las actividades, servicios, receptores de
emisiones y proveedores de contenido. Cada componente debe definir propiedades básicas, como el
nombre de su clase Kotlin o Java. También puede declarar capacidades, como las configuraciones de
dispositivos que puede manejar, además de filtros de intents que describen cómo se puede iniciar el
componente. Obtén más información sobre los componentes de la aplicación.
 Los permisos que necesita la aplicación para acceder a las partes protegidas del sistema o a otras
aplicaciones. También declara cualquier permiso que otras aplicaciones deben tener si quieren
acceder al contenido de esta aplicación. Obtén más información sobre los permisos.
 Las funciones de hardware y software que requiere la aplicación afectan a los dispositivos que pueden
instalar la aplicación desde Google Play. Obtén más información sobre la compatibilidad de
dispositivos.

Si usamos Android Studio para crear una aplicación, se generará el archivo de manifiesto
automáticamente, y la mayoría de los elementos esenciales de este se irán agregando a medida que
compilemos la aplicación (especialmente cuando usemos plantillas de código).

3.3. Funciones del archivo AndroidManifest

Algunas de las características más importantes de nuestra aplicación se reflejan en el archivo de


manifiesto:

 Nombre del paquete e ID de la aplicación


 Componentes de la aplicación
 Permisos
 Compatibilidad con dispositivos

Nombre del paquete e ID de la aplicación

El elemento raíz del archivo de manifiesto requiere un atributo para el nombre del paquete de tu
aplicación (que normalmente coincide con la estructura del directorio del proyecto: el espacio de
nombres de Java).

Mientras compilas tu aplicación en el paquete de aplicación final (APK), las herramientas de


compilación de Android utilizan el atributo package para dos cosas:

 Aplica este nombre como espacio de nombres para la clase R.java generada de tu app (se usa para
acceder a los recursos de la aplicación). Ejemplo: Con el manifiesto anterior, se crea la clase R en
com.example.myapp.R.
 Usa este nombre para resolver cualquier nombre de clase relativo que se declare en el archivo de
manifiesto. Ejemplo: Con el manifiesto anterior, se resuelve una actividad declarada como <activity
android:name=".MainActivity"> y pasa a ser com.example.myapp.MainActivity.

Como tal, el nombre del atributo package del manifiesto siempre debe coincidir con el nombre de
paquete básico de tu proyecto, en el cual conservas tus actividades y otros tipos de código de la
aplicación. Por supuesto, puedes tener otros subpaquetes en tu proyecto, pero esos archivos deben
importar la clase R.java usando el espacio de nombres del atributo package.
 

Componentes de la aplicación
Por cada componente de la aplicación que creemos en nuestro proyecto, deberemos declarar un
elemento XML correspondiente en el archivo de manifiesto:

 <activity> para cada subclase de Activity.


 <service> para cada subclase de Service.
 <receiver> para cada subclase de BroadcastReceiver.
 <provider> para cada subclase de ContentProvider.

Si incluimos en subclases cualquiera de estos componentes sin declararlo en el archivo de


manifiesto, el sistema no podrá iniciarlo.

Permisos
Las aplicaciones de Android deben solicitar permiso para acceder a datos del usuario confidenciales
(como contactos y SMS) o a determinadas funciones del sistema (como la cámara y el acceso a
Internet).

A partir de Android 6.0 (nivel de API 23), el usuario puede aprobar o rechazar algunos permisos
durante el tiempo de ejecución. No obstante, sin importar qué versión de Android admita tu
aplicación, debes declarar todas las solicitudes de permisos con un elemento <uses-permission> en
el manifiesto. Si se otorga el permiso, la aplicación puede usar las funciones protegidas. De lo
contrario, los intentos de acceder a esas funciones fallarán.

Compatibilidad con dispositivos


En el archivo de manifiesto, también puedes declarar qué tipos de funciones de hardware y software
requiere tu aplicación y, por lo tanto, qué tipos de dispositivos admite. Google Play Store no permite
que tu app se instale en dispositivos que no tienen las funciones o la versión del sistema que
requiere tu app.

Ejemplo de archivo de manifiesto

El XML que aparece a continuación es un AndroidManifest.xml simple de ejemplo que declara dos
actividades de la aplicación.

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

<manifest
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:versionCode="1"
    android:versionName="1.0"
    package="com.example.myapp">

    <!-- Beware that these values are overridden by the build.gradle file -->
    <uses-sdk android:minSdkVersion="15" android:targetSdkVersion="26" />
    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:label="@string/app_name"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">

        <!-- This name is resolved to com.example.myapp.MainActivity


             based upon the package attribute -->
        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>

        <activity
            android:name=".DisplayMessageActivity"
            android:parentActivityName=".MainActivity" />
    </application>
</manifest>
3.4. Permisos de Apps

El objetivo de un permiso es proteger la privacidad del usuario de Android. Las aplicaciones para
Android deben solicitar permiso para acceder a datos sensibles del usuario (como contactos y SMS)
y algunas funciones del sistema (como Internet y la cámara). Según la función, el sistema podría
otorgar automáticamente el permiso o pedirle al usuario que apruebe la solicitud.

Un punto central del diseño de la arquitectura de seguridad de Android consiste en que ninguna
aplicación, de forma predeterminada, tiene permiso para realizar operaciones que pudieran tener
consecuencias negativas para otras aplicaciones, el sistema operativo o el usuario. Esto incluye leer
datos privados de los usuarios o escribir en ellos (por ejemplo, los contactos o los mensajes de
correo electrónico), leer archivos de otra aplicación o escribir en ellos, acceder a una red, mantener
el dispositivo activo, etcétera.

Aprobación de permisos

Una aplicación debe publicitar los permisos que requiere incluyendo etiquetas <uses-permission> en
el manifiesto de la app. Por ejemplo, en el manifiesto de una app que necesite enviar mensajes SMS,
debería incluirse esta línea:

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.snazzyapp">

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


    <application ...>
    ...
    </application>
</manifest>
Si en el manifiesto de nuestra aplicación se incluyen permisos normales (es decir, los que no
presentan un gran riesgo para la privacidad del usuario o el funcionamiento del dispositivo), el
sistema otorgará automáticamente esos permisos.

Si en el manifiesto de nuestra aplicación se incluyen permisos riesgosos (es decir, los que podrían
afectar la privacidad del usuario o el funcionamiento normal del dispositivo), como el permiso de
SEND_SMS del ejemplo anterior, el sistema solicitará al usuario que otorgue explícitamente esos
permisos.

Solicitudes para permisos riesgosos

Solo los permisos riesgosos requieren la aprobación del usuario. El modo en el que Android le pide
al usuario que otorgue permisos riesgosos depende de la versión del sistema que se ejecuta en el
dispositivo del usuario y de la versión del sistema a la que se orienta nuestra aplicación.

Solicitudes de tiempo de ejecución (Android 6.0 y posteriores)


Si el dispositivo tiene instalado Android 6.0 (nivel 23 de API) o una versión posterior, y la
targetSdkVersion de la aplicación es de nivel 23 o posterior, el usuario no recibirá ninguna
notificación de permisos durante la instalación. La aplicación debe pedirle al usuario que otorgue
permisos riesgosos durante el tiempo de ejecución. Cuando la aplicación solicita un permiso, el
usuario ve un diálogo del sistema que le indica a qué grupo de permisos está intentando acceder la
aplicación. El diálogo incluye los botones Denegar y Permitir.

Si el usuario rechaza la solicitud de permiso, la próxima vez que la aplicación solicite el permiso, el
diálogo incluirá una casilla de verificación que, si se marca, indicará que el usuario no desea que se
le vuelva a pedir el permiso.

Incluso si el usuario le otorga a la aplicación el permiso que solicitó, esto no te garantizará que
siempre lo tendrá. Además, los usuarios tienen la opción de habilitar o inhabilitar permisos uno por
uno en la configuración del sistema. Siempre deberíamos verificar y solicitar permisos durante el
tiempo de ejecución, a fin de evitar errores durante ese momento.

Solicitudes en el momento de la instalación (Android 5.1.1 y anteriores)


Si el dispositivo tiene instalado Android 5.1.1 (nivel 22 de API) o versiones anteriores, o si el atributo
targetSdkVersion es 22 o inferior y se ejecuta en cualquier versión de Android, el sistema le pedirá
automáticamente al usuario que otorgue todos los permisos riesgosos para nuestra aplicación en el
momento de la instalación

Si el usuario hace clic en Aceptar, se otorgarán todos los permisos solicitados por la aplicación. Si el
usuario rechaza la solicitud de permisos, el sistema cancelará la instalación de la aplicación.

Si se requieren permisos adicionales para instalar una actualización de la aplicación, se le pedirá al


usuario que acepte los nuevos permisos antes de actualizar la aplicación.

3.5. Conclusión

La separación del código y los recursos en una aplicación nos permite a nosotros como
desarrolladores tener un mayor control de los diferentes componentes que integran un proyecto de
aplicación así como mecanismo para dar soporte a diferentes tipos de dispositivos.

3. Ciclo de vida de una Activity


En el capítulo anterior vimos cómo desarrollar una aplicación simple. Esta aplicación contaba con
una única actividad (Activity). Antes de continuar con el estudio del desarrollo de aplicaciones nos
detendremos analizar ciclo de vida de una Activity.

 
2.1. Entendiendo el ciclo de vida de una Activity

Cuando un usuario navega por nuestra aplicación, las instancias de Activity atraviesan diferentes
estados de su ciclo de vida. La clase Activity, y todas las que extienden de ella, proporciona una
serie de métodos callback que permiten a la actividad saber que un estado cambió, esto es, saber
cuándo el sistema está creando, deteniendo o reanudando una actividad, o si el proceso en que se
encuentra a finalizado.

Con los callbacks de un ciclo de vida, podemos definir como se comportará una actividad cuando, el
usuario inicie, abandone o reanude esta. Por ejemplo, si creamos una aplicación para reproductor de
video, podemos pausar el video cuando el usuario cambie a otra aplicación. Cuando el usuario
regrese, podríamos reanudar la reproducción el video desde el mismo punto en que se pausó. Los
callbacks permiten realizar un trabajo específico que sea apropiado para cada cambio de estado de
aplicación esto nos permite hacer aplicaciones más sólidas y eficientes. Una buena implementación
de los callbacks del ciclo de vida nos puede ayudar a garantizar que nuestra aplicación:

 No falle si el usuario recibe una llamada telefónica o cambia a otra aplicación mientras usa la nuestra.
 No consuma recursos valiosos del sistema cuando el usuario no la use de forma activa.
 No pierda el progreso del usuario si este abandona nuestra aplicación y regresa a ella posteriormente.
 No falle ni pierda el progreso del usuario cuando se gire la pantalla entre la orientación horizontal y la
vertical.

2.2. Métodos del ciclo de vida de las actividades

Como mencionamos anteriormente, para manejar las transiciones entre las etapas del ciclo de vida
de una actividad, la clase Activity proporciona un conjunto básico de seis métodos callback:
onCreate(), onStart(), onResume(), onPause(), onStop() y onDestroy(). Android se encarga de
invocar cada uno de estos métodos activity entra en un nuevo estado. En la figura 2.1, se muestra
una representación visual de cómo trabajan estos métodos durante el ciclo de vida de una actividad.

Figura 2.1: Ilustración simplificada del ciclo de vida de una actividad

Según la complejidad de nuestra activity, probablemente no necesitemos implementar todos los


métodos de ciclo de vida. Sin embargo, es importante que comprendamos cada uno de ellos y que
implementemos aquellos que garanticen que nuestra aplicación como los usuarios esperan. Es por
esto por lo que analizaremos en detalle cada uno de los métodos involucrados en el ciclo de vida de
una activity.

onCreate()
Este método siempre los debemos implementar ya que se activa cuando el sistema crea la actividad
por primera vez. Cuando se crea la actividad, esta entra en el estado Created. En el método
onCreate(), ejecutaremos la lógica de arranque básica de la aplicación que debe ocurrir una sola vez
en todo el ciclo de vida de la actividad. Este método recibe el parámetro savedInstanceState, que es
un objeto Bundle que contiene el estado ya guardado de la activity. Si la actividad nunca ha existido,
el valor del objeto Bundle es nulo.

 
onStart()
Cuando la actividad entra en el estado Started, el sistema invoca este método. onStart() hace que el
usuario pueda ver la actividad, mientras la aplicación se prepara para que esta entre en primer plano
y se convierta en interactiva. Por ejemplo, este método es donde la aplicación inicializa el código que
mantiene la interfaz de usuario (IU). El método onStart() se completa muy rápido y, al igual que con
el estado Created, la actividad no permanece en el estado Started. Una vez finalizada este método,
la actividad entra en el estado Resumed, y el sistema invoca el método onResume().

onResume()
Cuando la actividad entra en el estado Resumed, pasa al primer plano y, a continuación, el sistema
invoca la devolución de llamada onResume(). Este es el estado en el que la app interactúa con el
usuario. La app permanece en este estado hasta que ocurre algún evento que la quita de foco. Tal
evento podría ser, por ejemplo, recibir una llamada telefónica, que el usuario navegue a otra
actividad o que se apague la pantalla del dispositivo. Cuando se produce un evento interrumpa la
actividad, esta entra en el estado Paused y el sistema invoca la devolución de llamada onPause(). Si
la actividad regresa al estado Resumed desde Paused, el sistema volverá a llamar al método
onResume(). Por esta razón, debemos implementar onResume() para inicializar los componentes
que lancemos en onPause() y realizar otras inicializaciones que deban ejecutarse cada vez que la
actividad entre en el estado Resumed.

onPause()
Android llama a este método a modo de primera indicación de que:

 el usuario está abandonando nuestra actividad (aunque no siempre significa que está finalizando la
actividad);
 indica que la actividad ya no está en primer plano (aunque puede seguir siendo visible si el usuario
está en el modo multiventana).

Debemos utilizar el método onPause() para pausar o ajustar las operaciones que no deben continuar
(o que deben continuar con moderación) mientras la activity se encuentra en estado Paused, y que
esperamos reanudar en breve. Hay varias razones por las que una actividad puede entrar en este
estado. Por ejemplo:

 Algunos eventos interrumpen la ejecución de la app, como se describe en la sección onResume(). Este
es el caso más común.
 En Android 7.0 (API nivel 24) o versiones posteriores, varias apps se ejecutan en el modo
multiventana. Debido a que solo una de las apps (ventanas) tiene foco en cualquier momento, el
sistema pausa todas las demás.
 Se abre una nueva actividad semitransparente (como un diálogo). Mientras la actividad siga siendo
parcialmente visible, pero no esté en foco, se mantendrá pausada.

También puedemos utilizar el método onPause() para liberar recursos del sistema, controladores de
sensores (como el GPS) o cualquier otro recurso que pueda afectar la duración de la batería
mientras nuestra actividad esté en pausa y el usuario no los necesite.

 
onStop()
Cuando el usuario ya no puede ver tu actividad, significa que ha entrado en el estado Stopped, y el
sistema invoca la devolución de llamada onStop(). Esto puede ocurrir, por ejemplo, cuando una
actividad recién lanzada cubre toda la pantalla. El sistema también puede llamar a onStop() cuando
haya terminado la actividad y esté a punto de finalizar.

En el método onStop(), la app debe liberar o ajustar los recursos que no son necesarios mientras no
sea visible para el usuario. Por ejemplo, nuestra aplicación podría pausar animaciones o cambiar de
actualizaciones de ubicación detalladas a más generales. Usar onStop() en lugar de onPause()
garantiza que continúe el trabajo relacionado con la IU, incluso cuando el usuario esté viendo
nuestra activity en el modo multiventana.

Desde el estado Stopped, la actividad regresa a interactuar con el usuario o se termina de ejecutar y
desaparece. Si regresa la actividad, el sistema llamará a onRestart(). Si se terminó de ejecutar
Activity, el sistema llamará a onDestroy(). En la siguiente sección, se explica la devolución de
llamada onDestroy().

onDestroy()
Se llama a onDestroy() antes de que finalice la actividad. El sistema invoca este método por los
siguientes motivos:

 La actividad está terminando (debido a que el usuario la descarta por completo o a que se llama a
finish()).
 El sistema está finalizando temporalmente la actividad debido a un cambio de configuración (como la
rotación de la pantalla o el modo multiventana).

Podemos diferenciar estos dos casos con el método utilizando el método isFinishing().

Si la actividad está terminando, onDestroy() es el método del ciclo de vida final que recibe la
actividad. Si se llama a onDestroy() como resultado de un cambio de configuración, el sistema crea
inmediatamente una nueva instancia de Activity y luego llama a onCreate() en esa nueva instancia
en la nueva configuración.

El método onDestroy() debe liberar todos los recursos que aún no han sido liberados por
devoluciones de llamada anteriores, como onStop().

2.3. Estado de actividad y expulsión de memoria

El sistema finaliza los procesos cuando necesita liberar RAM; la probabilidad de que el sistema
finalice un proceso determinado dependerá del estado del proceso en ese momento. El estado del
proceso, a su vez, depende del estado de la actividad que se ejecuta en el proceso. La tabla 2.1
muestra la correlación entre el estado del proceso, el estado de la actividad y la probabilidad de que
el sistema finalice el proceso.

Probabilidad de que finalice Estado del proceso Estado de la actividad


Menor Primer plano (en foco o por Created
estar en él)
Started

Resumed
Más Segundo plano (foco perdido) Paused
Mayor Segundo plano (no visible) Stopped
Vacío Destroyed
Tabla 2.1: Relación entre el ciclo de vida del proceso y el estado de la actividad

El sistema nunca finaliza una actividad de forma directa para liberar memoria. En su lugar, finaliza el
proceso en el que se ejecuta la actividad para eliminar no solo la actividad, sino también todo lo que
se ejecuta en el proceso. Para aprender a preservar y restaurar el estado de la IU de tu actividad
cuando finaliza el proceso iniciado por el sistema, consulta Cómo guardar y restablecer el estado de
una actividad. Un usuario también puede finalizar un proceso utilizando el Administrador de
aplicaciones de Configuración para finalizar la aplicación correspondiente.

2.4. Ejemplo de los métodos del ciclo de vida de una actividad

Ahora vamos a desarrollar una pequeña aplicación que demuestre el funcionamiento los métodos
involucrados en el ciclo de vida de una actividad. Para ver el comportamiento de cada método hemos
incluido un mensaje que se mostrará cada vez que uno de los métodos se ejecute. El mensaje
indicará que método es el que se está llevando a cabo.

MainActivty.java

package hn.edu.unah.ciclovida;

import androidx.appcompat.app.AppCompatActivity;

import android.os.Bundle;
import android.widget.Toast;

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Toast.makeText(this, "Actividad Creada", Toast.LENGTH_SHORT).show();
    }

    @Override
    protected void onStart() {
        super.onStart();
        Toast.makeText(this, "Actividad Iniciada", Toast.LENGTH_SHORT).show();
    }

    @Override
    protected void onResume() {
        super.onResume();
        Toast.makeText(this, "Actividad Reanudada", Toast.LENGTH_SHORT).show();
    }

    @Override
    protected void onPause() {
        Toast.makeText(this, "Actividad Pausada", Toast.LENGTH_SHORT).show();
        super.onPause();
    }

    @Override
    protected void onStop() {
        Toast.makeText(this, "Actividad Detenida", Toast.LENGTH_SHORT).show();
        super.onStop();
    }
   
    @Override
    protected void onDestroy() {
        Toast.makeText(this, "Actividad Destruida", Toast.LENGTH_SHORT).show();
        super.onDestroy();
    }
}

Se puede apreciar que en los métodos onCreate, onStart, onResume, siempre se invoca primero el
método de la super clase y luego ejecutamos nuestro código. En contraposición, en los métodos
onPause, onStop, onDestroy siempre ejecutaremos nuestro código y luego invocaremos el método
de la super clase.   

En cuanto a la interfaz no hemos hecho nada extraordinario. Le código de la UI es el que se muestra


a continuación:

activity_main.xml

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


<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Ciclo de vida"/>
</LinearLayout>

2.5. Conclusión

Los métodos callback del ciclo de vida nos proporcionan un mecanismo para controlar los diferentes
cambios de estado de una Activity lo que nos permite crear aplicaciones mas confiables y robustas
que se comporte como el usuario espera.  

4. Layouts
Un diseño (Layout) define la estructura de la interfaz de usuario en nuestra aplicación, como, por
ejemplo, en una actividad. Todos los elementos del diseño se crean usando una jerarquía de objetos
View y ViewGroup. Una View suele mostrar un elemento que el usuario puede ver y con el que
puede interactuar. Por su parte, ViewGroup es un contenedor invisible que define la estructura de
diseño de View y otros objetos ViewGroup.

Los objetos View suelen llamarse "widgets" y pueden ser una de las muchas subclases, como Button
o TextView. Los objetos ViewGroup se denominan generalmente "diseños" y pueden ser de muchos
tipos que proporcionan una estructura diferente, como LinearLayout o RelativeLayout. 

Podemos declarar un diseño de dos maneras:

 Declarar elementos de la IU en XML. Android proporciona un vocabulario XML simple que coincide con
las clases y subclases de vistas, como las que se usan para widgets y diseños.
 También puedes utilizar la función Layout Editor de Android Studio para crear tu diseño XML mediante
una interfaz de arrastrar y soltar.

Crear una instancia de elementos de diseño durante el tiempo de ejecución. Nuestra aplicación
puede crear objetos View y ViewGroup (y manipular sus propiedades) de forma programática.

Declarar la IU en XML nos permite separar la presentación de nuestra aplicación del código que
controla su comportamiento. El uso de archivos XML también facilita la creación de diferentes
diseños para diferentes tamaños de pantalla y orientaciones. Este es el método que vamos a utilizar
a lo largo de este curso.

4.1. LinearLayout

Diseño lineal o LinearLayout es un grupo de vista que alinea todos los campos secundarios en una
única dirección, de manera vertical u horizontal. Podemos especificar la dirección del diseño con el
atributo android:orientation.

Todos los campos secundarios de un LinearLayout se apilan uno detrás de otro, por lo cual una lista
vertical solo tendrá un campo secundario por fila, independientemente del ancho que tengan, y una
lista horizontal solo tendrá la altura de una fila (la altura del campo secundario más alto, más el
relleno). Un LinearLayout respeta los márgenes entre los campos secundarios y la gravedad
(alineación a la derecha, centrada o a la izquierda) de cada campo secundario.

Volumen del diseño


LinearLayout también es compatible con la asignación de un volumen a campos secundarios
individuales con el atributo android:layout_weight. Este atributo asigna un valor de "importancia" a
una vista en términos de la cantidad de espacio que debe ocupar en la pantalla. Un valor de volumen
más grande posibilita la expansión para llenar el espacio restante en la vista primaria. Las vistas
secundarias pueden especificar un valor de volumen y, luego, todo espacio restante en la vista del
grupo se asigna a los campos secundarios según la proporción de su volumen declarado. El volumen
predeterminado es cero.
 

Distribución equitativa
Para crear un diseño lineal en el que cada campo secundario use la misma cantidad de espacio en la
pantalla, define el android:layout_height de cada vista en "0dp" (para un diseño vertical) o el
android:layout_width de cada vista en "0dp" (para un diseño horizontal). Luego, fija el
android:layout_weight de cada vista en "1".

Distribución no equitativa
También podemos crear diseños lineales en los que los elementos secundarios utilicen diferentes
cantidades de espacio en la pantalla:

 Si hay tres campos de texto y dos de ellos declaran un volumen igual a 1 mientras al restante no se le
asigna volumen, el tercer campo de texto sin volumen no se expandirá. En cambio, solo ocupará el
área que requiera su contenido. Los otros dos campos de texto, por otro lado, se expandirán de
manera equitativa a fin de llenar el espacio restante después de que se midan los tres campos.
 Si hay tres campos de texto y dos de ellos declaran un volumen de 1 mientras al tercer campo se le
asigna un volumen de 2 (en lugar de 0), entonces ahora se declara más importante que los otros dos,
por lo que obtiene la mitad del espacio total restante, mientras que los dos primeros comparten el resto
por igual.

El siguiente de código muestra cómo podemos utilizar combinaciones de LinearLayout para crear
una interfaz como la que se muestra en la figura 4.1

activity_main.xml

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


<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">
    <TextView
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:background="#2A982F"
        android:layout_weight="2"
        />
    <TextView
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:background="#FF9800"
        android:layout_weight="2"/>
    <TextView
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:background="#3F51B5"
        android:layout_weight="3"/>
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:orientation="horizontal"
        android:layout_weight="3">
        <TextView
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:background="#F44336"
            android:layout_weight="1"/>
        <TextView
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:background="#FFEB3B"
            android:layout_weight="1"/>
        <TextView
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:background="#FF9800"
            android:layout_weight="1"/>
    </LinearLayout>
</LinearLayout>

Figura 4.1: LinearLayout

Ejemplo de creacrion de un esquema lineal (LinearLayout)

4.2. RelativeLayout

El Esquema relativo o RelativeLayout es un grupo de vistas que muestra vistas secundarias en


posiciones relativas. La posición de cada vista puede especificarse como relativa a elementos
equivalentes (como a la izquierda o por debajo de otra vista) o en posiciones relativas al área de
propio contenedor, es decir, del RelativeLayout (como alineada a la parte inferior, izquierda o central
del Relative layout).

RelativeLayout es un elemento muy eficaz para diseñar una interfaz de usuario porque puede
eliminar grupos de vistas anidados y conservar la estabilidad de la jerarquía de diseño, lo que mejora
el rendimiento. Si descubrimos que usamos varios grupos de LinearLayout anidados, podemos
reemplazarlos por un solo RelativeLayout.

Cómo posicionar vistas

RelativeLayout permite que las vistas secundarias especifiquen su posición relativa a la vista
superior o entre sí (especificada por ID). De esta manera, podemos alinear dos elementos por el
borde derecho o hacer que uno esté por debajo del otro, en el centro de la pantalla, en el centro a la
izquierda, y así sucesivamente. De manera predeterminada, todas las vistas secundarias se dibujan
en la esquina superior izquierda del diseño, por lo que debemoss definir la posición de cada una de
las vistas utilizando las diversas propiedades de diseño disponibles del  RelativeLayout.
 Entre algunas de las muchas propiedades de diseño disponibles para las vistas de un grupo
RelativeLayout, se incluyen las siguientes:
 android:layout_alignParentTop: Si el valor es "true", el borde superior de esta vista coincidirá con el del
elemento superior.
 android:layout_alignParentBottom: Si el valor es "true", el borde inferior de esta vista coincidirá con el
del elemento inferior.
 android:layout_alignParentLeft: Si el valor es "true", el borde izquierdo de esta vista coincidirá con el
del elemento izquierdo.
 android:layout_alignParentRight: Si el valor es "true", el borde derecho de esta vista coincidirá con el
del elemento derecho.
 android:layout_below: Posiciona el borde superior de esta vista debajo de la vista especificada con un
ID de recurso.
 android:layout_above: Posiciona el borde inferior de esta vista encima de la vista especificada con un
ID de recurso.
 android:layout_toRightOf: Posiciona el borde izquierdo de esta vista a la derecha de la vista
especificada con un ID de recurso.
 android:layout_toLeftOf: Posiciona el borde derecho de esta vista a la izquierda de la vista especificada
con un ID de recurso.

Estos son solo algunos ejemplos. Todos los atributos de diseño están documentados
en: https://developer.android.com/reference/android/widget/RelativeLayout.LayoutParams

El valor de cada propiedad de diseño es un valor booleano que habilita una posición de diseño
relativa al elemento RelativeLayout principal o un ID que hace referencia a otra vista en el diseño en
el que se debe posicionar la vista.

Veamos un pequeño ejemplo en donde ubiquemos algunas vistas en relación otras y a su


contenedor.

activity_main.xml

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


<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <TextView
        android:id="@+id/primer_texto"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
     android:text="Primer texto"
        android:layout_alignParentLeft="true"
        android:layout_alignParentTop="true"
        android:background="#CDDC39"/>
    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
     android:text="Segundo texto"
        android:layout_alignParentRight="true"
        android:background="#00BCD4"/>
    <TextView
        android:id="@+id/tercer_texto"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Tercer texto"
        android:layout_alignParentBottom="true"
        android:layout_alignParentRight="true"
        android:background="#EA9F1E"/>
 <TextView
        android:id="@+id/cuarto_texto"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
     android:text="Cuarto texto"
        android:layout_alignParentBottom="true"
        android:layout_alignParentLeft="true"
        android:background="#EA3D1E"/>
 <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Quinto texto"
        android:layout_below="@id/primer_texto"
        android:layout_above="@id/cuarto_texto"
        android:layout_alignParentRight="true"
     android:layout_alignParentLeft="true"
        android:background="#3FA3B5"/>
    <TextView
        android:layout_width="wrap_content"
     android:layout_height="wrap_content"
        android:text="Sexto texto"
        android:layout_alignParentBottom="true"
        android:layout_toRightOf="@id/cuarto_texto"
        android:layout_toLeftOf="@id/tercer_texto"
     android:background="#BDD85C"/>
</RelativeLayout>
La interfaz resultante es la que se puede apreciar en la figura 4.2

Figura 4.2: Esquema Relativo (RelativeLayout)

Ejemplo de creacrion de un esquema relativo (RelativeLayout)

4.3. ScrollView

En ocasiones el contenido de nuestras activity puede exceder el tamaño de la pantalla de nuestro


dispositivo. En estos casos debemos agregar un ScrollView

Un ScrollView es un ViewGroup que permite desplazarse por la jerarquía de vistas ubicada dentro de
él. ScrollView puede tener solo un hijo directo colocado dentro de él. Para agregar varias vistas
dentro de la vista de desplazamiento, haga que el hijo directo que agrega sea un ViewGroup, por
ejemplo, LinearLayout, y coloque vistas adicionales dentro de ese LinearLayout. Tal como se
muestra en el siguiente ejemplo:

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


<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
   
<LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical">
        <TextView
            android:layout_width="match_parent"
            android:layout_height="70dp"
            android:text="Esto es una Prueba"
            android:textAlignment="center"
            android:textSize="30sp"
            android:background="#2DF3E2"/>
<TextView
            android:layout_width="match_parent"
            android:layout_height="70dp"
            android:text="Esto es otra Prueba"
            android:textAlignment="center"
            android:textSize="30sp"
            android:background="#FFA682"/>
        <TextView
            android:layout_width="match_parent"
            android:layout_height="70dp"
            android:text="Esto es una Prueba"
             android:textAlignment="center"
            android:textSize="30sp"
            android:background="#2DF3E2"/>
        <TextView
            android:layout_width="match_parent"
            android:layout_height="70dp"
            android:text="Esto es otra Prueba"
            android:textAlignment="center"
            android:textSize="30sp"
            android:background="#FFA682"/>
        <TextView
            android:layout_width="match_parent"
            android:layout_height="70dp"
            android:text="Esto es una Prueba"
            android:textAlignment="center"
            android:textSize="30sp"
            android:background="#2DF3E2"/>
        <TextView
            android:layout_width="match_parent"
            android:layout_height="70dp"
            android:text="Esto es otra Prueba"
            android:textAlignment="center"
            android:textSize="30sp"
            android:background="#FFA682"/>
    </LinearLayout>
</ScrollView>
 

Nunca agregue un RecyclerView o ListView a una vista de desplazamiento. Hacerlo da como


resultado un rendimiento deficiente de la interfaz de usuario y una experiencia de usuario deficiente.

 Vistas Comunes
En este capítulo estudiaremos algunas de las vistas típicas que veremos en aplicaciones Android
como, por ejemplo, etiquetas (TextView), cajas de texto (EditText), Imágenes (ImageView), etc.

5.1. View

Esta clase representa el bloque de construcción básico para los componentes de la interfaz de
usuario (UI). Una vista (View) ocupa un área rectangular en la pantalla y es responsable del dibujo y
el manejo de eventos. View es la clase base para los widgets, que se utilizan para crear
componentes de interfaz de usuario interactivos (botones, campos de texto, etc.). La subclase
ViewGroup es la clase base para diseños, que son contenedores invisibles que contienen otras
Vistas (u otros ViewGroups) y definen sus propiedades de diseño.

Todas las vistas de una ventana están organizadas en un solo árbol. Puede agregar vistas desde el
código o especificando un árbol de vistas en uno o más archivos de diseño XML. Hay muchas
subclases especializadas de vistas que actúan como controles o son capaces de mostrar texto,
imágenes u otro contenido.

Una vez que haya creado un árbol de vistas, normalmente existen algunos tipos de operaciones
comunes que puede desear realizar:

 Establecer propiedades: por ejemplo, establecer el texto de un TextView. Las propiedades


disponibles y los métodos que las establecen variarán entre las diferentes subclases de vistas.
Tenga en cuenta que las propiedades que se conocen en el momento de la compilación se
pueden establecer en los archivos de diseño XML.
 Establecer el foco: el marco manejará el foco en movimiento en respuesta a la entrada del
usuario. Para forzar el foco a una vista específica, llame a requestFocus().
 Configurar listeners: las vistas nos permiten configurar listeners(clases encargadas de
escuchar y manejar los eventos) que serán notificados cuando algo interesante le suceda a la
vista. Por ejemplo, todas las vistas le permitirán configurar un para recibir una notificación
cuando la vista gane o pierda el foco. Otras subclases de vista ofrecen oyentes más
especializados. Por ejemplo, un botón proporciona un listener para notificar a los clientes
cuando se hace clic en el botón.
 Establecer visibilidad: puede ocultar o mostrar vistas usando setVisibility (int).

5.2. TextView

El TextView es un elemento de la interfaz de usuario que muestra texto al usuario. El siguiente


ejemplo de código muestra un uso típico, con un diseño XML y código para modificar el contenido de
la vista de texto:

<LinearLayout
 xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <TextView
        android:id="@+id/text_view_id"
        android:layout_height="wrap_content"
        android:layout_width="wrap_content"
        android:text="@string/hello"/>
</LinearLayout>
Este ejemplo de código demuestra cómo modificar el contenido de la vista de texto definida en el
diseño XML anterior:

public class MainActivity extends Activity {


    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
final TextView helloTextView = (TextView) findViewById(R.id. text_view_id);
        helloTextView.setText(R.string.user_greeting);
    }
}
5.3. EditText

El EditText es un elemento de interfaz de usuario para ingresar y modificar texto. Cuando define un
widget de edición de texto, debe especificar el atributo R.styleable.TextView_inputType. Por ejemplo,
para la entrada de texto sin formato, establezca inputType en "text":

<EditText
    android:id="@+id/plain_text_input"
    android:layout_height="wrap_content"
    android:layout_width="match_parent"
    android:inputType="text"/>

La elección del tipo de entrada configura el tipo de teclado que se muestra, los caracteres aceptables
y la apariencia del texto de edición. Por ejemplo, si desea aceptar un número secreto, como un pin
único o un número de serie, puede establecer inputType en "numericPassword". Un inputType de
"numericPassword" da como resultado un texto de edición que solo acepta números, muestra un
teclado numérico cuando está enfocado y enmascara el texto que se ingresa para privacidad.

5.4. ImageView

Muestra recursos de imágenes, por ejemplo, Bitmap o recursos Drawable. ImageView también se
usa comúnmente para aplicar tintes a una imagen y manejar la escala de la imagen. El siguiente
fragmento XML es un ejemplo común del uso de ImageView para mostrar un recurso de imagen:

<ImageView
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:src="@drawable/my_image"
    android:contentDescription="@string/my_image_description"/>

6. Botones
En este capitulo vamos a revisar algunos de los diferentes tipos de botones que Android proporciona
para construir nuestros tipos de interfaces. Primero revisaremos los botones típicos o push buttons
(botones que el usuario presiona y de inmediato realizan una acción estos son Button e
ImageButton). Luego revisaremos los botones de estado, es decir botones que realizan una acción
en función del estado al que el usuario lo cambia: Checkbox, RadioButton y Switch

6.1. Button

Un botón es un elemento de la UI que consta de texto o un ícono (o ambos, tanto texto como un
ícono) que comunica qué acción ocurre cuando el usuario lo toca (hace click).

Dependiendo de si desea un botón con texto, un icono o ambos, puede crear el botón en su diseño
de tres formas:

 Con texto, usando la clase Button.


 Con texto, usando la clase Button.
 Con texto y un ícono, usando la clase Button con el atributo android: drawableLeft.

Con texto, usando la clase Button:

<Button
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="@string/button_text"
    ... />
 

Con texto, usando la clase Button:

<ImageButton
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:src="@drawable/button_icon"
    android:contentDescription="@string/button_icon_desc"
    ... />
Con texto y un ícono, usando la clase Button con el atributo android: drawableLeft:

<Button
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="@string/button_text"
    android:drawableLeft="@drawable/button_icon"
    ... />
Responder a eventos de clic
Cuando el usuario hace clic en un botón, el objeto Botón recibe un evento al hacer clic. Para definir
el controlador de eventos de clic para un botón, agregue el atributo android: onClick al elemento
<Button> en su diseño XML. El valor de este atributo debe ser el nombre del método al que desea
llamar en respuesta a un evento de clic. La actividad que aloja el diseño debe implementar el método
correspondiente. Por ejemplo, aquí hay un diseño con un botón que usa android: onClick:

<Button
    android:id="@+id/btn_enviar"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="@string/boton_enviar"
   
android:onClick="enviarMensaje" />
 

Dentro de la actividad que aloja este diseño, el siguiente método maneja el evento de clic:

/** llamado cuando el usuario toca el boton */


public void enviarMensaje(View view) {
    // hacer algo en respuesta al click del boton
}
El método que declare en el atributo android:onClick debe tener una firma exactamente como se
muestra arriba. Específicamente, el método debe:

 Debe ser público(public)


 No debe devolver valor, es decir debe ser retorno void
 Definir un objeto de tipo View como su único parámetro (esta será la vista (View) en la que se hizo clic)

Usando un OnClickListener
También puede declarar el controlador de eventos de clic mediante programación en lugar de en un
diseño XML. Esto puede ser necesario si crea una instancia de la clase Button en tiempo de
ejecución o si necesita declarar el comportamiento del clic en una subclase de Fragment.

Para declarar el controlador de eventos mediante programación, cree un objeto View.OnClickListener


y asígnelo al botón llamando a setOnClickListener(View.OnClickListener). Por ejemplo:

Button button = findViewById(R.id.btn_enviar);


button.setOnClickListener(new View.OnClickListener() {
    public void onClick(View v) {
        // hacer algo en respuesta al click del boton
    }
});
  

Ejemplo de uso de botones en android

6.2. CheckBox

Las casillas de verificación (CheckBox) permiten al usuario seleccionar una o más opciones de un
conjunto. Por lo general, debe presentar cada opción de casilla de verificación en una lista vertical.

Para crear cada opción de casilla de verificación (CheckBox), creamos una casilla de verificación en
su diseño. Debido a que un conjunto de opciones de casilla de verificación permite al usuario
seleccionar varios elementos, cada casilla de verificación se administra por separado y debe registrar
un Listener de click para cada uno.

Responder a eventos de clic del CheckBox


Cuando el usuario selecciona una casilla de verificación, el objeto CheckBox recibe un evento al
hacer clic.Para definir el controlador de eventos de clic para una casilla de verificación, agregue el
atributo android: onClick al elemento <CheckBox> en su diseño XML. El valor de este atributo debe
ser el nombre del método al que desea llamar en respuesta a un evento de clic. La actividad que
aloja el diseño debe implementar el método correspondiente. Aquí hay un objeto CheckBox de
ejemplo:

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


<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent">
    <CheckBox android:id="@+id/chk_activo"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
     android:text="Activo"
        android:onClick="marcar"/>
</LinearLayout>
Dentro de la actividad que aloja este diseño, el siguiente método maneja el evento de clic para este
CheckBox:

public void marcar(View view) {


    // ¿Está marcada la vista?
    boolean marcado = ((CheckBox) view).isChecked();
    if(marcado){
        hacer algo si está marcado
    } else {
        // hacer otra cosa si no está marcado
    }
}
El método que declare en el atributo android:onClick debe tener una firma exactamente como se
muestra arriba. Específicamente, el método debe:

 Debe ser público(public)


 No debe devolver valor, es decir debe ser retorno void
 Definir un objeto de tipo View como su único parámetro (esta será la vista (View) en la que se hizo clic)

Ejemplo de uso de CheckBoxes en android

6.3. RadioButton

Los RadioButtons (También llamados botones de opción) permiten al usuario seleccionar una opción
de un conjunto. Debe usar botones de opción para conjuntos opcionales que se excluyan
mutuamente. Al crear una lista de opciones utilizando RadioButton debemos agruparlos dentro de un
RadioGroup. Al agruparlos, el sistema garantiza que solo se pueda seleccionar un botón de opción a
la vez:

<RadioGroup xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="vertical">
    <RadioButton android:id="@+id/radio_rojo"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/rojo"
        android:onClick="marcar"/>
    <RadioButton android:id="@+id/radio_verde"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/verde"
        android:onClick="marcar"/>
</RadioGroup>
 

Cuando el usuario selecciona uno de los botones de opción, el objeto RadioButton correspondiente
recibe un evento al hacer clic.

Para definir el controlador de eventos de clic para un botón, agregue el atributo android:onClick al
elemento <RadioButton> en su diseño XML. El valor de este atributo debe ser el nombre del método
al que desea llamar en respuesta a un evento de clic. La actividad que aloja el diseño debe
implementar el método correspondiente.

public void marcar(View view) {


    // ¿está el boton marcado?
    boolean checked = ((RadioButton) view).isChecked();
    // Verificar cual es el boton marcado
    switch(view.getId()) {
        case R.id.radio_rojo:
            if (checked)
                // hacer algo si es el rojo
                break;        
case R.id.radio_verde:
            if (checked)
                // hacer algo si es el verde
                break;
}
}
 

El método que declare en el atributo android:onClick debe tener una firma exactamente como se
muestra arriba. Específicamente, el método debe:

 Debe ser público(public)


 No debe devolver valor, es decir debe ser retorno void
 Definir un objeto de tipo View como su único parámetro (esta será la vista (View) en la que se hizo clic)

Ejemplo de uso de RadioButton

6.4. Switch

Un Switch es un widget que nos permite cambiar entre dos estados. El usuario puede arrastrar el
"pulgar" hacia adelante y hacia atrás para elegir la opción seleccionada, o simplemente tocar para
alternar como si fuera una casilla de verificación (CheckBox). La propiedad de texto controla el texto
que se muestra en la etiqueta del interruptor, mientras que el texto de apagado y encendido controla
el texto en el pulgar. De manera similar, los métodos textAppearance y setTypeface () relacionados
controlan el tipo de letra y el estilo del texto de la etiqueta, mientras que los métodos
switchTextAppearance y setSwitchTypeface () relacionados controlan el del pulgar.
Para detectar cuándo el usuario activa el switch, cree y asigne un objeto tipo
CompoundButton.OnCheckedChangeListener al método setOnCheckedChangeListener (). Por
ejemplo:

Switch sw =
findViewById(R.id.interruptor);
sw.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
    @Override
    public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
        if (isChecked) {
         // hacer algo si esta activado
        } else {
// hacer algo sino esta activado
        }
    }
});
7. Intents
Un Intent es un objeto de mensajería que puedes usar para solicitar una acción de otro componente
de una aplicación. Si bien los intents facilitan la comunicación entre componentes de varias formas,
existen tres casos de uso principales:

 Iniciar una actividad

Una Activity representa una única pantalla en una aplicación. Puedes iniciar una nueva
instancia de una Activity pasando un Intent a startActivity(). El Intent describe la actividad que
se debe iniciar y contiene los datos necesarios para ello. Si deseas recibir un resultado de la
actividad cuando finalice, llama a startActivityForResult(). La actividad recibe el resultado
como un objeto Intent separado en la devolución de llamada de onActivityResult() de la
actividad.
 Iniciar un servicio

Un Service es un componente que realiza operaciones en segundo plano sin una interfaz de
usuario. Con Android 5.0 (nivel de API 21) y versiones posteriores, puedes iniciar un servicio
con JobScheduler. En las versiones anteriores a Android 5.0 (nivel de API 21), puedes iniciar
un servicio usando métodos de la clase Service. Puedes iniciar un servicio para realizar una
operación única (como descargar un archivo) pasando un Intent a startService(). El Intent
describe el servicio que se debe iniciar y contiene los datos necesarios para ello. Si el servicio
está diseñado con una interfaz cliente-servidor, podemos establecer un enlace con el servicio
de otro componente pasando un Intent a bindService().
 Transmitiruna emisión

Una emisión es un aviso que cualquier aplicación puede recibir. El sistema transmite varias
emisiones de eventos, como cuando se inicia el sistema o comienza a cargarse el dispositivo.
Puedes transmitir una emisión a otras apps pasando una Intent a sendBroadcast() o
sendOrderedBroadcast().

El resto de esta página explica cómo funcionan las intents y cómo debes usarlas. Para
obtener información relacionada, consulta Cómo actualizar con otras aplicaciones y Cómo
compartir contenido.
7.1. Tipos de intents

Existen dos tipos de intents:

 Las intents explícitas especifican qué aplicación las administrará, ya sea incluyendo el


nombre del paquete de la aplicación de destino o el nombre de clase del componente
completamente calificado. Normalmente, el usuario usa una intent explícita para iniciar un
componente en su propia aplicación porque conoce el nombre de clase de la actividad o el
servicio que desea iniciar. Por ejemplo, puedes utilizarla para iniciar una actividad nueva en
respuesta a una acción del usuario o iniciar un servicio para descargar un archivo en segundo
plano.
 Las intents implícitas no nombran el componente específico, pero, en cambio, declaran una
acción general para realizar, lo cual permite que un componente de otra aplicación la maneje.
Por ejemplo, si deseas mostrar al usuario una ubicación en un mapa, puedes usar una intent
implícita para solicitar que otra aplicación apta muestre una ubicación específica en un mapa.
Cuando usas una intent implícita, el sistema Android busca el componente apropiado para
iniciar comparando el contenido de la intent con los filtros de intents declarados en el archivo
de manifiesto de otras aplicaciones en el dispositivo. Si la intent coincide con un filtro de
intents, el sistema inicia ese componente y le entrega el objeto Intent. Si varios filtros de
intents son compatibles, el sistema muestra un cuadro de diálogo para que el usuario pueda
elegir la aplicación que se debe usar.

Un filtro de intents es una expresión en el archivo de manifiesto de una aplicación que especifica el
tipo de intent que el componente podría recibir. Por ejemplo, declarar un filtro de intents para una
actividad permite que otras aplicaciones la inicien directamente con un tipo de intent específico.
Asimismo, si no declaras ningún filtro de intent para una actividad, esta solo se puede iniciar con una
intent explícita.

7.2. Cómo crear una intent

Un objeto Intent tiene información que el sistema Android usa para determinar qué componente debe
iniciar (como el nombre exacto del componente o la categoría que debe recibir la intent), además de
información que el componente receptor usa para realizar la acción correctamente (por ejemplo, la
acción que debe efectuar y los datos en los que debe actuar).

La información principal que contiene una Intent es la siguiente:

Nombre del componente

El nombre del componente que se debe iniciar.

Esto es opcional, pero es la información clave que hace que una intent sea explícita, lo que significa
que la intent debe enviarse solamente al componente de la aplicación definido en el nombre del
componente. Sin un nombre de componente, la intent es implícita y el sistema decide qué
componente debe recibir la intent conforme la información restante que esta contiene (como la
acción, los datos y la categoría, que se describen a continuación). Por lo tanto, si necesitas iniciar un
componente específico en tu aplicación, debes especificar el nombre del componente.

Este campo de la Intent es un objeto ComponentName que puedes especificar con un nombre de
clase completamente calificado del componente de destino, incluido el nombre del paquete de la
aplicación, como com.example.ExampleActivity. Puedes establecer el nombre del componente con
setComponent(), setClass(), setClassName() o el constructor Intent.

Acción

Una string que especifica la acción genérica que se debe realizar (como ver o elegir).

En el caso de la intent de una emisión, es la acción que se produjo y que se está registrando. La
acción determina cuál es la estructura del resto de la intent, especialmente la información que se
incluye en los datos y extras.

Puedes especificar tus propias acciones para que las usen las intents en tu aplicación (o para que
las usen otras aplicaciones a fin de invocar componentes en tu aplicación); pero, usualmente, debes
especificar acciones constantes definidas por la clase Intent u otras clases de marcos de trabajo.
Estas son algunas acciones comunes para iniciar una actividad:

 ACTION_VIEW: Usa esta acción en una intent con startActivity() cuando tengas información
que la actividad pueda mostrar al usuario, como una foto para ver en una app de galería o una
dirección para ver en una app de mapas.
 ACTION_SEND: También se conoce como la intent de compartir y debes usarla en una intent
con startActivity() cuando tengas información que el usuario pueda compartir mediante otra
app, como una app de correo electrónico o intercambio social.

Consulta la referencia de la clase Intent para conocer más constantes que definen las acciones
genéricas. Otras acciones se definen en otras partes del marco de trabajo de Android, como en
Settings para las acciones que abren pantallas específicas en la aplicación de Configuración del
sistema.

Podemos especificar la acción de una intent con setAction() o un constructor Intent.

Datos

El URI (un objeto Uri) que hace referencia a los datos en los que se debe realizar la acción o el tipo
de MIME de esos datos. El tipo de datos suministrado está generalmente determinado por la acción
de la intent. Por ejemplo, si la acción es ACTION_EDIT, los datos deben contener el URI del
documento que se debe editar.

Cuando creas una intent, es importante especificar el tipo de datos (su tipo de MIME) además de su
URI. Por ejemplo, una actividad que puede mostrar imágenes probablemente no sea capaz de
reproducir un archivo de audio aunque los formatos de URI sean similares. Especificar el tipo de
MIME de tus datos ayuda al sistema Android a encontrar el mejor componente para recibir tu intent.
Sin embargo, el tipo de MIME a veces se puede deducir del URI, especialmente cuando los datos
son un URI content:. Un URI content: indica que los datos se encuentran en el dispositivo y son
controlados por un ContentProvider, lo que hace que el sistema pueda ver el tipo de datos de MIME.

Para establecer solamente el URI de datos, llama a setData(). Para establecer solo el tipo de MIME,
llama a setType(). Si es necesario, puedes establecer ambos explícitamente con setDataAndType().

Categoría

Una string que contiene información adicional sobre el tipo de componente que la intent debe
manejar. En una intent, se puede incluir la cantidad deseada de descripciones de categorías, pero la
mayoría de las intents no requieren una categoría. Estas son algunas categorías comunes:

 CATEGORY_BROWSABLE: La actividad de destino permite que la inicie un navegador web


para mostrar datos a los que hace referencia un vínculo, como una imagen o un mensaje de
correo electrónico.
 CATEGORY_LAUNCHER: La actividad es la actividad inicial de una tarea y está enumerada
en el selector de la aplicación del sistema.

También puedes especificar una categoría con addCategory(). 

Las propiedades nombradas anteriormente (nombre de componente, acción, datos y categoría)


representan las características definitorias de una intent. Mediante la lectura de estas propiedades, el
sistema Android puede resolver qué componente de la aplicación debe iniciar. Sin embargo, una
intent puede tener información adicional que no afecte cómo se resuelve en un componente de la
aplicación. Una intent también puede incluir la siguiente información:

Extras

Pares clave-valor que contienen información adicional necesaria para completar la acción solicitada.
Al igual que algunas acciones usan tipos particulares de URI de datos, algunas acciones también
usan extras específicos.

Puedes agregar datos adicionales con varios métodos putExtra(), cada uno de los cuales acepta dos
parámetros: el nombre de la clave y el valor. También puedes crear un objeto Bundle con los datos
adicionales y, luego, insertar el Bundle en la Intent con putExtras().

Por ejemplo, al crear una intent para enviar un correo electrónico con ACTION_SEND, puedes
especificar el destinatario para con la clave EXTRA_EMAIL y el asunto con la clave
EXTRA_SUBJECT.

Indicadores

Los indicadores se definen en la clase Intent que funciona como metadatos de la intent. Los
indicadores pueden indicar al sistema Android cómo iniciar una actividad (por ejemplo, a qué tarea
debe pertenecer) y cómo tratarla después de que se inicia (por ejemplo, si pertenece a la lista de
actividades recientes).

7.3. Ejemplo de una intent implícita

Una intent implícita especifica una acción que puede invocar cualquier aplicación en el dispositivo
que puede realizar la acción. El uso de una intent implícita es útil cuando la aplicación no puede
realizar la acción, pero otras aplicaciones probablemente sí, y quieres que el usuario elija qué
aplicación usar. 

Por ejemplo, si tienes contenido que quieres que el usuario comparta con otras personas, crea una
intent con la acción ACTION_SEND y agrega extras que especifiquen el contenido para compartir.
Cuando llamas a startActivity() con esa intent, el usuario puede elegir una aplicación mediante la cual
compartir el contenido.

7.4. Ejemplo de una intent explícita

Una intent explícita es una intent que se usa para iniciar un componente específico de la aplicación,
como una actividad o un servicio particular en la aplicación. Para crear una intent explícita, define el
nombre de componente del objeto Intent (todas las otras propiedades de la intent son opcionales).

Intent Explícita - Enviando datos:

También podría gustarte