Documentos de Académico
Documentos de Profesional
Documentos de Cultura
Tema 12
Intents y Filtros
TEMA 12. INTENTS Y FILTROS
Introducción
Las actividades, servicios y receptores broadcasts son activados a través del envío de mensajes
llamados intenciones (intents).
Existen diferentes mecanismos para enviar intents a los diferentes tipos de componentes:
• Para lanzar una actividad, o hacer que una actividad ya iniciada realice una operación
nueva, se utiliza el método de contexto startActivity(Intent) o bien
Activity.startActivityForResult(Intent) (devolviéndose en este caso el
resultado a través de otro Intent pasado al método Activity.setResult(Intent)).
• Para lanzar un servicio, o hacer que un servicio ya iniciado realice una operación
nueva, se utiliza el método de contexto startService(Intent). También se puede
establecer una conexión con un servicio pasando el intent al método de contexto
bindService(Intent).
• Se pueden pasar intents a los métodos de contexto sendBroadcast(Intent),
sendOrderedBroadcast(Intent), sendStickyBroadcast(Intent). Estos intents
serán enviados a todos los receptores de broadcast que estén suscritos.
En todos los casos, el sistema Android es capaz de encontrar la actividad, servicio o broadcast
adecuado para responder al intent enviado, instanciando dicho componente en caso de que
sea necesario. Debido a los métodos utilizados, los intents son enviados siempre al tipo de
componente adecuado. Por ejemplo, un intent enviado para iniciar una actividad, a través del
método startActivity(), nunca podrá iniciar un servicio o un broadcast.
Descripción de Intent
Los Intent son contenedores de información. Esta información es básicamente de dos tipos:
información que recibirá el componente al cual va dirigido el intent e información dirigida al
sistema, que indicará, por ejemplo, a quién dirigir el intent y cómo iniciar el componente al
cual va dirigido. De forma más pormenorizada, los intent contendrán la siguiente información:
Acción
La acción que desencadenará el intent se pasa al mismo en forma de String. En caso de que el
intent se dirija a un receptor de broadcast, esta acción se refiere al evento que ha tenido lugar
y se quiere comenzar a comunicar en el sistema. Dentro de la propia clase Intent existen
constantes que definen ciertas acciones del sistema. Por ejemplo:
Existen muchas otras acciones definidas en la API Android 1. Además, en cada aplicación se
pueden definir acciones en formato String para activar los diversos componentes que
1
La lista total de acciones definidas en el Intent es, para las actividades: ACTION_MAIN, ACTION_VIEW,
ACTION_ATTACH_DATA, ACTION_EDIT, ACTION_PICK, ACTION_CHOOSER, ACTION_GET_CONTENT, ACTION_DIAL,
ACTION_CALL, ACTION_SEND, ACTION_SENDTO, ACTION_ANSWER, ACTION_INSERT, ACTION_DELETE, ACTION_RUN,
ACTION_SYNC, ACTION_PICK_ACTIVITY, ACTION_SEARCH, ACTION_WEB_SEARCH, ACTION_FACTORY_TEST.
Para los broadcasts: ACTION_TIME_TICK, ACTION_TIME_CHANGED, ACTION_TIMEZONE_CHANGED,
ACTION_BOOT_COMPLETED, ACTION_PACKAGE_ADDED, ACTION_PACKAGE_CHANGED, ACTION_PACKAGE_REMOVED,
contenga. Estas acciones deberán ir precedidas por el nombre del paquete de la aplicación
(por ejemplo, “com.cursoandroid.VER_CITAS_HOY”).
La acción determina completamente cómo se estructura el resto del intent, así como los datos
y los campos extra que pudiera contener. Por lo tanto, es necesario usar nombres de acción lo
más específicos posible y acoplarlos fuertemente al resto de campos del intent. En vez de
definir la acción independientemente, se deberá definir un protocolo completo sobre qué
objetos Intent puede gestionar cada componente de una aplicación.
Para establecer y para leer la acción de un Intent se dispone de los métodos accesores
setAction(String) y getAction().
Datos
Los datos sobre los cuales se actuará se pasan en forma de URI y de tipo MIME. En función de
las especificaciones de los tipos de datos, se adoptarán diferentes acciones. Por ejemplo, si la
acción es ACTION_EDIT, el campo data contendrá la URI de un documento que será mostrado
en modo edición. En el caso de ACTION_CALL, los datos serán una URI tipo tel:, con el
número al cual llamar. Si la acción es ACTION_VIEW y los datos son una URI tipo http:, la
actividad receptora deberá descargar y mostrar los datos a los cuales se refiera la URI (sean
una página web, un documento descargado, o cualquier otro tipo de archivo). Por lo tanto,
cuando un intent inicia un componente que es capaz de gestionar los datos recibidos, es
aconsejable comprobar el tipo MIME para asegurarse que el tipo de dato a manejar es el
correcto.
El tipo de dato puede ser deducido en muchos casos directamente de la URI. En concreto,
aquellas URIs que indican que los datos referenciados están localizados en el propio dispositivo
y que son controlados y proveídos por un proveedor de contenido (las cuales comienzan por
content:).
Para establecer y para leer la URI y el tipo MIME, se utilizarán los métodos accesores
setData(Uri), setType(String), setDataAndType(Uri, String), getData() y getType().
Categoría
Se trata de un String con información adicional sobre el tipo de componente que debería
manejar el intent lanzado. Se pueden almacenar tantas descripciones de categorías como se
requiera, dentro del Intent. Al igual que en el caso de las acciones, dentro de la clase Intent
existen diversas constantes que definen diferentes categorías:
Para establecer y para leer las categorías de un Intent se dispone de los métodos
addCategory(String), removeCategory(String) y getCategories(), método que
devolverá un Set<String> con todas las categorías del Intent.
Extras
Los extras son pares clave-valor que permiten añadir información adicional en el Intent para
que sea gestionada por el componente que lo reciba. Tal y como se ha mencionado más arriba,
como existen acciones que están ligadas a ciertos tipos de URIs, los intent también podrán
estar ligados a ciertos extras. Por ejemplo, ACTION_HEADSET_PLUG deberá ser acompañado de
un extra “state” que indique si los auriculares han sido conectados o desconectados así como
otro extra “name” que especifique el nombre de los auriculares. Igualmente,
ACTION_TIMEZONE_CHANGED deberá ser acompañado de un extra “time-zone” que identifique
la nueva zona horaria. Es decir, si, por ejemplo, se quiere definir una acción MOSTRAR_COLOR
para una actividad, se deberá adjuntar un extra que indique el valor del color a mostrar.
La clase Intent contiene métodos put…() y get…() que permiten la inserción y lectura de
diversos tipos de datos extra. Estos métodos también están disponibles en el propio Bundle
de forma que los extras pueden ser almacenados en dicho objeto el cual será adjuntado al
Intent a través de su método putExtras(Bundle) para posteriormente obtenerlo con el
método getExtras().
Flags
Existen flags de diversos tipos que indicarán al sistema, entre otras cosas, cómo lanzar la
actividad (por ejemplo, a qué tarea pertenecerá) y cómo se deberá tratar una vez haya sido
lanzada (por ejemplo, si aparecerá o no en la lista de actividades recientes). Todos estos flags
están definidos en la clase Intent:
• FLAG_GRANT_READ_URI_PERMISSION
• FLAG_GRANT_WRITE_URI_PERMISSION
• FLAG_DEBUG_LOG_RESOLUTION
• FLAG_FROM_BACKGROUND
• FLAG_ACTIVITY_BROUGHT_TO_FRONT
• FLAG_ACTIVITY_CLEAR_TASK
• FLAG_ACTIVITY_CLEAR_TOP
• FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET
• FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS
• FLAG_ACTIVITY_FORWARD_RESULT
• FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY
• FLAG_ACTIVITY_MULTIPLE_TASK
• FLAG_ACTIVITY_NEW_TASK
• FLAG_ACTIVITY_NO_ANIMATION
• FLAG_ACTIVITY_NO_HISTORY
• FLAG_ACTIVITY_NO_USER_ACTION
• FLAG_ACTIVITY_PREVIOUS_IS_TOP
• FLAG_ACTIVITY_RESET_TASK_IF_NEEDED
• FLAG_ACTIVITY_REORDER_TO_FRONT
• FLAG_ACTIVITY_SINGLE_TOP
• FLAG_ACTIVITY_TASK_ON_HOME
• FLAG_RECEIVER_REGISTERED_ONLY
La funcionalidad asociada a cada uno de estos flags podrá ser consultada en la documentación
oficial de Android, concretamente en la clase Intent.
Filtros de Intent
Las actividades, servicios y broadcasts pueden indicar al sistema qué intents implícitos 2 pueden
gestionar a través de diversos filtros. Cada filtro describe una capacidad de un componente, es
decir, un conjunto de intents que el componente está dispuesto a recibir y gestionar. Los filtros
evitan la recepción de intents implícitos no deseados, ya que solo son enviados al componente
si pueden pasar a través de los filtros que dicho componente haya definido. Sin embargo, los
intents explícitos siempre son enviados a su objetivo, sin considerar su contenido, ya que no se
consultan los filtros.
Los componentes pueden definir por separado los filtros para cada tipo de funcionalidad que
pueden desempeñar. Por ejemplo, la actividad encargada de mostrar un formulario para la
edición citas de una aplicación “Calendario” podrá definir diferentes filtros: uno que invoque
dicha actividad con la información de una cita cargada y lista para ser editada, y otro que
invoque dicha actividad para que muestre el mismo formulario en blanco, permitiendo la
adición de una nueva cita.
2
Es necesario recordar aquí que un intent implícito es aquel que no especifica el nombre (paquete + clase) del
componente destinatario. Un intent explícito, en cambio, es aquel que especifica el nombre de la clase o servicio al
cual va dirigido.
Los filtros de intents son instancias de la clase IntentFilter. No obstante, puesto que el
sistema debe conocer cuáles son las capacidades de un componente (definidas a través de los
filtros) antes de instanciar el mismo, dichos filtros han de ser definidos en el manifiesto de la
aplicación (AndroidManifest.xml), por medio de elementos <intent-filter>. Existe una
excepción en el caso de los filtros de los receptores de broadcast, los cuales son definidos
dinámicamente al invocar al método de contexto registerReceiver() quien recibe como
parámetro, entre otros, un IntentFilter.
Hay que tener en cuenta que, puesto que los filtros solo se aplican en el caso de intents
implícitos, no se puede delegar en ellos la seguridad de la aplicación ya que un intent explícito
siempre llegará a su destino.
Para resolver un intent explícito, Android lo entrega directamente a una instancia de la clase
designada en el intent. En cambio, en el caso de intents implícitos, el sistema debe encontrar el
o los mejores componentes a quienes entregar el intent, que serán actividades o servicios que
declaren a través de filtros que pueden realizar la acción solicitada en el intent, o bien
conjuntos de receptores de broadcasts que puedan responder diversos anuncios de broadcast.
Para ello, comparará el contenido del objeto intent con los filtros de intents, quienes anuncian
las capacidades de los componentes y limitan los intents que estos pueden gestionar. Si el
sistema encuentra varios componentes, de distintas aplicaciones, capaces de gestionar el
intent implícito, mostrará un listado con dichas aplicaciones al usuario, para que este elija,
finalmente, el destino del intent 3.
Para resolver un intent implícito, el sistema consultará los filtros de intents de los
componentes registrados, y los comparará con la acción, datos (URI y tipo) y categoría
definidos en el intent. En dicha consulta, el sistema no tiene en cuenta ni los flags ni los extras
del intent. Para que el intent implícito sea finalmente entregado a un componente que haya
declarado un filtro, deberá cumplir todas las condiciones declaradas en el mismo para poder
pasar a través de dicho filtro (acción, datos y categoría). Si alguna de las áreas no las cumple, el
intent no será capaz de pasar el filtro, por lo que el sistema no entregará dicho intent al
componente que declaraba dicho filtro 4.
Consulta de acción
3
El sistema ofrecerá al usuario recordar cuál es la aplicación preferida para gestionar intents de dicho tipo, de
forma que, en sucesivos intents implícitos similares, no se muestre la lista con las distintas aplicaciones que pueden
gestionarlos.
4
Se deberá tener en cuenta que, puesto que un componente puede declarar más de in filtro, habrá intents que no
pasen por determinados filtros, mientras que por otros sí que pueda pasar.
5
Si el filtro no declara ninguna acción, bloqueará todos los intents implícitos.
<intent-filter>
<action android:name="com.cursoandroid.VER_CITAS_HOY" />
<action android:name="com.cursoandroid.VER_CITAS_SEMANA" />
<action android:name="com.cursoandroid.VER_CITAS_MES" />
…
</intent-filter>
Para que el intent pase el filtro declarado, la acción especificada en el Intent deberá coincidir
con alguna de las declaradas en el filtro. Si el filtro no especifica ninguna acción, ningún intent
que especifique alguna acción podrá pasar dicho filtro. Si, en cambio, el intent no especifica
ninguna acción, podrá pasar por cualquier filtro que sí que especifique alguna.
Consulta de categoría
Los filtros también pueden enumerar listas de categorías como subelementos <category>. Las
categorías son constantes definidas en la clase Intent (CATEGORY_DEFAULT,
CATEGORY_BROWSABLE…) pero son declaradas en el manifiesto a través del valor de la constante
(android.intent.category.DEFAULT, android.intent.category.BROWSABLE…).
<intent-filter>
<category android:name="android.intent.category.DEFAULT"/>
<category android:name="android.intent.category.ALTERNATIVE"/>
…
</intent-filter>
Para que un intent pase el test de la categoría, cada categoría que contenga deberá encajar
con una categoría del filtro. El filtro podrá incluir más categorías, pero si omite alguna de las
contenidas en el Intent, dicho intent no pasará el test.
Cualquier Intent que no contenga categorías cumplirá esta parte del filtro, salvo para aquellas
actividades que no contengan la categoría DEFAULT. Esta categoría es asumida de forma
implícita por el sistema cuando se invoca al método de contexto startActivity(Intent) de
forma que, si se está invocando a una actividad de forma implícita a través de un intent que no
contiene categorías y dicha actividad no contiene ningún filtro con la categoría DEFAULT, el
intent nunca será entregado.
Consulta de datos
Del mismo modo que para las acciones y para las categorías, los filtros pueden enumerar
elementos <data>. Cada elemento especificará una URI así como un tipo de dato MIME.
Además cada parte de la URI podrá ser especificada por separado.
<intent-filter>
<data android:mimeType="video/mpeg" android:scheme="http"… />
<data android:mimeType="audio/mpeg" android:scheme="http"… />
…
</intent-filter>
scheme://host:port/path
content://com.cursoandroid.proveedor:8989/carpeta/subcarpeta/etc
La authority está formada por el host y el port. (Si el host no se especifica, el port se ignora.)
En el filtro, cada uno de los atributos será opcional, pero no son independientes, si no que
dependen del anterior (para especificar en un filtro el path se deberá especificar previamente
la authority quien, a su vez, obligará a que se especifique el schema).
Es más común especificar el tipo de la URI (o parte de la misma) en un filtro. Además, tanto en
los Intent como en los filtros, se puede usar el carácter comodín “*” para el subtipo
(“audio/*”, “video/*”), de forma que cualquier subtipo es permitido, encajando en el filtro.
Las reglas que rigen la comparación de la URI y del tipo de dato declarados en un Intent para
que este pase un filtro son las siguientes:
• Un Intent que no contenga ni URI ni tipo MIME pasará aquellos filtros que no
especifiquen ni URI ni tipo MIME.
• Un Intent que contenga URI pero no tipo MIME, pasará aquellos filtros que solo
declaren URIs que coincidan y que no declaren tipo MIME.
• Un Intent que contenga solo tipo MIME solo pasará aquellos filtros que especifiquen
únicamente el mismo tipo MIME.
• Un Intent que contenga URI y tipo MIME, pasará aquellos filtros que especifiquen el
mismo tipo MIME y que especifiquen una URI coincidente. También pasarán aquellos
Intent que especifiquen una URI de tipo content: o file: si en el filtro no se ha
especificado una URI.
Si un Intent cumple más de un filtro de más de una actividad o servicio, el sistema mostrará
un listado al usuario con todos los componentes capaces de recibir el Intent. Si el Intent
implícito no cumple ningún filtro de ningún componente, se lanzará una excepción.
Del mismo modo, es usual la definición de filtros que especifiquen que el componente es capaz
de obtener un tipo MIME desde un esquema concreto:
Por ejemplo, en el caso de una aplicación tipo navegador de internet, cuando el usuario pulsa
un enlace de una página, el navegador intentará cargarla como si fuera una página HTML. En
caso de no poder mostrar los datos, lanzará un intent que contenga el esquema y el tipo MIME
de dicho enlace. Si no existe ninguna actividad o servicio que, a través de sus filtros, sea capaz
de gestionar dicho intent, el navegador invocará al gestor de descargas para que descargue el
contenido del enlace.
Cualquier aplicación que sea capaz de iniciar de forma autónoma, sin cargar datos de un
Intent deberá tener un filtro con la acción MAIN:
En el caso de que se desee que dicha aplicación sea listada en el launcher deberá, además,
contener la categoría LAUNCHER:
Coincidencia de intents
Los intents son contrastados contra los diversos filtros de las aplicaciones no solo para
descubrir qué componentes pueden ser activados sino también para inferir información del
tipo de componentes instalados en el dispositivo. Por ejemplo, para obtener la lista de
aplicaciones que se mostrarán en el launcher 6, el sistema busca todas las actividades que
especifiquen el filtro:
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
Del mismo modo, el sistema “descubre” la pantalla de inicio, buscando la actividad que
contenga un filtro con “android.intent.category.HOME”.
6
En el launcher se muestran los iconos y etiquetas de todas aquellas aplicaciones instaladas en el dispositivo que el
usuario puede iniciar.