Beruflich Dokumente
Kultur Dokumente
Para aprender cómo funcionan las apps, comienza con Aspectos fundamentales
de apps.
Desde un componente puedes iniciar otro componente con una intent. Incluso
puedes iniciar un componente en otra app, como una actividad en una app de
mapas para mostrar una dirección. Este modelo proporciona varios puntos de
entrada para una app y permite que cualquier app se comporte como
“predeterminada” de un usuario para una acción que otras apps pueden invocar.
Sin embargo, hay maneras en las que una aplicación puede compartir datos con
otras aplicaciones y en las que una aplicación puede acceder a servicios del
sistema:
Esto cubre los aspectos básicos sobre cómo una aplicación de Android existe en
el sistema. El resto de este documento te presenta lo siguiente:
Componentes de la aplicación
Hay cuatro tipos diferentes de componentes de una aplicación. Cada tipo tiene un
fin específico y un ciclo de vida diferente que define cómo se crea y se destruye el
componente.
Actividades
Una actividad representa una pantalla con interfaz de usuario. Por ejemplo, una
aplicación de correo electrónico tiene una actividad que muestra una lista de los
correos electrónicos nuevos, otra actividad para redactar el correo electrónico y
otra actividad para leer correos electrónicos. Si bien las actividades trabajan juntas
para proporcionar una experiencia de usuario consistente en la aplicación de
correo electrónico, cada una es independiente de las demás. De esta manera, una
aplicación diferente puede inicial cualquiera de estas actividades (si la aplicación
de correo electrónico lo permite). Por ejemplo, una aplicación de cámara puede
iniciar la actividad en la aplicación de correo electrónico que redacta el nuevo
mensaje para que el usuario comparta una imagen.
Proveedores de contenido
Los proveedores de contenido también son útiles para leer y escribir datos
privados de tu aplicación y que no se comparten. Por ejemplo, la aplicación
de ejemplo Bloc de notas usa un proveedor de contenido para guardar
notas.
Receptores de mensajes
Un aspecto exclusivo del diseño del sistema Android es que cualquier aplicación
puede iniciar un componente de otra aplicación. Por ejemplo, si quieres que el
usuario tome una foto con la cámara del dispositivo, probablemente haya otra
aplicación para eso y tu aplicación pueda usarla, en lugar de desarrollar una
actividad para tomar una foto. No necesitas incorporar ni establecer un enlace con
el código de la aplicación de cámara. En su lugar, puedes simplemente iniciar la
actividad en la aplicación de cámara que toma la foto. Cuando termines, la foto
aparecerá en tu aplicación para que puedas usarla. Al usuario le parecerá que la
cámara en realidad forma parte de tu aplicación.
Cuando el sistema inicia un componente, inicia el proceso para esa aplicación (si
es que no se está ejecutando) y crea una instancia de las clases necesarias para
el componente. Por ejemplo, si tu app inicia la actividad en la app de cámara que
toma una foto, esa actividad se ejecuta en el proceso que pertenece a la app de
cámara, no en el proceso de tu app. Por lo tanto, a diferencia de lo que sucede
con las apps en la mayoría de los demás sistemas, las apps de Android no tienen
un solo punto de entrada (por ejemplo, no existe la función main()).
Activación de componentes
Tres de los cuatro tipos de componentes (actividades, servicios y receptores de
mensajes) se activan mediante un mensaje asincrónico llamado intent. Las intents
enlazan componentes individuales en tiempo de ejecución (son como mensajeros
que solicitan una acción de otros componentes), ya sea que el componente le
pertenezca a tu aplicación o a otra.
Una intent se crea con un objeto Intent, que define un mensaje para activar un
componente específico o un tipoespecífico de componente; una intent puede ser
explícita o implícita, respectivamente.
Para actividades y servicios, una intent define la acción a realizar (por ejemplo,
"ver" o "enviar" algo) y puede especificar el URI de los datos en los que debe
actuar (entre otras cosas que el componente que se está iniciando podría
necesitar saber). Por ejemplo, una intent podría transmitir una solicitud para que
una actividad muestre una imagen o abra una página web. En algunos casos,
puedes iniciar una actividad para recibir un resultado; en cuyo caso, la actividad
también devuelve el resultado en una Intent (por ejemplo, puedes emitir una
intent para que el usuario elija un contacto personal y te lo devuelva; la intent de
devolución incluye un URI que apunta al contacto seleccionado).
Puedes iniciar una actividad (o asignarle algo nuevo para hacer) al pasar
una Intent a startActivity()o startActivityForResult() (cuando quieras
que la actividad devuelva un resultado).
Puedes iniciar un servicio (o darle instrucciones nuevas a un servicio en curso) al pasar
una Intent a startService(). O puedes establecer un enlace con el servicio al pasar
una Intent a bindService().
Puedes iniciar la transmisión de un mensaje pasando una Intent a métodos
como sendBroadcast(), sendOrderedBroadcast(), o sendStickyBroadcast().
Puedes realizar una consulta a un proveedor de contenido llamando a query() en
un ContentResolver.
Identificar los permisos de usuario que requiere la aplicación, como acceso a Internet o
acceso de lectura para los contactos del usuario.
Declarar el nivel de API mínimo requerido por la aplicación en función de las API que usa
la aplicación.
Declarar características de hardware y software que la aplicación usa o exige, como una
cámara, servicios de bluetooth o una pantalla multitáctil.
Bibliotecas de la API a las que la aplicación necesita estar vinculada (además de las
Android framework API), como la biblioteca Google Maps .
Y más.
Declaración de componentes
La tarea principal del manifiesto es informarle al sistema acerca de los
componentes de la aplicación. Por ejemplo, un archivo de manifiesto puede
declarar una actividad de la siguiente manera:
Por ejemplo, si compilaste una aplicación de correo electrónico con una actividad
para redactar un nuevo mensaje de correo electrónico, puedes declarar un filtro de
intents para responder a las intents "enviar" (a fin de enviar un nuevo correo
electrónico) de esta manera:
Para obtener más información acerca de cómo crear filtros de intents, lee el
documento Intents y filtros de intents.
Recursos de la aplicación
En Android, una aplicación está compuesta por más que simplemente código;
requiere recursos independientes del código fuente, como imágenes, archivos de
audio y otros elementos relacionados con la presentación de la aplicación. Por
ejemplo, debes definir animaciones, menús, estilos, colores y el diseño de las
interfaces de usuario de la actividad con archivos XML. El uso de recursos de la
aplicación facilita la actualización de varias características de tu aplicación sin
necesidad de modificar el código y, al proporcionar conjuntos de recursos
alternativos, puedes optimizar tu aplicación para una variedad de configuraciones
de dispositivos (como diferentes idiomas y tamaños de pantalla).
Por cada recurso que incluyes en tu proyecto para Android, las herramientas de
compilación del SDK definen un ID con número entero que puedes usar para
hacer referencia al recurso desde el código de tu aplicación o desde otros
recursos definidos en XML. Por ejemplo, si tu app contiene un archivo de imagen
denominado logo.png(guardado en el directorio res/drawable/), las
herramientas del SDK generan un ID de recurso llamado R.drawable.logo que
puedes usar para hacer referencia a la imagen e insertarla en tu interfaz de
usuario.
Para obtener más información acerca de los diferentes tipos de recursos que
puedes incluir en tu aplicación y cómo crear recursos alternativos para diferentes
configuraciones de dispositivos, lee Provisión de recursos.
Continúa leyendo:
Información acerca de cómo usar las Intent API para activar componentes de la
aplicación, como actividades y servicios, y cómo hacer para que los componentes
de tu aplicación estén disponibles para que los usen otras apps.
Actividades
Provisión de recursos
Tipos de intents
Intents explícitas: especifican qué componente se debe iniciar mediante su nombre (el
nombre de clase completamente calificado). Usualmente, 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, puede 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.
Intents implícitas: no se nombra el componente específicamente; pero, en cambio, se
declara una acción general para realizar, lo que permite que un componente de otra
aplicación la maneje. Por ejemplo, si desea mostrar al usuario una ubicación en un mapa,
puede usar una intent implícita para solicitar que otra aplicación capaz muestre una
ubicación específica en un mapa.
Cuando crea una intent explícita para iniciar una actividad o un servicio, la
aplicación inicia inmediatamente el componente de la aplicación especificado en el
objeto Intent.
Figura 1: Ilustración de la forma en que se entrega una intent implícita mediante el sistema
para iniciar otra actividad. [1]La actividad A crea una Intent con una descripción de acción y
la pasa a startActivity(). [2] El sistema Android busca en todas las apps un filtro de
intents que coincida con la intent. Cuando se encuentra una coincidencia, [3] el sistema inicia
la actividad coincidente (actividad B) invocando su método onCreate() y pasándolo a
la Intent.
Advertencia: Para garantizar que su aplicación sea segura, siempre use una intent explícita
cuando inicie un Service y no declare filtros de intents para los servicios. El uso de una intent
implícita para iniciar un servicio es un riesgo de seguridad porque no puede estar seguro de
qué servicio responderá a la intent, y el usuario no puede ver qué servicio se inicia. A partir de
Android 5.0 (nivel de API 21), el sistema arroja una excepción si llama a bindService() con
una intent implícita.
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 del componente 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).
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 que si necesita iniciar un componente específico en su
aplicación, debe espceificar el nombre del componente.
Acción
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 usar acciones
constantes definidas por la clase Intent u otras clases del framework.
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 puede mostrar al usuario, como una foto para ver en una app de
galería o una dirección para ver en una app de mapa.
ACTION_SEND
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 se crea una intent, suele ser importante especificar el tipo de datos
(su tipo de MIME), además del URI. Por ejemplo, una actividad que puede
mostrar imágenes, probablemente no podrá reproducir un archivo de video,
aunque los formatos del URI podrían ser similares. Por lo tanto, especificar
el tipo de MIME de tus datos ayuda al sistema Android a encontrar el mejor
componente para recibir la intent. No obstante, el tipo de MIME puede, a
veces, inferirse del URI, en especial cuando los datos representan un
URIcontent:. Esto indica que los datos están en el dispositivo y los
controla un ContentProvider; esto hace que el tipo de MIME sea visible
para el sistema.
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
Sin embargo, una intent puede tener información adicional que no afecta cómo se
resuelve en un componente de la aplicación. Una intent también puede incluir lo
siguiente:
Extras
Pares de valores clave que tienen información adicional necesaria para lograr la
acción solicitada. Al igual que algunas acciones usan tipos particulares de URI de
los datos, algunas acciones también usan extras particulares.
Indicadores
Por ejemplo, si tiene contenido que deseas 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 llama astartActivity() con
esa intent, el usuario puede elegir una aplicación mediante la cual compartir el
contenido.
Advertencia: Es posible que un usuario no tenga ninguna aplicación para manejar la intent
implícita que tu envías a startActivity(). Si esto sucede, la llamada fallará y la aplicación
colapsará. Para verificar que una actividad recibirá la intent, llama a resolveActivity() en el
objeto Intent. Si el resultado no es nulo, hay, al menos, una aplicación que puede manejar la
intent y es seguro llamar astartActivity(). Si el resultado es nulo, no debes usar la intent y,
si es posible, debes inhabilitar la característica que emite la intent.
// Create the text message with a string
Intent sendIntent = new Intent();
sendIntent.setAction(Intent.ACTION_SEND);
sendIntent.putExtra(Intent.EXTRA_TEXT, textMessage);
sendIntent.setType("text/plain");
Nota: En este caso, el URI no se usa, pero el tipo de los datos de la intent se declara para
especificar el contenido que tienen los extras.
Aquí se muestra un diálogo con una lista de apps que responden a la intent
pasada al método createChooser(), con el texto proporcionado como título del
diálogo.
Para informar las intents implícitas que puede recibir tu app, declara uno o más
filtros para cada componente de la esta con un elemento <intent-filter> en
el archivo de manifiesto. Cada filtro de intents especifica el tipo de intents que
acepta según la acción, los datos y la categoría de la intent. El sistema entregará
la intent implícita al componente de la aplicación solo si la intent puede pasar por
uno de los filtros de intents.
Nota: Una intent explícita siempre se entrega al destino, independientemente de los filtros de
intents que declare el componente.
<action>
<data>
Declara el tipo de datos que se acepta, mediante el uso de uno o más atributos
que especifican varios aspectos del URI de los datos (scheme, host, port, path,
etc.) y el tipo de MIME.
<category>
<activity android:name="ShareActivity">
<intent-filter>
<action android:name="android.intent.action.SEND"/>
<category android:name="android.intent.category.DEFAULT"/>
<data android:mimeType="text/plain"/>
</intent-filter>
</activity>
El uso de un filtro de intents no es una manera segura de prevenir que otras apps
inicien tus componentes. Si bien los filtros de intents restringen un componente
para que responda solamente a ciertos tipos de intents implícitas, otra app puede
iniciar potencialmente el componente de tu app usando una intent explícita si el
desarrollador determina los nombres de los componentes. Si es importante
que solo tu apppueda iniciar uno de los componentes, establece el
atributo exported en "false" para ese componente.
Una intent implícita se prueba con un filtro comparando la intent con cada uno de
los tres elementos. Para que se la entregue al componente, la intent debe pasar
las tres pruebas. Si no pasa tan solo una de ellas, el sistema Android no la
entregará al componente. Sin embargo, como un componente puede tener varios
filtros de intents, una intent que no pase por el filtro de un componente podría
pasar por otro filtro. Se proporciona más información sobre la manera en que el
sistema resuelve las intents en la siguiente sección sobre resolución de intents.
Advertencia: Para evitar ejecutar accidentalmente el Service de otra aplicación, siempre usa
una intent explícita cuando inicies tu propio servicio y no declares filtros de intents para el
servicio.
Nota: Para todas las actividades, debes declarar los filtros de intents en el archivo de
manifiesto. No obstante, los filtros para los receptores de mensajes se pueden registrar
dinámicamente llamando a registerReceiver(). Puede anular el registro del receptor
con unregisterReceiver(). Hacerlo permite que la aplicación espere mensajes específicos
solo durante un plazo especificado mientras la aplicación está ejecutándose.
Ejemplos de filtros
Para comprender mejor algunos de los comportamientos de los filtros de intents,
observa el siguiente fragmento de código del archivo de manifiesto de una
aplicación de intercambio social.
<activity android:name="MainActivity">
<!-- This activity is the main entry, should appear in app
launcher -->
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity android:name="ShareActivity">
<!-- This activity handles "SEND" actions with text data -->
<intent-filter>
<action android:name="android.intent.action.SEND"/>
<category android:name="android.intent.category.DEFAULT"/>
<data android:mimeType="text/plain"/>
</intent-filter>
<!-- This activity also handles "SEND" and "SEND_MULTIPLE" with
media data -->
<intent-filter>
<action android:name="android.intent.action.SEND"/>
<action android:name="android.intent.action.SEND_MULTIPLE"/>
<category android:name="android.intent.category.DEFAULT"/>
<data
android:mimeType="application/vnd.google.panorama360+jpg"/>
<data android:mimeType="image/*"/>
<data android:mimeType="video/*"/>
</intent-filter>
</activity>
Estos son algunos de los casos de uso principales de una intent pendiente:
Declarar una intent que se ejecutará cuando el usuario realice una acción con
su notificación (el NotificationManager del sistema Android ejecuta la Intent).
Declarar una intent que se ejecutará cuando el usuario realice una acción con el widget de
su aplicación (la app de la pantalla principal ejecuta la Intent).
Declarar una intent que se ejecutará en un momento especificado en el futuro
(el AlarmManager del sistema Android ejecuta la Intent).
Como cada objeto Intent está diseñado para ser manejado por un tipo específico
de componente de la aplicación (Activity, Service o BroadcastReceiver), se
debe tener la misma consideración al crear unaPendingIntent. Cuando use una
intent pendiente, la aplicación no ejecutará la intent con una llamada
como startActivity(). En cambio, debe declarar el tipo de componente
deseado cuando cree la PendingIntentllamando al método creador respectivo:
Cuando el sistema recibe una intent implícita para iniciar una actividad, busca la
mejor actividad para la intent mediante la comparación de la intent con los filtros
de intents basándose en tres aspectos:
La acción de la intent
Los datos de la intent (tanto URI como tipo de datos)
La categoría de la intent
Prueba de acción
Para especificar las acciones de intents aceptadas, un filtro de intents puede
declarar un número de elementos <action> de cero en adelante. Por ejemplo:
<intent-filter>
<action android:name="android.intent.action.EDIT" />
<action android:name="android.intent.action.VIEW" />
...
</intent-filter>
Para pasar el filtro, la acción especificada en la Intent debe coincidir con una de
las acciones indicadas en el filtro.
Prueba de categoría
Para especificar las categorías de intents aceptadas, un filtro de intents puede
declarar un número de elementos <category> de cero en adelante. Por ejemplo:
<intent-filter>
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
...
</intent-filter>
Para que una intent pase una prueba de categoría, cada categoría en
la Intent debe coincidir con la categoría que figura en el filtro. No es necesario
que suceda la situación inversa (el filtro de intents puede declarar más categorías
que las que se especifican en la Intent y la Intent pasará la prueba). Por lo
tanto, una intent sin categorías siempre debería pasar esta prueba,
independientemente de qué categorías estén declaradas en el filtro.
Prueba de datos
Para especificar datos de intents aceptadas, un filtro de intents puede declarar un
número de elementos <data>de cero en adelante. Por ejemplo:
<intent-filter>
<data android:mimeType="video/mpeg" android:scheme="http" ... />
<data android:mimeType="audio/mpeg" android:scheme="http" ... />
...
</intent-filter>
Cada elemento <data> puede especificar una estructura de URI y tipo de datos
(tipo de medios de MIME). Hay atributos separados (scheme, host, port y path)
para cada parte del URI:
<scheme>://<host>:<port>/<path>
Por ejemplo:
content://com.example.project:200/folder/subfolder/etc
Si un filtro especifica únicamente un esquema, todos los URI con ese esquema coinciden
con el filtro.
Si un filtro especifica un esquema y una autoridad pero no una ruta de acceso, todos los
URI con el mismo esquema y autoridad pasan el filtro, independientemente de la ruta que
tengan.
Si un filtro especifica un esquema, una autoridad y una ruta de acceso, solo los URI con el
mismo esquema, autoridad y ruta pasan el filtro.
Nota: La especificación de una ruta de acceso puede contener un asterisco (*) comodín para
requerir solamente una coincidencia parcial del nombre de la ruta.
La prueba de datos compara tanto el URI como el tipo de MIME en la intent con el
URI y el tipo de MIME especificados en el filtro. Las reglas son las siguientes:
1. Una intent que no contiene ni un URI ni un tipo de MIME pasa la prueba solo si el filtro no
especifica ningún URI ni tipo de MIME.
2. Una intent que contiene un URI pero no un tipo de MIME (ni explícitamente ni que se
pueda inferir del URI) pasa la prueba solo si el URI coincide con el formato de URI del
filtro y si el filtro tampoco especifica un tipo de MIME.
3. Una intent que contiene un tipo de MIME pero no un URI pasa la prueba solo si el filtro
enumera el mismo tipo de MIME y no especifica un formato de URI.
4. Una intent que contiene tanto un URI como un tipo de MIME (explícitamente o que se
pueda inferir del URI) pasa la parte de tipo de MIME de la prueba solo si ese tipo coincide
con el tipo enumerado en el filtro. Pasa la parte del URI de la prueba si este coincide con
un URI del filtro o si tiene un URI content: o file: y el filtro no especifica uno. Es decir,
se supone que un componente admite datos content: y file: si el filtro solo indica un
tipo de MIME.
Esta última regla, la regla (d), refleja la expectativa de que los componentes estén
disponibles para obtener datos locales de un archivo o proveedor de contenido.
Por lo tanto, los filtros pueden enumerar solo un tipo de datos y no deben explicitar
el nombre de los esquemas content: y file:. Este es un caso típico. Un
elemento <data> como el siguiente, por ejemplo, indica a Android que el
componente puede obtener datos de imagen de un proveedor de contenido y
mostrarlos:
<intent-filter>
<data android:mimeType="image/*" />
...
</intent-filter>
Como la mayoría del los datos son proporcionados por proveedores de contenido,
los filtros que especifican un tipo de datos pero no un URI son, tal vez, los más
comunes.
<intent-filter>
<data android:scheme="http" android:type="video/*" />
...
</intent-filter>
Coincidencias de intents
Se establecen coincidencias de las intents con filtros de intents no solo para
detectar un componente de destino que se debe activar, sino también para
detectar algo sobre el conjunto de componentes del dispositivo. Por ejemplo, la
app de página principal completa el lanzador de la aplicación encontrando todas
las actividades con filtros de intents que especifiquen la acción ACTION_MAIN y la
categoría CATEGORY_LAUNCHER.
El resto de este documento aborda los conceptos básicos con respecto a cómo
crear y utilizar una actividad, incluido un artículo completo sobre cómo funciona el
ciclo de vida de la actividad, de modo que puedas administrar correctamente la
transición entre diferentes estados de la misma.
onCreate()
onPause()
Existen muchos otros métodos callback del ciclo de vida que deberías usar para
proporcionar una experiencia de usuario fluida entre actividades y abordar
interrupciones inesperadas que provocan la detención e incluso la destrucción de
tu actividad. Todos los métodos callback del ciclo de vida se discuten más
adelante, en la sección acerca de Cómo administrar el ciclo de vida de la
actividad.
Android ofrece varias vistas listas que puedes usar para diseñar y organizar tu
presentación. Los “widgets” son vistas que proporcionan elementos visuales (e
interactivos) para la pantalla, como un botón, un campo de texto, una casilla de
verificación o una imagen. Los “diseños” son vistas derivadas de ViewGroup que
proporcionan un modelo de diseño único para sus vistas secundarias, como un
diseño lineal, un diseño de cuadrículas o un diseño relativo. También puedes
convertir en subclases las clases View y ViewGroup (o subclases ya existentes)
para crear tus propios widgets y diseños y aplicarlos en el diseño de tu actividad.
La forma más común de definir un diseño mediante el uso de vistas es con un
archivo de diseño XML guardado en los recursos de tu aplicación. De esta
manera, puedes mantener el diseño de tu interfaz de usuario separado del código
fuente que define el comportamiento de la actividad. Puedes configurar el diseño
como la IU para tu actividad con setContentView(), pasando la ID de recurso
para el diseño. También puedes crear nuevas Viewen el código de tu actividad y
una jerarquía de vistas insertando nuevas View en un ViewGroup, y luego usar
ese diseño pasando la raíz ViewGroup a setContentView().
Para obtener información acerca de cómo crear una interfaz de usuario, consulta
la documentación Interfaz de usuario.
Existen muchos otros atributos que puedes incluir en este elemento para definir
propiedades, como la etiqueta para la actividad, un ícono para la actividad o un
tema para diseñar la IU de la actividad. El atributo android:name es el único
obligatorio; especifica el nombre de clase de actividad. Una vez que publicas tu
aplicación, no debes cambiar este nombre porque si lo haces podrías anular
funcionalidades, como accesos directos de la aplicación (lee la publicación del
blog, Cosas que no pueden cambiar).
<activity android:name=".ExampleActivity"
android:icon="@drawable/app_icon">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
Para obtener más información acerca de cómo tus actividades pueden responder
a intents, lee el documento Intents y filtros de intents .
Sin embargo, tu aplicación también podría querer realizar alguna acción, como
enviar un correo electrónico, un mensaje de texto o actualizar el estado con datos
de tu actividad. En este caso, tu aplicación podría no tener sus propias actividades
para realizar esas acciones, por lo que, en su lugar, puedes aprovechar las
actividades que proporcionan otras aplicaciones en el dispositivo y que pueden
realizar las acciones por ti. Aquí es cuando las intents pasan a ser muy valiosas,
ya que puedes crear una intent que describa una acción que quieres realizar y el
sistema iniciará la actividad adecuada desde otra aplicación. Si hubieran varias
actividades que pudiesen ejecutar la intent, el usuario podrá seleccionar la que
quiera usar. Por ejemplo, si quieres permitirle al usuario enviar un mensaje de
correo electrónico, puedes crear la siguiente intent:
Por ejemplo, quizá quieras que el usuario seleccione uno de sus contactos para
que tu actividad pueda hacer algo con la información de ese contacto. Aquí te
mostramos cómo puedes crear esa intent y manipular el resultado:
private void pickContact() {
// Create an intent to "pick" a contact, as defined by the content
provider URI
Intent intent = new Intent(Intent.ACTION_PICK,
Contacts.CONTENT_URI);
startActivityForResult(intent, PICK_CONTACT_REQUEST);
}
@Override
protected void onActivityResult(int requestCode, int resultCode,
Intent data) {
// If the request went well (OK) and the request was
PICK_CONTACT_REQUEST
if (resultCode == Activity.RESULT_OK && requestCode ==
PICK_CONTACT_REQUEST) {
// Perform a query to the contact's content provider for the
contact's name
Cursor cursor = getContentResolver().query(data.getData(),
new String[] {Contacts.DISPLAY_NAME}, null, null, null);
if (cursor.moveToFirst()) { // True if the cursor is not empty
int columnIndex =
cursor.getColumnIndex(Contacts.DISPLAY_NAME);
String name = cursor.getString(columnIndex);
// Do something with the selected contact's name...
}
}
}
Nota: En la mayoría de los casos, no debes finalizar explícitamente una actividad con estos
métodos. Tal como se discute en la siguiente sección acerca del ciclo de vida de la actividad,
el sistema Android se encarga de administrar el ciclo de vida de una actividad por ti, por lo que
no necesitas finalizar tus propias actividades. Llamar a estos métodos podría afectar de forma
negativa la experiencia de usuario esperada y solo deben usarse cuando no quieres que el
usuario vuelva a esta instancia de la actividad de forma terminante.
Reanudada
Pausada
Detenida
Nota: La implementación que realices de estos métodos del ciclo de vida siempre deben
llamar la implementación de la superclase antes de realizar cualquier otra tarea, como se
muestra en los ejemplos anteriores.
La figura 1 ilustra esos bucles y el camino que debe tomar una actividad entre
estados. Los rectángulos representan los métodos callback que puedes
implementar para realizar operaciones cuando la actividad cambie de estado.
Figura 1: Ciclo de vida de la actividad.
Los mismos métodos callback del ciclo de vida se indican en la tabla 1, que
describe cada uno de los métodos callback en más detalle y ubica a cada uno
dentro del ciclo de vida total de la actividad, incluido si el sistema puede eliminar la
actividad después de que se completa el método callback.
Tabla 1: Resumen de los métodos de callback del ciclo de vida de una actividad.
¿Se puede
A
Método Descripción eliminar después
continuación
?
Siempre seguido
por onStart().
temporalmente esa
instancia de la actividad
para ahorrar espacio.
Puedes diferenciar estos
dos escenarios con el
método isFinishing()
.
Los métodos en los que se indica "No" en la columna ¿Se puede eliminar
después? protegen el proceso que aloja la actividad para que no pueda ser
eliminada desde el momento en que se los llama. De esta manera, la actividad es
"eliminable" desde el momento en que onPause() regresa hasta el momento en
que se llama a onResume(). No volverá a ser "eliminable" hasta que se llame
nuevamente a onPause() y regrese.
Nota: Una actividad que técnicamente no sea "eliminable" de acuerdo con su definición en la
tabla 1, aún podrá ser eliminada por el sistema, pero esto solo ocurriría en situaciones
extremas en las que no haya otros recursos. Cuándo se podría eliminar una actividad se
discute en más detalle en el documento Procesos y subprocesos.
Sin embargo, cuando el sistema destruye una actividad para recuperar memoria,
el objeto Activity también se destruye, por lo cual el sistema no puede
simplemente reanudarla con su estado intacto. En su lugar, si el usuario retrocede
en su navegación hasta esa actividad, el sistema debe volver a crear el
objeto Activity. Aún así, el usuario no sabe que el sistema destruyó la actividad
y la volvió a crear y, por lo tanto, probablemente espere que la actividad se
encuentre tal como estaba. En esa situación, puedes garantizar que se conserve
la información importante acerca del estado de la actividad mediante la
implementación de un método de callback adicional que te permita guardar
información acerca del estado de tu actividad: onSaveInstanceState().
Figura 2: Dos maneras en las cuales una actividad recupera el foco para el usuario con su
estado intacto: la actividad se destruye, luego vuelve a crearse y debe restaurar el estado
guardado anteriormente, o se detiene y luego se reanuda, y su estado permanece intacto.
Coordinar actividades
Cuando una actividad inicia otra, ambas experimentan transiciones en el ciclo de
vida. La primera actividad se pausa y se detiene (aunque no se detendrá si aún
está visible en segundo plano) mientras se crea la otra actividad. Si esas
actividades comparten datos guardados en el disco o en alguna otra parte, es
importante que entiendas que la primera actividad no se detiene completamente
antes de que se cree la segunda, sino que el proceso de inicio de una segunda
actividad se superpone con el proceso de detención de la primera.
El orden de los callbacks del ciclo de vida está bien definido, especialmente
cuando las dos actividades están en el mismo proceso y una inicia la otra. Aquí te
mostramos el orden de las operaciones que ocurren cuando la actividad A inicia la
actividad B:
Para lograr la mayor base de usuarios posible para su aplicación, debe esforzarse
por admitir tantas configuraciones de dispositivo como sea posible con un solo
APK. En la mayoría de las situaciones, puede hacerlo desactivando las funciones
opcionales en tiempo de ejecución y proporcionando recursos de aplicaciones con
alternativas para diferentes configuraciones (como diferentes diseños para
diferentes tamaños de pantalla). Sin embargo, si es necesario, puede restringir la
disponibilidad de su aplicación a los dispositivos a través de Google Play Store
según las siguientes características del dispositivo:
Si es necesario, puede evitar que los usuarios instalen su aplicación cuando sus
dispositivos no proporcionan una característica determinada declarándola con
un <uses-feature> elemento en el archivo de manifiesto desu aplicación .
Google Play Store compara las funciones que su aplicación requiere con las
funciones disponibles en el dispositivo de cada usuario para determinar si su
aplicación es compatible con cada dispositivo. Si el dispositivo no proporciona
todas las funciones que su aplicación requiere, el usuario no puede instalarla.
KOTLIN
JAVA
si (! packageManager . hasSystemFeature ( PackageManager . FEATURE _
SENSOR _ COMPASS )) { // Este dispositivo no tiene una brújula,
desactive la función brújula disableCompassFeature () }
Para obtener información sobre todos los filtros que puede usar para controlar la
disponibilidad de su aplicación para los usuarios a través de Google Play Store,
consulte el documento Filtros en Google Play .
Nota: algunos permisos del sistema requieren implícitamente la disponibilidad de una función
del dispositivo. Por ejemplo, si su aplicación solicita permiso para acceder BLUETOOTH, esto
requiere implícitamente la FEATURE_BLUETOOTHfunción del dispositivo. Puede deshabilitar el
filtrado basado en esta función y hacer que su aplicación esté disponible para dispositivos sin
Bluetooth configurando el requiredatributo "false"en la <uses-feature>etiqueta. Para
obtener más información sobre las funciones del dispositivo requeridas implícitamente, lea
los Permisos que implican los requisitos de las funciones .
Versión de plataforma
Diferentes dispositivos pueden ejecutar diferentes versiones de la plataforma
Android, como Android 4.0 o Android 4.4. Cada versión de plataforma sucesiva a
menudo agrega nuevas API no disponibles en la versión anterior. Para indicar qué
conjunto de API están disponibles, cada versión de plataforma especifica un nivel
de API . Por ejemplo, Android 1.0 es el nivel API 1 y Android 4.4 es el nivel API 19.
android {
defaultConfig {
applicationId 'com.example.myapp' // Define el nivel de API mínimo
requerido para ejecutar la aplicación. minSdkVersion 15 // Especifica
el nivel de API utilizado para probar la aplicación. targetSdkVersion
28 ... } }
Para obtener más información sobre el build.gradlearchivo, lea acerca de cómo
configurar su compilación .
Sin embargo, si su aplicación utiliza API agregadas en una versión más reciente
de la plataforma, pero no las requiere para su funcionalidad principal, debe
verificar el nivel de API en tiempo de ejecución y degradar las características
correspondientes cuando el nivel de API sea demasiado bajo. En este caso,
establezca el minSdkVersionvalor más bajo posible para la funcionalidad principal
de su aplicación, luego compare la versión del sistema actual SDK_INT, con una de
las constantes de nombre de código Build.VERSION_CODESque corresponda al
nivel de API que desea verificar. Por ejemplo:
KOTLIN
JAVA
if ( Build . VERSION . SDK _ INT < Build . VERSION _ CODES . HONEYCOMB
) { // Se ejecuta en algo más antiguo que el nivel API 11, así que
deshabilita // las funciones de arrastrar y soltar que usan <code> <a
href = "/ reference / android / content / ClipboardManager.html ">
ClipboardManager </a> </code> APIs disableDragAndDrop () }
Configuracion de pantalla
Android se ejecuta en dispositivos de varios tamaños, desde teléfonos hasta
tabletas y televisores. Para clasificar los dispositivos por su tipo de pantalla,
Android define dos características para cada dispositivo: el tamaño de la pantalla
(el tamaño físico de la pantalla) y la densidad de la pantalla (la densidad física de
los píxeles en la pantalla, conocida como DPI ). Para simplificar las diferentes
configuraciones, Android generaliza estas variantes en grupos que facilitan su
orientación:
Para obtener información sobre cómo crear recursos alternativos para diferentes
pantallas y cómo restringir su aplicación a ciertos tamaños de pantalla cuando sea
necesario, lea Cómo admitir diferentes pantallas .
Figura 1: Dos dispositivos diferentes, cada uno con el diseño predeterminado (la app no
proporciona diseños alternativos).
Figure 2: Dos dispositivos diferentes, cada uno con un diseño diferente para distintos tamaños
de pantalla.
Los recursos predeterminados son los que debes usar sin importar la
configuración del dispositivo o cuando no hay recursos alternativos que coincidan
con la configuración actual.
Los recursos alternativos son los que diseñaste para usar con una configuración
específica. A fin de especificar que un grupo de recursos es para una
configuración específica, agrega un calificador de configuración apropiado al
nombre del directorio.
Por ejemplo, si bien el diseño predeterminado de la IU se guarda en el
directorio res/layout/, puedes especificar que se debe usar un diseño diferente
cuando la pantalla tiene orientación horizontal guardándolo en el
directorio res/layout-land/. Android aplica automáticamente los recursos
correspondientes estableciendo una coincidencia de la configuración actual del
dispositivo con los nombres del directorio de recursos.
Los siguientes documentos proporcionan una guía completa sobre cómo puedes
organizar los recursos de la aplicación, especificar recursos alternativos, acceder a
ellos en la aplicación y más:
Provisión de recursos
Información sobre los tipos de recursos que puedes incluir en tu app, dónde
guardarlos y cómo crear recursos alternativos para configuraciones
específicas de dispositivos.
Acceso a recursos
Localización
Tipos de recursos
Información general de la IU
Todos los elementos de la interfaz de usuario de una app para Android están
desarrollados con objetos View yViewGroup. Una View es un objeto que dibuja
algo en la pantalla con lo que el usuario puede interactuar. Un ViewGroup es un
objeto que tiene otros objetos View (y ViewGroup) para definir el diseño de la
interfaz.
Para declarar el diseño, puedes crear una instancia de objetos View en el código y
desarrollar un árbol, pero la manera más sencilla y efectiva para definir el diseño
consiste en utilizar un archivo XML. XML ofrece una estructura en lenguaje natural
para el diseño, similar a HTML.
Por ejemplo, un diseño vertical simple con una vista de texto y un botón tiene esta
apariencia:
Cuando cargas un recurso de diseño en la app, Android inicia cada nodo del
diseño en un objeto de tiempo de ejecución que puedes usar para definir
comportamientos adicionales, consultar el estado del objeto o modificar el diseño.