Entendendo as Intents do Android - Parte 2
Continuando o assunto, este post apresenta a estrutura básica das intents e um exemplo de criação de intents com ações e categorias próprias além da definição de intent filters para responder a estas intents.
As Intents são compostas basicamente de:
Nome do componente - é definido pelo nome qualificado da classe e o nome do pacote definido no AndroidManifest.xml que representam o componente que deve ser o encarregado de tratar a Intent. Quando criamos uma Intent explícita com o construtor Intent(this, OutraAtividade.class), o nome do componente é criado automaticamente. No entanto, também é possível defini-lo de forma programática, utilizando os métodos setComponent(), setClass() ou setClassName() da classe Intent.
Ação - é uma string que define qual ação deve ser realizada. Representa aquilo que se deseja fazer. Existem diversas ações genéricas no Android, disponibilizadas como constantes na classe Intent. Alguns exemplos de constantes são:
1) ACTION_CALL - indica que uma chamada telefônica deve ser realizada.
2) ACTION_VIEW - indica que algum dado deve ser exibido para o usuário.
3) ACTION_EDIT - indica que se deseja editar alguma informação.
4) ACTION_SENDTO - indica que se deseja enviar alguma informação.
Enquanto a Intent declara o que deve ser feito, o componente que a recebe é o responsável por definir como a ação será executada. Ou seja, para uma mesma ação, podemos ter comportamentos distintos quando a ação for executada por componentes diferentes. Por exemplo, a ACTION_VIEW pode ser utilizada tanto para indicar que desejamos abrir uma página da Internet quanto para abrir informações de um contato armazenado no telefone.
Dados - uma Intent pode receber uma Uri que determina os dados sobre os quais a ação deve ser realizada. No primeiro exemplo de uso de intents do post anterior, criamos uma Uri para a página que gostaríamos de visitar. Outro exemplo seria criar uma Intent informando uma Uri com valor “content://contacts/people/”, que abriria os contatos do telefone:
Uri uri = Uri.parse("content://contacts/people/");
Intent intent = new Intent(Intent.ACTION_VIEW, uri);
startActivity(intent);
Informações extras - quaisquer outros dados necessários para que o componente execute a ação apropriadamente podem ser informados através dos “extras” da Intent. É bastante comum passarmos uma Uri como fizemos anteriormente quando informamos o local onde a foto deveria ser armazenada. Além disso, podemos também informar outros tipos de dados como strings, tipos primitivos, arrays e objetos serializáveis. Para incluir um dado como extra utilizamos o método putExtra da classe Intent, fornecendo uma string como identificador do dado e o seu respectivo valor. Relembre com o código abaixo, no qual o MediaStore.EXTRA_OUTPUT é o identificador e a uri é o extra:
intent.putExtra(MediaStore.EXTRA_OUTPUT, uri);
Categoria - a categoria, representada apenas por uma string, serve como informação adicional para auxilliar o Android na escolha de qual componente é o mais adequado para receber a Intent. Podemos adicionar várias categorias a uma Intent através do método addCategory. Assim como as ações, existem várias categorias pré-definidas, como a Intent.CATEGORY_APP_MUSIC, que quando colocada em uma Intent informará ao Android que uma Activity capaz de reproduzir músicas deve ser acionada.
As informações contidas nas Intents são utilizadas pelo Android para localizar o componente adequado, geralmente uma activity, para executar a ação desejada. Quando o nome de componente é informado, o Android inicializa exatamente aquele componente, sem necessidade de avaliar a ação ou categoria.
Por outra lado, quando o nome do componente não é informado, é necessário consultar quais são os componentes existentes com a habilidade de executar a ação desejada e que pertencem às categorias existentes na Intent. Adicionalmente, o Android também pode procurar por componentes capazes de resolver a Uri repassada e também de lidar com o formato dos dados (MIME type) informado.
A pergunta que deve estar latente é como o Android sabe ou encontra a Activity que deve ser iniciada, apenas informando esses dados na Intent? A resposta é que não existe mágica e em algum lugar deve estar especificado que determinadas ações podem ser resolvidas por um dado componente. A definição de quais ações um componente está apto a responder, bem como a quais categorias ele pertence e também quais dados ele sabe tratar, é realizado através de intent filters que são configurados no arquivo AndroidManifest.xml.
Em qualquer aplicação Android já existe a declaração de um intent filter no AndroidManifest.xml para a Activity principal:
https://gist.github.com/2479211#file=AndroidManifest.xml
Este intent filter indica que a atividade HelloAndroidActivity é aquela que deve ser iniciada ao abrir a aplicação e que também deve ser listada como uma aplicação do Android que pode ser utilizada por um usuário. Os intent filters podem ainda declarar,além da ação e da categoria, os tipos de dados com os quais o componente é capaz de lidar, como uma imagem por exemplo:
https://gist.github.com/2479211#file=dataMimeType.xml
Com base nestas três informações (action, category e data), o Android é capaz de selecionar qual é o compenente mais adequado para responder à uma Intent implícita, comparando o que foi passado na Intent com aquilo que está declarado nos intent filters.
Nossas aplicações podem definir intent filters com ações e categorias próprias ou fazer uso das já existentes para expor funcionalidades para as demais aplicações. Considerando que em nossa aplicação existe uma activity para exibir uma saudação personalizada para o usuário, podemos declarar um intent filter para ela da seguinte maneira:
https://gist.github.com/2479211#file=AndroidManifest2.xml
E para ativar essa activity devemos criar uma intent assim:
Intent intent = new Intent(SaudacaoActivity.ACAO_EXIBIR_SAUDACAO);
intent.addCategory(SaudacaoActivity.CATEGORIA_SAUDACAO);
intent.putExtra(SaudacaoActivity.EXTRA_NOME_USUARIO,
nomeEditText.getText().toString)
startActivity(intent);
Quando desejamos que uma activity receba intents implícitas, é obrigatório que no intent filter também seja incluída a categoria android.intent.category.DEFAULT. Para cada activity é possível definir vários intent filters, com configurações diferentes de ação e categoria.
Utilizar intents e intent filters personalizados permite que seu aplicativo seja reutilizado por outros, agregando mais funcionalidades. No site http://www.openintents.org/en/intentstable existe uma lista de Intents e aplicativos que podem ser reutilizados facilmente. Não deixe de conferir e contribuir!