Intents e Services
4.1.3 Adicionando links externos ao RestaurantFinder
Quando começamos o RestaurantFinder na Listagem 3.6, usamos objetos Intent
para nos mover entre as telas do nosso aplicativo. Na listagem seguinte, finalizamos a Activity ReviewDetail usando um novo conjunto de objetos Intent implícitos para conectar o usuário a outros aplicativos do telefone.
lisTagem 4.1 Segunda sessão de ReviewDetail, demonstrando a invocação Intent
@Override
public boolean onMenuItemSelected(int featureId, MenuItem item) { Intent intent = null;
switch (item.getItemId()) { case MENU_WEB_REVIEW:
if ((link != null) && !link.equals("")) { intent = new Intent(Intent.ACTION_VIEW, Uri.parse(link)); startActivity(intent); } else { new AlertDialog.Builder(this) setTitle(getResources() .getString(R.string.alert_label)) .setMessage(R.string.no_link_message) .setPositiveButton("Continue", new OnClickListener() {
public void onClick(DialogInterface dialog, int arg1) { } }).show(); } return true; case MENU_MAP_REVIEW: if ((location.getText() != null) && !location.getText().equals("")) { intent = new Intent(Intent.ACTION_VIEW, Uri.parse("geo:0,0?q=" + location.getText().toString())); startActivity(intent); } else { new AlertDialog.Builder(this) .setTitle(getResources() .getString(R.string.alert_label)) .setMessage(R.string.no_location_message)
.setPositiveButton("Continue", new OnClickListener() { public void onClick(DialogInterface dialog, int arg1) { } }).show(); } return true; case MENU_CALL_REVIEW: if ((phone.getText() != null) && !phone.getText().equals("") && !phone.getText().equals("NA")) { String phoneString = parsePhone(phone.getText().toString());
q
Declara o Intentw
Mostra a página webe
Configura o Intent para o item de menu mapServindo o RestaurantFinder com Intent 107
intent = new Intent(Intent.ACTION_CALL, Uri.parse("tel:" + phoneString)); startActivity(intent); } else { new AlertDialog.Builder(this) .setTitle(getResources() .getString(R.string.alert_label)) .setMessage(R.string.no_phone_message)
.setPositiveButton("Continue", new OnClickListener() { public void onClick(DialogInterface dialog, int arg1) { } }).show(); } return true; }
return super.onMenuItemSelected(featureId, item); }
private String parsePhone(final String phone) { String parsed = phone;
parsed = parsed.replaceAll("\\D", ""); parsed = parsed.replaceAll("\\s", ""); return parsed.trim();
}
O objeto Review contém o endereço e número de telefone de um restaurante e um link para a crítica completa online. Usando a Activity ReviewDetail, o usuário abre o menu e escolhe exibir um mapa com direções para o restaurante, chamar o restaurante ou ver a crítica completa em um navegador web. Para permitir que todas essas ações ocorram, o ReviewDetail executa aplicativos Android nativos por meio de chamadas Intent implícitas.
No nosso novo código, inicializamos uma instância de classe Intent
q
para que possa ser usada mais tarde nos menus. Se o usuário selecionar o botão de menuMENU_WEB_REVIEW, criamos uma nova instância da variável Intent inserindo uma ação e dados. Para a ação, usamos a constante String Intent.ACTION_VIEW, que tem o valor android.app.action.VIEW. Você pode usar a constante ou o valor, mas usar constantes ajuda a garantir que você não digite o nome errado. Outras ações comuns são Intent.ACTION_EDIT, Intent.ACTION_INSERT e Intent. ACTION_DELETE.
Para o componente de dados do Intent, usamos Uri.parse(link) para criar um URI. Vamos examinar a Uri em mais detalhes na próxima seção. Por hora, saiba só que isso permite que o componente correto responda a requisição startActiv ity (Intent i)
w
e renderize o recurso identificado pela Uri. Não declaramos diretamente nenhuma Activity ou Service para o Intent. Simplesmente dize- mos o que queremos para a view http://somehost/somepath. O mecanismo de late binding do Android irá interpretar essa requisição durante o tempo de execução, provavelmente iniciando o navegador nativo do dispositivo.ReviewDetail também manipula o item de menu MENU_MAP_REVIEW. Nós ini- cializamos o Intent para usar Intent.ACTION_VIEW novamente, mas dessa vez com um tipo diferente de URI: "geo:0,0?q=" + street_address
e
. Essa combinaçãow
Configura o Intent para o item de menu call
de VIEW e geo invoca um Intent diferente, prova- velmente o aplicativo de mapas nativo. Finalmente, quando executamos MENU_MAP_CALL, requisitamos uma chamada telefônica usando a ação Intent. ACTION_CALL e o esquema tel:Uri
r
.Por meio dessas requisições simples, nosso aplica- tivo RestaurantFinder usa a invocação implícita de
Intent para permitir ao usuário telefonar ou ver o mapa do restaurante selecionado, ou ver a Crítica completa na página web. Esses botões de menu são mostrados na Figura 4.1.
O aplicativo RestaurantFinder agora está com- pleto. Os usuários podem buscar críticas, selecionar uma crítica particular de uma lista, mostrar uma críti- ca detalhada e usar aplicativos nativos adicionais para descobrir mais sobre um restaurante selecionado.
Você aprenderá mais sobre todos os aplicativos nativos e os pares ação-dados na Seção 4.1.5. Agora, vamos nos concentrar no processo de decisão de
Intent e como ele direciona as requisições. 4.1.4 Encontrando seu caminho com Intents
RestaurantFinder faz requisições a outros aplicativos usando invocações de Intents e guia seu movimento interno monitorando requisições de Intent. Três tipos de componentes Android podem se registrar para manipular requisições de Intent:
Activity, Broadcast Receiver e Service. Eles divulgam seus recursos por meio do elemento <intent-filter> no arquivo AndroidManifest.xml.
O Android coloca cada elemento <intent-filter> em um objeto IntentFil ter. Depois que o Android instala um arquivo.apk, ele registra os componentes do aplicativo, incluindo os filtros Intent. Quando a plataforma possui um registro de filtros de Intent, ela pode mapear qualquer requisição de Intent para a Activity,
BroadcastReceiver ou Service corretos instalados. Para encontrar o handler apro- priado de um Intent, o Android inspeciona a ação, dados e categorias do Intent. Um <intent-filter> deve atender as seguintes condições para ser considerado:
A ação e categoria devem combinar.
Se especificados, o tipo data também devem combinar, ou a combinação de es-
quema de dados e autoridade e caminho devem combinar. Vamos examinar esses componentes em mais detalhes. AÇÕES E CATEGORIAS
Cada IntentFilter individual pode especificar zero ou mais ações e zero ou mais cate- gorias. Se nenhuma ação for especificada no IntentFilter, ele combinará com qual- quer Intent. Caso contrário, ele combinará somente se o Intent tiver a mesma ação. Um IntentFilter sem categorias combinará somente com um Intent sem catego- rias. Caso contrário, um IntentFilter deve ter no mínimo o que o Intent especifica. Por exemplo, se um IntentFilter suporta tanto as categorias HOME e ALTERNATIVE, Figura 4.1 Botões de menu
do aplicativo RestaurantFinder que invoca diversos aplicativos externos.
Servindo o RestaurantFinder com Intent 109 ele combinará com um Intent para HOME ou CATEGORY. Mas se o IntentFilter
não fornecer nenhuma categoria, ele não combinará com HOME ou CATEGORY. Você pode trabalhar com ações e categorias sem especificar nenhum dado. Usamos essa técnica na Activity ReviewList que criamos no Capítulo 3. Nesse exemplo, definimos o IntentFilter no XML de manifesto, como mostrado na listagem a seguir.
lisTagem 4.2 Declaração de manifesto da Activity ReviewList com <intent-filter>
<activity android:name="ReviewList" android:label="@string/app_name"> <intent-filter>
<category android:name="android.intent.category.DEFAULT" /> <action android:name="com.msi.manning.restaurant.VIEW_LIST" /> </intent-filter>
</activity>
Para combinar o filtro declarado nessa listagem, usamos o seguinte Intent no código, onde Constants.INTENT_ACTION_VIEW_LIST é a String"com.msi.manning.res taurant.VIEW_LIST":
Intent intent = new Intent(Constants.INTENT_ACTION_VIEW_LIST); startActivity(intent);
DADOS
Depois que o Android determinou que a ação e a categoria combinam, ele inspe- ciona os dados do Intent. Os dados podem ser do tipo MIME explícito ou uma combinação de esquema, autoridade e caminho. O Uri mostrada na Figura 4.2 é um exemplo do uso de esquemas, autoridade e caminhos.
O exemplo seguinte mostra com que se parece o uso de um tipo MIME explícito dentro de um URI:
audio/mpeg
As classes IntentFilter descrevem que combinação de tipo, esquema, autoridade e caminho é aceita. O Android segue um processo detalhado para determinar se há uma correspondência de Intent:
Se um esquema estiver presente e o tipo ausente, Intents com qualquer tipo irão se
corresponder.
Se um tipo estiver presente e o esquema ausente, Intents com qualquer esquema
irão se corresponder.
Se o esquema e o tipo estiverem ausentes, somente Intents sem esquema nem
tipo irão se corresponder.
Se uma autoridade for especificada, um esquema também deve ser especificado. Se um caminho for especificado, um esquema e uma autoridade também devem
ser especificados.
Figura 4.2 As partes de um URI
usadas no Android, mostrando esquema, autoridade e caminho.
weather:// com.msi.manning/loc?zip=12345
IntentFilter
<Intent-filter>
<action android:name=”android.intent.action.VIEW” />
<data android:scheme=”weather” android:host=”com.msi.manning” /> </Intent-filter>
Intent
Intent = newIntent(Intent.ACTION_VIEW
Uri.parse(”weather://com.msi.manning /loc?zip=12345”);
Figura 4.3 Exemplo de Intent e IntentFilter combinados usando um filtro definido em XML.
A maioria das correspondências é direta, mas, como você pode ver, elas podem ficar complicadas. Pense em Intent e IntentFilter como peças de um mesmo quebra-cabeça. Quando você chama um Intent em um aplicativo Android, o siste- ma decide que Activity, Service ou BroadcastReceiver irá executar sua re- quisição usando as ações, categorias e dados fornecidos. O sistema examina todas as peças do quebra-cabeça que possui até encontrar uma que combine com o Intent
que você forneceu e, então, encaixa essas peças para formar a conexão.
A Figura 4.3 mostra um exemplo de como ocorre uma correspondência. Esse exemplo define um IntentFilter com uma ação e uma combinação de um esque- ma e uma autoridade. Ele não especifica um caminho, então, qualquer caminho irá combinar. A figura também mostra um exemplo de Intent com um URI que combina com esse filtro.
Se múltiplas classes de IntentFilter se correspondem com o Intent forneci- do, a plataforma seleciona qual vai tratar o Intent. Para uma ação visível ao usuário como uma Activity, o Android geralmente apresenta ao usuário um menu pop-up que permite que ele selecione que Intent deve controlá-la. Para ações invisíveis como um broadcast, o Android considera a prioridade declarada de cada Intent Filter e dá a eles uma chance ordenada para tratar o Intent.