Aspectos fundamentales de la app

Las apps para Android se pueden escribir con Kotlin, los lenguajes de programación Java y C++. Las herramientas del SDK de Android compilan tu código junto con los archivos de recursos y datos en un APK o un Android App Bundle.

Un paquete de Android, que es un archivo de almacenamiento con un sufijo .apk, incluye el contenido de una app para Android que se requiere en el tiempo de ejecución y es el archivo que usan los dispositivos con tecnología Android para instalarla.

Un Android App Bundle, que es un archivo con el sufijo .aab, incluye el contenido de un proyecto de app para Android, incluidos algunos metadatos adicionales que no son necesarios en el tiempo de ejecución. Un AAB es un formato de publicación y no se puede instalar en dispositivos Android. Difiere la generación y la firma del APK a una etapa posterior.

Cuando distribuyes tu app a través de Google Play, por ejemplo, los servidores de Google Play generan APKs optimizados que contienen solo los recursos y el código que requiere el dispositivo específico que solicita la instalación de la app.

Cada app para Android reside en su propia zona de pruebas de seguridad y está protegida por las siguientes funciones de seguridad de Android:

  • El sistema operativo Android es un sistema Linux multiusuario en el que cada app es un usuario diferente.
  • De forma predeterminada, el sistema le asigna a cada app un ID de usuario de Linux único, que solo el sistema utiliza y que la app desconoce. El sistema establece permisos para todos los archivos de una app de modo que solo el ID de usuario asignado a esa app pueda acceder a ellos.
  • Cada proceso tiene su propia máquina virtual (VM), por lo que el código de una app se ejecuta de forma aislada de otras.
  • De forma predeterminada, cada aplicación ejecuta su propio proceso de Linux. El sistema Android inicia el proceso cuando se debe ejecutar alguno de los componentes de la app y, luego, lo cierra cuando ya no es necesario o cuando el sistema debe recuperar memoria para otras apps.

El sistema Android implementa el principio de privilegio mínimo. Es decir, de forma predeterminada, cada app tiene acceso solo a los componentes que necesita para hacer su trabajo y ya no. Esto crea un entorno muy seguro en el que una app no puede acceder a partes del sistema para las que no se le da permiso.

Sin embargo, hay maneras en las que una app puede compartir datos con otras y en las que una app puede acceder a servicios del sistema:

  • Es posible establecer que dos apps compartan el mismo ID de usuario de Linux para que puedan acceder a los archivos de la otra. Para conservar recursos del sistema, las apps con el mismo ID de usuario también pueden organizar la ejecución en el mismo proceso de Linux y compartir la misma VM. Las apps también deben estar firmadas con el mismo certificado.
  • Una app puede solicitar permiso para acceder a datos del dispositivo, como su ubicación, cámara y conexión Bluetooth. El usuario debe otorgar de manera explícita estos permisos. Para obtener más información sobre los permisos, consulta Permisos en Android.

En el resto de este documento, se describen los siguientes conceptos:

  • Los componentes del marco de trabajo central que definen tu aplicación.
  • El archivo de manifiesto en el que declaras los componentes y las funciones del dispositivo requeridas para tu app.
  • Recursos que son independientes del código de la app y que permiten que esta optimice su comportamiento correctamente para una variedad de configuraciones de dispositivos

Componentes de la aplicación

Los componentes de la app son los componentes básicos de una app para Android. Cada componente es un punto de entrada a través del cual el sistema o un usuario pueden ingresar a la app. Algunos componentes dependen de otros.

Hay cuatro tipos de componentes de una aplicación:

  • Actividades
  • Servicios
  • Receptores de emisiones
  • Proveedores de contenido

Cada tipo cumple un propósito distinto y tiene un ciclo de vida distinto que define cómo se crea y se destruye un componente. En las siguientes secciones, se detallan los cuatro tipos de componentes de la aplicación.

Actividades
Una actividad es el punto de entrada para interactuar con el usuario. Representa una pantalla única con una interfaz de usuario. Por ejemplo, una app de correo electrónico podría tener una actividad que muestra una lista de correos electrónicos nuevos, otra actividad para redactar correos electrónicos y otra actividad para leer correos electrónicos. Si bien las actividades funcionan en conjunto para formar una experiencia del usuario coherente en la app de correo electrónico, cada una es independiente de las demás.

Una app diferente puede iniciar cualquiera de estas actividades si la app de correo electrónico lo permite. Por ejemplo, una app de cámara podría iniciar la actividad en la app de correo electrónico para redactar un nuevo correo electrónico y permitirle al usuario compartir una imagen.

Una actividad posibilita las siguientes interacciones clave entre el sistema y la aplicación:

  • Hacer un seguimiento de lo que le importa al usuario actualmente (lo que está en pantalla) para que el sistema continúe ejecutando el proceso que aloja la actividad
  • Saber qué procesos usados con anterioridad contienen actividades detenidas el usuario podría volver y priorizar esos procesos con mayor prioridad para que estén disponibles.
  • Ayudar a la app a controlar la finalización del proceso para que el usuario pueda volver a las actividades con su estado anterior restablecido
  • Permitir que las apps implementen flujos de usuarios entre sí y que el sistema coordine esos flujos El ejemplo principal es el uso compartido.

Implementas una actividad como una subclase de la clase Activity. Para obtener más información sobre la clase Activity, consulta Introducción a las actividades.

Servicios
Un servicio es un punto de entrada de uso general para mantener una app ejecutándose en segundo plano por todo tipo de motivos. Es un componente que se ejecuta en segundo plano para realizar operaciones de larga duración o realizar trabajos para procesos remotos. Un servicio no proporciona una interfaz de usuario.

Por ejemplo, un servicio podría reproducir música en segundo plano mientras el usuario se encuentra en otra app, o bien podría recuperar datos en la red sin bloquear la interacción del usuario con una actividad. Otro componente, como una actividad, puede iniciar el servicio y dejar que se ejecute o vincularse a él para interactuar con él.

Existen dos tipos de servicios que le indican al sistema cómo administrar una app: servicios iniciados y servicios vinculados.

Los servicios iniciados le indican al sistema que los mantenga en ejecución hasta que se complete su trabajo. Por ejemplo, para sincronizar algunos datos en segundo plano o reproducir música, incluso después de que el usuario abandona la app. La sincronización de datos en segundo plano o la reproducción de música representan diferentes tipos de servicios iniciados, que el sistema maneja de manera diferente:

  • La reproducción de música es algo de lo que el usuario conoce directamente, y la app le comunica esto al sistema indicando que quiere estar en primer plano, con una notificación para informarle al usuario que se está ejecutando. En este caso, el sistema prioriza que el proceso de ese servicio se mantenga en ejecución, ya que el usuario tiene una mala experiencia si desaparece.
  • El usuario no tiene conocimiento directo de un servicio normal en segundo plano, por lo que el sistema tiene más libertad para administrarlo. Podría dejar que se cierre y reiniciar el servicio más tarde, si necesita RAM para elementos que son de mayor interés para el usuario.

Los servicios vinculados se ejecutan porque otra app (o el sistema) indicó que quiere usarlos. Un servicio vinculado proporciona una API a otro proceso, y el sistema sabe que hay una dependencia entre estos procesos. Por lo tanto, si el proceso A está vinculado a un servicio en el proceso B, el sistema sabe que necesita mantener el proceso B y su servicio ejecutándose para A. Además, si el proceso A es algo que le importa al usuario, sabrá que debe tratar el proceso B como algo que también le interesa al usuario.

Debido a su flexibilidad, los servicios son componentes básicos útiles para todo tipo de conceptos de sistemas de nivel superior. Los fondos animados, los objetos de escucha de notificaciones, los protectores de pantalla, los métodos de entrada, los servicios de accesibilidad y muchas otras funciones principales del sistema se compilan como servicios que implementan las aplicaciones y a los que se vincula el sistema cuando se ejecutan.

Un servicio se implementa como una subclase de Service. Para obtener más información sobre la clase Service, consulta la Descripción general de los servicios.

Nota: Si tu app se orienta a Android 5.0 (API nivel 21) o versiones posteriores, usa la clase JobScheduler para programar acciones. JobScheduler tiene la ventaja de ahorrar batería, ya que programa de forma óptima las tareas para reducir el consumo de energía y trabaja con la API de Descanso. Si quieres obtener más información para usar esta clase, consulta la documentación de referencia de JobScheduler.

Receptores de emisiones
Un receptor de emisión es un componente que permite que el sistema entregue eventos a la app fuera de un flujo de usuarios normal para que la app pueda responder a los anuncios de emisión en todo el sistema. Debido a que los receptores de emisión son otra entrada bien definida a la app, el sistema puede entregar emisiones incluso a las apps que no están en ejecución en ese momento.

Por ejemplo, una app puede programar una alarma para publicar una notificación que le informe al usuario sobre un evento próximo. Debido a que la alarma se entrega a un BroadcastReceiver en la app, no es necesario que la app permanezca ejecutándose hasta que se active.

Muchas emisiones se originan desde el sistema, como una que anuncia que la pantalla está apagada, la batería tiene poca carga o que se capturó una imagen. Las apps también pueden iniciar transmisiones, por ejemplo, para informarles a otras apps que algunos datos se descargan en el dispositivo y están disponibles para su uso.

Aunque los receptores de emisión no muestran una interfaz de usuario, pueden crear una notificación en la barra de estado para alertar al usuario cuando se produce un evento de emisión. Sin embargo, por lo general, un receptor de emisión es solo una puerta de enlace a otros componentes y está diseñado para realizar una cantidad mínima de trabajo.

Por ejemplo, un receptor de emisión podría programar un JobService para que realice algunas tareas en función de un evento mediante JobScheduler. A menudo, los receptores de emisión implican apps que interactúan entre sí, por lo que es importante tener en cuenta las implicaciones de seguridad cuando se configuran.

Un receptor de emisión se implementa como una subclase de BroadcastReceiver y cada receptor de emisión se entrega como un objeto Intent. Para obtener más información, consulta la clase BroadcastReceiver.

Proveedores de contenido
Un proveedor de contenido administra un conjunto compartido de datos de app que puedes almacenar en el sistema de archivos, en una base de datos SQLite, en la Web o en cualquier otra ubicación de almacenamiento persistente a la que pueda acceder tu app. A través del proveedor de contenido, otras apps pueden consultar o modificar los datos si el proveedor de contenido lo permite.

Por ejemplo, el sistema Android proporciona un proveedor de contenido que administra la información de contacto del usuario. Cualquier app con los permisos adecuados puede consultar el proveedor de contenido, como usar ContactsContract.Data, para leer y escribir información sobre una persona en particular.

Resulta tentador pensar en un proveedor de contenido como una abstracción en una base de datos, porque cuentan con mucha API y compatibilidad integradas para ese caso común. Sin embargo, tienen un propósito principal diferente desde una perspectiva de diseño del sistema.

Para el sistema, un proveedor de contenido es un punto de entrada a una app para publicar elementos de datos con nombre, identificados por un esquema de URI. Por lo tanto, una app puede decidir cómo quiere asignar los datos que contiene a un espacio de nombres de URI y entregar esos URI a otras entidades que, a su vez, pueden usarlos para acceder a los datos. Esto permite que el sistema realice algunas acciones en particular cuando administre una aplicación:

  • La asignación de un URI no requiere que la app permanezca ejecutándose, por lo que los URI pueden persistir después de que se cierran las apps propietarias. El sistema solo necesita asegurarse de que la app propietaria aún esté en ejecución cuando recupere los datos de la app del URI correspondiente.
  • Estos URI también ofrecen un modelo de seguridad importante y detallado. Por ejemplo, una app puede colocar el URI de una imagen que tiene en el portapapeles, pero dejar bloqueado a su proveedor de contenido para que otras apps no puedan acceder a él libremente. Cuando una segunda app intenta acceder a ese URI en el portapapeles, el sistema puede permitir que esa app acceda a los datos mediante un otorgamiento de permisos de URI temporal, de modo que solo acceda a los datos que se encuentran detrás de ese URI y a nada más en la segunda app.

Los proveedores de contenido también son útiles para leer y escribir datos privados de tu app y que no se comparten.

Un proveedor de contenido se implementa como una subclase de ContentProvider y debe implementar un conjunto estándar de APIs que permitan que otras apps realicen transacciones. Para obtener más información, consulta la guía para desarrolladores sobre proveedores de contenido.

Un aspecto único del diseño del sistema Android es que cualquier app puede iniciar un componente de otra app. Por ejemplo, si quieres que el usuario tome una foto con la cámara del dispositivo, es probable que haya otra app para eso, y tu app puede usarla en lugar de desarrollar una actividad para tomar una foto tú mismo. No es necesario que incorpores ni vincules el código de la app de cámara. En cambio, puedes iniciar la actividad en la app 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 app.

Cuando el sistema inicia un componente, inicia el proceso para esa app (si aún 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 ejecutará en el proceso que pertenece a la app de cámara, no en el proceso de tu app. Por lo tanto, a diferencia de las apps de la mayoría de los demás sistemas, las apps para Android no tienen un único punto de entrada: no hay una función main().

Como el sistema ejecuta cada app en un proceso independiente con permisos de archivo que restringen el acceso a otras apps, tu app no puede activar directamente un componente de otra app. Sin embargo, el sistema Android sí puede hacerlo. Para activar un componente en otra app, envías un mensaje al sistema que especifica tu intent de iniciar un componente en particular. Luego, el sistema activa ese componente por ti.

Cómo activar componentes

Un mensaje asíncrono llamado intent activa tres de los cuatro tipos de componentes: actividades, servicios y receptores de emisión. Las intents vinculan componentes entre sí durante el tiempo de ejecución. Puedes pensar en ellos como los mensajeros que solicitan una acción de otros componentes, ya sea que el componente pertenezca a tu app o a otra.

Se crea un intent con un objeto Intent, que define un mensaje para activar un componente específico (un intent explícito) o un tipo específico de componente (un intent implícito).

Para las actividades y los servicios, un intent define la acción que se realizará, como ver o enviar algo, y puede especificar el URI de los datos sobre los que se debe actuar, entre otros aspectos que el componente que se inicia podría necesitar saber.

Por ejemplo, un intent puede 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 muestra el resultado en una Intent. También puedes emitir un intent para permitir que el usuario elija un contacto personal y te lo devuelva. El intent que se muestra incluye un URI que apunta al contacto elegido.

En el caso de los receptores de emisión, el intent define el anuncio de emisión. Por ejemplo, una transmisión que indica que el dispositivo tiene poca batería incluye solo una cadena de acción conocida que indica que la batería está baja.

A diferencia de las actividades, los servicios y los receptores de emisión, los proveedores de contenido se activan cuando se orienta a una solicitud desde un ContentResolver. La resolución de contenido controla todas las transacciones directas con el proveedor de contenido, y el componente que realiza transacciones con el proveedor llama a los métodos del objeto ContentResolver. Esto deja una capa de abstracción por motivos de seguridad entre el proveedor de contenido y el componente que solicita información.

Existen métodos independientes para activar cada tipo de componente:

  • Puedes iniciar una actividad o asignarle una tarea nueva pasando un elemento Intent a startActivity() o, cuando quieras que la actividad muestre un resultado, startActivityForResult().
  • En Android 5.0 (nivel de API 21) y versiones posteriores, puedes usar la clase JobScheduler para programar acciones. En las versiones anteriores de Android, puedes iniciar un servicio o darle instrucciones nuevas a un servicio en curso pasando un Intent a startService(). Puedes establecer una vinculación con el servicio si pasas un Intent a bindService().
  • Puedes iniciar una transmisión pasando un Intent a métodos como sendBroadcast() o sendOrderedBroadcast().
  • Puedes realizar una consulta a un proveedor de contenido si llamas a query() en un ContentResolver.

Para obtener más información sobre el uso de intents, consulta el documento Intents y filtros de intents. En los siguientes documentos, se proporciona más información sobre cómo activar componentes específicos: Introducción a las actividades, Descripción general de los servicios, BroadcastReceiver y Proveedores de contenido.

El archivo de manifiesto

Antes de que el sistema Android pueda iniciar un componente de la app, debe leer el archivo de manifiesto de la app, AndroidManifest.xml, para confirmar que existe el componente. Tu app declara todos sus componentes en este archivo, que se encuentra en la raíz del directorio del proyecto de la app.

El manifiesto puede hacer varias cosas además de declarar los componentes de la app, por ejemplo:

  • Identifica los permisos de usuario que requiere la app, como acceso a Internet o acceso de lectura de los contactos del usuario.
  • Declara el nivel de API mínimo que requiere la app, según las APIs que usa.
  • Declara funciones de hardware y software que la app usa o exige, como una cámara, servicios Bluetooth o una pantalla multitáctil.
  • Declara las bibliotecas de API con las que debe vincularse la app (además de las APIs del framework de Android), como la biblioteca de Google Maps.

Cómo declarar componentes

La tarea principal del manifiesto es informar al sistema sobre los componentes de la app. Por ejemplo, un archivo de manifiesto puede declarar una actividad de la siguiente manera:

<?xml version="1.0" encoding="utf-8"?>
<manifest ... >
    <application android:icon="@drawable/app_icon.png" ... >
        <activity android:name="com.example.project.ExampleActivity"
                  android:label="@string/example_label" ... >
        </activity>
        ...
    </application>
</manifest>

En el elemento <application>, el atributo android:icon apunta a los recursos de un ícono que identifica la app.

En el elemento <activity>, el atributo android:name especifica el nombre de clase completamente calificado de la subclase Activity y el atributo android:label especifica una cadena para usar como etiqueta de la actividad visible para el usuario.

Debes declarar todos los componentes de la aplicación mediante estos elementos:

Las actividades, los servicios y los proveedores de contenido que incluyes en la fuente, pero que no declaras en el manifiesto no son visibles para el sistema y, por lo tanto, nunca se pueden ejecutar. Sin embargo, los receptores de emisión pueden declararse en el manifiesto o crearse de forma dinámica en código como objetos BroadcastReceiver y registrarse en el sistema llamando a registerReceiver().

Para obtener más información sobre cómo estructurar el archivo de manifiesto para tu app, consulta Descripción general del manifiesto de la app.

Declara las capacidades de los componentes

Como se explica en la sección Activar componentes, puedes usar un Intent para iniciar actividades, servicios y receptores de emisión. Para ello, debes nombrar explícitamente el componente objetivo, utilizando el nombre de clase del componente, en el intent. También puedes usar un intent implícito, que describe el tipo de acción que se realizará y, de forma opcional, los datos sobre los que deseas realizar la acción. Un intent implícito permite que el sistema busque un componente en el dispositivo que pueda realizar la acción e iniciarla. Si hay varios componentes que pueden realizar la acción que describe el intent, el usuario selecciona cuál usar.

Precaución: Si usas un intent para iniciar un Service, asegúrate de que la app sea segura mediante un intent explícito. El uso de un intent implícito para iniciar un servicio es un riesgo de seguridad, ya que no puedes estar seguro de qué servicio responde al 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 llamas a bindService() con un intent implícito. No declares filtros de intents para tus servicios.

El sistema identifica los componentes que pueden responder a un intent comparando el intent recibido con los filtros de intents proporcionados en el archivo de manifiesto de otras apps en el dispositivo.

Cuando declaras una actividad en el manifiesto de tu app, tienes la opción de incluir filtros de intents que declaren las capacidades de la actividad para que pueda responder a intents de otras apps. Para ello, agrega un elemento <intent-filter> como elemento secundario del elemento de declaración del componente.

Por ejemplo, si compilas una app de correo electrónico con una actividad para redactar un nuevo correo electrónico, puedes declarar un filtro de intents para responder a los intents "enviar" a fin de enviar un nuevo correo electrónico, como se muestra en el siguiente ejemplo:

<manifest ... >
    ...
    <application ... >
        <activity android:name="com.example.project.ComposeEmailActivity">
            <intent-filter>
                <action android:name="android.intent.action.SEND" />
                <data android:type="*/*" />
                <category android:name="android.intent.category.DEFAULT" />
            </intent-filter>
        </activity>
    </application>
</manifest>

Si otra app crea un intent con la acción ACTION_SEND y lo pasa a startActivity(), el sistema puede iniciar tu actividad para que el usuario pueda redactar y enviar un correo electrónico.

Para obtener más información sobre cómo crear filtros de intents, consulta el documento Intents y filtros de intents.

Cómo declarar los requisitos de la app

Hay una gran variedad de dispositivos con la tecnología de Android, y no todos ofrecen las mismas funciones y capacidades. Para evitar que se instale tu app en dispositivos que no tienen las funciones que tu app necesita, es importante que definas claramente un perfil para los tipos de dispositivos compatibles con tu app declarando los requisitos de dispositivo y software en el archivo de manifiesto.

La mayoría de estas declaraciones son solo de carácter informativo. El sistema no las lee, pero los servicios externos, como Google Play, sí las leen para proporcionar filtros a los usuarios cuando buscan apps desde su dispositivo.

Por ejemplo, supongamos que tu app requiere una cámara y usa APIs introducidas en Android 8.0 (nivel de API 26). Debes declarar estos requisitos. Los valores para minSdkVersion y targetSdkVersion se establecen en el archivo build.gradle del módulo de tu app:

android {
  ...
  defaultConfig {
    ...
    minSdkVersion 26
    targetSdkVersion 29
  }
}

Nota: No configures minSdkVersion ni targetSdkVersion directamente en el archivo de manifiesto, ya que Gradle los reemplaza durante el proceso de compilación. Para obtener más información, consulta Cómo especificar los requisitos de nivel de API.

Debes declarar la función de cámara en el archivo de manifiesto de tu app:

<manifest ... >
    <uses-feature android:name="android.hardware.camera.any"
                  android:required="true" />
    ...
</manifest>

Con las declaraciones que se muestran en estos ejemplos, los dispositivos que no tengan cámara o tengan una versión de Android anterior a 8.0 no podrán instalar tu app desde Google Play. Sin embargo, también puedes declarar que tu app usa la cámara, pero no la exige. Para ello, establece el atributo required en false, verifica durante el tiempo de ejecución si el dispositivo tiene cámara e inhabilita las funciones de cámara según sea necesario.

En la Descripción general de compatibilidad de dispositivos, se proporciona más información para administrar la compatibilidad de tu app con diferentes dispositivos.

Recursos de la app

Una app para Android está compuesta por más que solo código. Requiere recursos que son independientes del código fuente, como imágenes, archivos de audio y cualquier otro elemento relacionado con la presentación visual de la app. Por ejemplo, puedes definir animaciones, menús, estilos, colores y el diseño de las interfaces de usuario de la actividad con archivos en formato XML.

El uso de recursos de la app facilita la actualización de varias características de la app sin modificar el código. Proporcionar conjuntos de recursos alternativos te permite optimizar tu app para una variedad de configuraciones de dispositivos, como diferentes idiomas y tamaños de pantalla.

Para cada recurso que incluyes en tu proyecto de Android, las herramientas de compilación del SDK definen un ID de número entero único que puedes usar para hacer referencia al recurso desde el código de tu app o desde otros recursos definidos en XML. Por ejemplo, si tu app contiene un archivo de imagen llamado logo.png (guardado en el directorio res/drawable/), las herramientas del SDK generan un ID de recurso llamado R.drawable.logo. Este ID se asigna a un número entero específico de la app, que puedes usar para hacer referencia a la imagen e insertarla en la interfaz de usuario.

Uno de los aspectos más importantes de proporcionar recursos independientes de tu código fuente es la capacidad de brindar recursos alternativos para diferentes configuraciones de dispositivos.

Por ejemplo, si defines strings de IU en XML, puedes traducirlas a otros idiomas y guardarlas en archivos separados. Luego, Android aplica las strings de idioma adecuadas a la IU en función de un calificador de idioma que agregas al nombre del directorio de recursos, como res/values-fr/ para los valores de la string en francés y la configuración de idioma del usuario.

Android admite muchos calificadores para tus recursos alternativos. El calificador es una string corta que incluyes en el nombre de tus directorios de recursos para definir la configuración del dispositivo para la que se usan esos recursos.

Por ejemplo, puedes crear diferentes diseños para tus actividades según la orientación y el tamaño de la pantalla del dispositivo. Cuando la pantalla del dispositivo está en orientación vertical (alta), es posible que desees un diseño con botones organizados de forma vertical, pero cuando la pantalla está en orientación horizontal (amplia), es posible que quieras que los botones estén alineados de forma horizontal. Para cambiar el diseño según la orientación, puedes definir dos diseños y aplicar el calificador adecuado al nombre de directorio de cada diseño. Luego, el sistema aplicará automáticamente el diseño apropiado según la orientación actual del dispositivo.

Para obtener más información sobre los diferentes tipos de recursos que puedes incluir en tu aplicación y cómo crear recursos alternativos para diferentes configuraciones de dispositivos, lee la Descripción general de recursos de la app. Para obtener más información sobre las prácticas recomendadas y el diseño de apps sólidas y de calidad de producción, consulta la Guía de arquitectura de apps.

Recursos adicionales

Si deseas aprender a desarrollar para Android con instructivos de código y videos, consulta el curso de Udacity Cómo desarrollar apps para Android con Kotlin.

Continúa leyendo:

Intents y filtros de intents
Obtén información sobre cómo usar las APIs de Intent para activar componentes de la app, como actividades y servicios, y cómo hacer que los componentes de tu app estén disponibles para que los usen otras apps.
Introducción a las actividades
Aprende a crear una instancia de la clase Activity, que proporciona una pantalla independiente en tu aplicación con una interfaz de usuario.
Descripción general de los recursos de las apps
Obtén más información sobre cómo se estructuran las apps para Android de modo que sus recursos independientes pertenezcan al código de la app, incluido cómo puedes proporcionar recursos alternativos para configuraciones de dispositivos específicos.

También es de interés:

Descripción general de la compatibilidad de dispositivos
Obtén información sobre cómo funciona Android en diferentes tipos de dispositivos y cómo puedes optimizar tu app para cada dispositivo o restringir la disponibilidad de la app a diferentes dispositivos.
Permisos en Android
Obtén información sobre cómo Android restringe el acceso de la app a ciertas APIs con un sistema de permisos que requiere el consentimiento del usuario para que tu app pueda usar esas APIs.