Escolar Documentos
Profissional Documentos
Cultura Documentos
ANDROID, Uma Visão Geral
ANDROID, Uma Visão Geral
2011
Contedo
Introduo ....................................................................................................................... 10 Atividades ....................................................................................................................... 11 Criar uma atividade .................................................................................................... 11 Implementando uma interface de usurio ................................................................... 12 Declarando a atividade no manifesto.......................................................................... 13 O uso de filtros inteno ............................................................................................. 13 Iniciar uma atividade .................................................................................................. 14 Iniciar uma atividade para um resultado..................................................................... 15 Encerrar uma atividade ............................................................................................... 16 Gerenciando o ciclo de atividade................................................................................ 16 Aplicar o ciclo de vida callbacks ................................................................................ 17 Salvando estado de atividade ...................................................................................... 23 Manipulao de alteraes na configurao ............................................................... 25 Coordenar as atividades .............................................................................................. 26 Fragmentos ..................................................................................................................... 27 Filosofia de design ...................................................................................................... 27 Criando um fragmento ................................................................................................ 29 DialogFragment ...................................................................................................... 30 ListFragment ........................................................................................................... 31 PreferenceFragment ................................................................................................ 31 Adicionando uma interface de usurio ................................................................... 31 Criando um layout .................................................................................................. 32 Adicionando um fragmento de uma atividade........................................................ 32 Adicionando um fragmento sem uma interface de usurio (UI) ............................ 34 Gerenciando fragmentos ......................................................................................... 35 Executando transaes com fragmento .................................................................. 35
Comunicando-se com a atividade ........................................................................... 37 Criar callbacks evento para a atividade .................................................................. 38 Adicionando itens barra de ao .......................................................................... 39 Manuseio do ciclo de vida do fragmento................................................................ 40 Coordenao com o ciclo de vida de atividade ...................................................... 41 Loaders ........................................................................................................................... 43 Resumo API Loader ................................................................................................... 43 Usando carregadores em um aplicativo ...................................................................... 44 Iniciando um Loader ............................................................................................... 45 Reiniciando o Loader.............................................................................................. 46 Usando callbacks do LoaderManager..................................................................... 47 Exemplo ...................................................................................................................... 50 Tarefas e pilha de execuo ............................................................................................ 53 Salvando estado de atividade ...................................................................................... 56 Gerenciando tarefas .................................................................................................... 57 Definio de modos de lanamento ............................................................................ 58 Usando o arquivo de manifesto .................................................................................. 59 Usando as opes de intenes ................................................................................... 61 Manipulao de afinidades ......................................................................................... 62 Limpando a pilha de volta .......................................................................................... 64 Iniciando uma tarefa ................................................................................................... 65 Servios .......................................................................................................................... 66 O bsico ...................................................................................................................... 67 Voc deve utilizar um servio ou um thread? ........................................................ 67 Declarando um servio no manifesto ..................................................................... 69 Criando um servio iniciado ....................................................................................... 70 Segmentao Android 1.6 ou inferior..................................................................... 70
Estendendo a classe IntentService .......................................................................... 71 Estendendo a classe de servio ............................................................................... 73 Iniciando um servio .............................................................................................. 77 Parando um servio ................................................................................................ 77 Criando um servio vinculado .................................................................................... 78 Enviando notificaes para o usurio ......................................................................... 79 Executando um servio em primeiro plano ................................................................ 79 Gerenciando ciclo de vida de um servio ................................................................... 80 Aplicando o ciclo de vida dos callbacks ................................................................. 81 Servios vinculados ........................................................................................................ 84 O bsico ...................................................................................................................... 84 Vinculao a um servio iniciado ........................................................................... 84 Criando um servio ligado.......................................................................................... 85 Estendendo a classe Binder .................................................................................... 87 Usando um Messenger ........................................................................................... 90 Vinculao a um servio............................................................................................. 93 Notas adicionais ...................................................................................................... 95 Gerenciando o ciclo de vida de um servio de associao ......................................... 96 Processos e threads ......................................................................................................... 98 Processos .................................................................................................................... 98 Ciclo de vida do processo ....................................................................................... 99 Thread ....................................................................................................................... 102 Threads funcionais ................................................................................................ 103 Usando AsyncTask ............................................................................................... 104 Mtodos de Thread-safe ....................................................................................... 106 Comunicao entre processos ................................................................................... 106 Interface de usurio ...................................................................................................... 108
Hierarquia de view.................................................................................................... 108 Como o Android desenha views ........................................................................... 109 Layout ....................................................................................................................... 111 Widgets ..................................................................................................................... 112 Eventos UI ................................................................................................................ 114 Menus ....................................................................................................................... 114 Tpicos Avanados .................................................................................................. 115 Adaptadores .......................................................................................................... 115 Estilos e Temas ..................................................................................................... 116 Declarando Layout ....................................................................................................... 117 Escreve o XML......................................................................................................... 118 Carregar os recursos XML ....................................................................................... 119 Atributos ................................................................................................................... 119 ID .......................................................................................................................... 119 Parmetros de layout ............................................................................................ 120 Posio de Layout ..................................................................................................... 122 Tamanho, padding e margin ..................................................................................... 122 Criando Menus ............................................................................................................. 124 Menu de Opes ................................................................................................... 124 Menu de Contexto ................................................................................................ 124 Submenu ............................................................................................................... 124 Criando um recurso de menu .................................................................................... 124 Inflar um recurso de menu ........................................................................................ 126 Criando um Menu de Opes ................................................................................... 126 Respondendo ao do usurio............................................................................ 127 Alterando os itens de menu em tempo de execuo ............................................. 129 Criando um Menu de Contexto ................................................................................ 129
Registre uma ListView ......................................................................................... 130 Criando Submenus.................................................................................................... 132 Outras funes do menu ........................................................................................... 132 Grupos de Menu ................................................................................................... 132 Itens de menu verificados ..................................................................................... 133 As teclas de atalho ................................................................................................ 135 Adicionar intenes em menu dinamicamente ..................................................... 136 Permitindo a sua atividade a ser adicionada para outros menus........................... 137 Usando a barra de ao ................................................................................................. 139 Adicionando a barra de ao .................................................................................... 139 Removendo a barra de ao .................................................................................. 140 Adicionando itens de ao ........................................................................................ 141 Usando o cone do aplicativo como um item de ao .......................................... 142 Usando o cone do aplicativo para navegar "para cima" ...................................... 143 Adicionando uma exibio de ao .......................................................................... 144 Adicionando abas ..................................................................................................... 146 Adicionando de navegao drop-down .................................................................... 149 Exemplo de SpinnerAdapter e OnNavigationListener ......................................... 150 Estilizando a barra de ao ....................................................................................... 152 Criando caixas de dilogo............................................................................................. 156 Mostrando uma caixa de dilogo .............................................................................. 156 Dispensar um dilogo ............................................................................................... 158 Usando demisso de receptores ............................................................................ 158 Criando um AlertDialog ........................................................................................... 159 Adicionando botes .............................................................................................. 160 Adicionando uma lista .......................................................................................... 161 Adicionando caixas de seleo e botes de rdio ................................................. 161
Criar um ProgressDialog .......................................................................................... 162 Mostrando uma barra de progresso ...................................................................... 163 Criando uma caixa de dilogo personalizada ........................................................... 166 Manipulando eventos de UI.......................................................................................... 169 Os ouvintes de eventos ............................................................................................. 169 Manipuladores de eventos ........................................................................................ 172 Modo de toque .......................................................................................................... 173 Manipulao do foco ................................................................................................ 174 Notificar o usurio ........................................................................................................ 176 Notificao brinde .................................................................................................... 176 Criando notificaes brinde .................................................................................. 177 Notificao na barra de status................................................................................... 179 Criao de notificaes da barra de status ............................................................ 180 Notificao de dilogo .............................................................................................. 189 Aplicando estilos e temas ............................................................................................. 190 Definio de estilos .................................................................................................. 190 Herana ................................................................................................................. 191 Propriedades do estilo........................................................................................... 192 Aplicando estilos e temas para a interface do usurio .............................................. 194 Aplicar um estilo a uma view ............................................................................... 194 Aplicar um tema a uma atividade ou aplicao .................................................... 195 Selecione um tema baseado na verso de plataforma........................................... 196 Usando estilos e temas da plataforma ...................................................................... 196 Recursos de aplicao ................................................................................................... 198 Armazenamento de dados............................................................................................. 201 Utilizando preferncias compartilhadas ................................................................... 201 Preferncias do usurio ......................................................................................... 202
Usando o armazenamento interno ............................................................................ 203 Salvando os arquivos de cache ............................................................................. 204 Usando o armazenamento externo............................................................................ 205 Verificar a disponibilidade dos meios .................................................................. 205 Acessando arquivos em armazenamento externo ................................................. 206 Escondendo seus arquivos a partir da Media Scanner.......................................... 206 Como salvar arquivos que devem ser compartilhados ......................................... 206 Salvando os arquivos de cache ............................................................................. 207 Utilizando bancos de dados ...................................................................................... 208 Banco de dados de depurao ............................................................................... 209 Usando uma conexo de rede ................................................................................... 209 Artigos .......................................................................................................................... 210 Acessibilidade........................................................................................................... 210 Linguagens e recursos .......................................................................................... 210 Linguagens e localidade ....................................................................................... 211 Fazendo o dispositivo falar ................................................................................ 211 Interface .................................................................................................................... 213 Toque .................................................................................................................... 213 Gestos ....................................................................................................................... 216 Mtodo de entrada de dados ................................................................................. 216 Criando um mtodo de entrada de dados ............................................................. 223 Aes de desenhos .................................................................................................... 226 Truques de layout: criando layouts eficientes .......................................................... 229 Truques de layout: usando ViewStub ....................................................................... 234 Truques de layout: mesclando layouts...................................................................... 237 ListView, uma otimizao ........................................................................................ 244 Live folders ............................................................................................................... 247
Live Wallpapers ........................................................................................................ 252 Usando webViews .................................................................................................... 254 Funcionalidades ........................................................................................................ 255 Caixa de pesquisa ................................................................................................. 255 Sistema ..................................................................................................................... 258 Alocao de memria ........................................................................................... 258 Zipaling oferece uma otimizao fcil ................................................................. 260 Nota .............................................................................................................................. 263 Fontes ........................................................................................................................... 263 Fontes das imagens ................................................................................................... 266 Fontes dos artigos ..................................................................................................... 266
Introduo
O Android um software open-source criado para os celulares e outros dispositivos. O Android Open Source Project (AOSP), liderado pelo Google, est encarregado da manuteno e desenvolvimento do Android. Muitos fabricantes de dispositivos trouxeram ao mercado de dispositivos rodando o Android, e eles so disponveis ao redor do mundo.
O objetivo principal construir uma plataforma de software excelente para usurios de todos os dias. Uma srie de empresas empenhou muitos engenheiros para atingir esse objetivo, e o resultado uma produo total de produtos de consumo de qualidade, cuja fonte aberta para customizao e portabilidade.
Voc pode encontrar mais informaes sobre o Android a partir destas pginas abaixo: Filosofia de projeto e objetivos Interagindo com o projeto Compatibilidade com Android Informaes sobre licenciamento
10
Atividades
Uma Activity um componente do aplicativo que fornece uma tela com a qual os usurios podem interagir, a fim de fazer algo, como discar o telefone, tirar uma foto, enviar um e-mail, ou ver um mapa. Para cada atividade dada uma janela na qual se desenha sua interface de usurio. A janela normalmente preenche a tela, mas pode ser menor do que a tela e flutuar em cima de outras janelas. Um aplicativo normalmente consiste de mltiplas atividades que so frouxamente ligadas uns aos outros. Normalmente uma atividade em um aplicativo especificada como a atividade principal", que apresentada ao usurio ao iniciar o aplicativo pela primeira vez. Cada atividade pode comear outra atividade, a fim de executar aes diferentes. Cada vez que comea uma nova atividade, a atividade anterior interrompida, mas o sistema preserva a atividade em uma pilha (a "pilha de volta"). Quando uma nova atividade comea, empurrada para a pilha de volta e leva o foco do usurio. A pilha de volta usa "last in, first out" como mecanismo de fila, ento, quando o usurio est em uma atividade e pressione a tecla BACK, a atividade removida da pilha (e destruda) e retoma a atividade anterior. Quando uma atividade parada por causa de uma nova atividade, h uma notificao da alterao no estado atravs de mtodos de retorno da atividade do ciclo de vida. Existem vrios mtodos de retorno que uma atividade possa receber, devido a uma mudana em seu estado. Por exemplo, quando parado, sua atividade deve liberar todos os objetos grandes, como conexes de rede ou banco de dados. Quando a atividade recomea, voc pode readquirir os recursos necessrios e retomar as aes que foram interrompidas. Estas transies de estado so todos parte do ciclo de atividade.
sua atividade. Mais importante, este o lugar onde voc deve chamar setContentView() para definir o layout para a atividade do usurio a interface. onPause(): O sistema chama este mtodo como o primeiro indcio de que o usurio est saindo de sua atividade (embora nem sempre signifique que a atividade est sendo destruda). Isso geralmente onde voc deve cometer quaisquer alteraes que devem ser mantidas para alm da sesso atual do usurio (porque o usurio pode no voltar). Existem vrios mtodos de retorno do ciclo de vida de outros que voc deve usar a fim de proporcionar uma experincia de usurio mais fluida entre as atividades e manipular interrupes inesperadas que causem a sua atividade a ser interrompida e at mesmo destruda.
12
uma hierarquia de vista atravs da insero de novos Views em um ViewGroup, em seguida, usar esse esquema, passando a raiz ViewGroup para setContentView().
Existem vrios outros atributos que podem ser includos nesse elemento, para definir propriedades, como o rtulo para a atividade, um cone para a atividade, ou um tema ao estilo de interface do usurio da atividade.
O elemento <action> especifica que este o "principal ponto de entrada" para o aplicativo. O elemento <category> especifica que esta atividade deve ser listada no sistema lanador de aplicao.
13
Se voc pretende que o seu aplicativo seja auto-suficiente e no permita que outras aplicaes ativem as suas atividades, ento voc no precisa de nenhum outro filtro de inteno. Apenas uma atividade deve ter a ao "principal" e "lanador" da categoria, como no exemplo anterior. Atividades que voc no deseja disponibilizar para outros aplicativos no devem ter a inteno de filtros e voc pode inici-los usando as intenes explcitas. No entanto, se voc quiser a sua atividade para responder s intenes implcitas que so entregues a partir de outras aplicaes (e suas prprias), ento voc deve definir filtros de inteno adicional para a sua atividade. Para cada tipo de inteno para o qual pretende responder, voc deve incluir um <intent-filter> que inclui um elemento <action> e, opcionalmente, um elemento <category> e/ou um <data>. Estes elementos especificam o tipo de intenes para que sua atividade possa responder.
No entanto, sua aplicao pode tambm querer executar alguma ao, como enviar um e-mail, mensagem de texto, ou atualizao de status, usando dados de sua atividade. Neste caso, sua aplicao no pode ter as suas prprias atividades para realizar tais aes, para que voc possa aproveitar ao invs das atividades previstas por outras aplicaes no dispositivo, que pode executar as aes para voc. Este o lugar onde as
14
intenes so realmente valiosas, voc pode criar uma inteno que descreve uma ao que deseja executar e o sistema inicia a atividade adequada a partir de outro aplicativo. Se houver mltiplas atividades que podem manipular a inteno, ento o usurio pode selecionar qual usar. Por exemplo, se voc quer permitir que o usurio envie uma mensagem de e-mail, voc pode criar a seguinte inteno:
Intent intent = new Intent(Intent.ACTION_SEND); intent.putExtra(Intent.EXTRA_EMAIL, recipientArray); startActivity(intent);
O EXTRA_EMAIL extra adicionado uma matriz de seqncia de endereos de e-mail para onde o e-mail deve ser enviado. Quando um aplicativo de e-mail responde a esta inteno, ele l a matriz de cadeia prevista na extra e as coloca no campo "Para" do formulrio de composio de e-mail.
15
Este exemplo mostra a lgica bsica que voc deve usar seu mtodo onActivityResult() para lidar com um resultado de atividade. A primeira condio verifica se a solicitao foi bem-sucedida, se for, ento o resultCode ser RESULT_OK e se a solicitao para que este resultado est respondendo conhecido, neste caso, o requestCode coincide com o segundo parmetro enviada com startActivityForResult(). De l, o cdigo manipula o resultado de atividade, consultando os dados retornados de uma Intent. O que acontece , um ContentResolver executa uma consulta contra um provedor de contedo, que retorna um Cursor que permite que os dados consultados possam serem lidos.
16
Em pausa: Outra atividade est em primeiro plano e tem foco, mas este ainda visvel. Ou seja, outra atividade visvel na parte superior de um presente e que a atividade parcialmente transparente ou no cobre a tela inteira. Uma atividade em pausa est completamente viva (o objeto Activity mantido na memria, ele mantm todas as informaes do estado e membro, e permanece preso ao gerenciador de janelas), mas pode ser morta pelo sistema em situaes de pouca memria. Parado: A atividade totalmente obscurecida por outra atividade (a atividade est agora em "background"). A atividade parada tambm est ainda viva (o objeto Activity mantido na memria, ele mantm todas as informaes do estado e membro, mas no est ligado ao gerenciador de janelas). No entanto, j no visvel para o usurio e pode ser morto pelo sistema quando a memria necessria em outro lugar. Se uma atividade est em pausa ou parada, o sistema pode retir-la da memria, quer por pedir para terminar (chamando seu finish()), ou simplesmente matar o processo. Quando a atividade aberta novamente (depois de ter sido concludo ou morto), ela deve ser criada por toda parte.
17
@Override protected void onPause() { super.onPause(); // Another activity is taking focus (this activity is about to be "paused"). } @Override protected void onStop() { super.onStop(); // The activity is no longer visible (it is now "stopped") } @Override protected void onDestroy() { super.onDestroy(); // The activity is about to be destroyed. } }
Nota: A implementao destes mtodos do ciclo de vida deve sempre chamar a implementao da superclasse antes de fazer qualquer trabalho, conforme mostrado nos exemplos acima. Juntos, esses mtodos definem o ciclo de vida de uma atividade. Ao implementar esses mtodos, voc pode monitorar trs loops aninhados no ciclo de vida de atividade: A vida inteira de uma atividade acontece entre a chamada para onCreate() e a chamada para onDestroy(). Sua atividade deve executar a instalao do "Estado" global (tal como a definio de layout) em onCreate(), e liberar todos os recursos remanescentes em onDestroy(). Por exemplo, se a sua atividade tem um
segmento em execuo em segundo plano para transferir os dados da rede, ele pode criar esse tpico em onCreate() e depois parar o segmento em onDestroy(). O tempo de vida visvel de uma atividade acontece entre a chamada para onStart() e a chamada para onStop(). Durante este tempo, o usurio pode ver a atividade na tela e interagir com ele. Por exemplo, onStop() chamado quando inicia uma nova atividade e esta no mais visvel. Entre estes dois mtodos, voc pode manter os recursos que so necessrios para mostrar a atividade para o usurio. Por exemplo, voc pode registrar um BroadcastReceiver em onStart() para monitorar as mudanas que impactam sua interface do usurio, e cancelar o registro em onStop() quando o usurio no pode mais ver o que voc est sendo exibido. O sistema pode chamar onStart() e onStop() vrias vezes durante toda a vida til da atividade, como a atividade se alterna entre visvel e oculta para o usurio. ANDROID, uma viso geral Anderson Duarte de Amorim
18
O tempo de vida do primeiro plano de uma atividade acontece entre a chamada para onResume() e a chamada para onPause(). Durante este tempo, a atividade est na frente de todas as outras atividades na tela e tem foco de entrada do usurio. Uma atividade pode freqentemente transitar para dentro e fora do plano, por exemplo, onPause() chamado quando o dispositivo vai dormir ou quando uma caixa de dilogo aparece. O cdigo desses dois mtodos deve ser bastante leve, para evitar transies lentas que fazem o usurio esperar. A figura 1 ilustra esses laos e os caminhos de uma atividade que podem levar a esses estados.
19
Mtodo
Descrio Chamado quando a atividade criada pela primeira vez. Isto onde voc deve fazer tudo do seu conjunto esttico
Killable depois?
Seguinte
onCreate()
normal - criar pontos de vista, vincular dados em listas, e assim por diante. Sempre seguido por onStart() . Chamado atividade depois foi que a
No
onStart()
interrompida, No onStart()
onRestart()
pouco antes de ele ser iniciado novamente. Sempre seguido por onStart() Chamado imediatamente antes da atividade tornar-se visvel para o usurio. Seguido por
onStart()
onResume() se a atividade vem para o primeiro plano, ou onStop() se torna oculto. Chamado imediatamente antes da atividade passar a interagir com o usurio. Neste ponto, a
No
onResume()
onResume()
No
onPause()
20
Chamado quando o sistema est prestes a comear a retomar a outra atividade. Este mtodo geralmente usado para confirmar as alteraes no salvas, dados persistentes, animaes stop e outras coisas que podem estar consumindo onPause() CPU, e assim por diante. Ele deve fazer tudo o que ele faz muito rapidamente, porque a prxima atividade no ser retomada at que ele retorne. Seguidas por onResume() se a atividade retorna para a frente, ou por onStop() se torna invisvel para o usurio. Chamado quando a atividade j no visvel para o usurio. Isso pode acontecer porque ele est sendo destrudo, ou porque outra atividade (seja um existente ou uma nova) foi onStop() retomado e est cobrindo-o. Seguidas por onRestart() se a atividade est voltando para interagir com o usurio, ou por onDestroy() se essa Sim onRestart() ou onDestroy() Sim onResume() ou onStop()
21
Chamado
antes
que
atividade destruda. Esta a chamada final que a atividade ir receber.Poderia quer est chamado porque ser a
nela), ou porque o sistema est destruindo essa instncia da atividade para economizar espao. Voc pode distinguir entre estes dois cenrios com o isFinishing().
A coluna chamada "killable depois?" indica se o sistema pode matar o processo que acolhe a atividade a qualquer momento aps o mtodo retornar, sem executar outra linha. Trs mtodos so marcados como "sim": (onPause() , onStop() , e onDestroy() ). onPause() o primeiro dos trs, uma vez que a atividade criada, onPause() o ltimo mtodo que garantido para ser chamado antes que o processo pode ser morto, se o sistema deve recuperar a memria em caso de emergncia, ento onStop() e onDestroy() no podem ser chamados. Portanto, voc deve usar onPause() para escrever dados persistentes para armazenamento. No entanto, voc deve ser seletivo sobre quais informaes devem ser mantidas durante onPause(), porque os procedimentos de bloqueio neste mtodo bloqueiam a passagem para a prxima atividade e retardam a experincia do usurio. Mtodos que so marcados como "No" na coluna killable protegem o processo da atividade de ser morto desde o momento em que so chamados. Assim, uma atividade killable a partir do momento onPause() e retorna quando onResume() chamado. No ser novamente killable at onPause() seja novamente chamado e retornado. Nota: uma atividade que no tecnicamente "killable" por esta definio na tabela 1 ainda pode ser morta pelo sistema, mas isso vai acontecer apenas em circunstncias extremas, quando no h outro recurso.
22
Figura 2. As duas formas em que para a atividade um usurio retorna ao foco com seu estado intacto, quer a atividade interrompida, e retomada em seguida, o estado de atividade permanece intacta ( esquerda), ou a atividade destrudo, ento recriada e a atividade deve restaurar o estado da atividade anterior (direita).
No entanto, quando o sistema destri uma atividade, a fim de recuperar a memria, a Activity destruda, ento o sistema no pode simplesmente continuar com o seu estado intacto. Em vez disso, o sistema deve recriar a Activity se o usurio navega de volta para ele. No entanto, o usurio no sabe que o sistema destri e recria a atividade e, assim, provavelmente espera que a atividade seja exatamente como era. Nessa situao,
23
voc pode garantir que informaes importantes sobre o estado de atividade so preservadas atravs da implementao de um mtodo de retorno adicional que permite que voc salve as informaes sobre o estado de sua atividade e, em seguida, restaura quando o sistema recria a atividade. O mtodo de callback em que voc pode salvar informaes sobre o estado atual da sua atividade onSaveInstanceState(). O sistema chama este mtodo antes de fazer a atividade vulnervel a ser destruda e passa-lhe um objeto Bundle. O Bundle o lugar onde voc pode armazenar informaes de estado sobre a atividade como pares valornome, utilizando mtodos como putString(). Ento, se o sistema mata a atividade e o usurio navega de volta para sua atividade, o sistema passa o Bundle para onCreate() para que voc possa restaurar o estado de atividade que tenha sido guardado durante onSaveInstanceState(). Se no h informaes do estado para restaurar, em seguida, o Bundle que passou a onCreate() se torna nulo. Nota: No h nenhuma garantia de que onSaveInstanceState() ser chamado antes de sua atividade ser destruda, porque h casos em que no ser necessrio salvar o estado (como quando o usurio deixa a sua atividade com a chave de volta, porque a usurio explicitamente encerra as atividades). Se o mtodo for chamado, ele sempre chamado antes de onStop() e, possivelmente, antes de onPause(). No entanto, mesmo se voc no faz nada e no implementar onSaveInstanceState(), alguns estados de atividade so restaurados pela Activity de implementao padro da classe de onSaveInstanceState(). Especificamente, a implementao padro chama onSaveInstanceState() para cada View no layout, que permite fornecer informaes sobre si que devem ser salvos. Quase todos os widgets no mbito Android implementam este mtodo, de modo que qualquer mudana visvel para o interface do usurio so automaticamente salvas e restauradas quando sua atividade recriada. Por exemplo, o EditText salva qualquer texto digitado pelo usurio e o CheckBox widget salva se marcado ou no. O nico trabalho exigido por voc fornecer uma identificao nica (com o android:id) para cada elemento grfico que deseja salvar seu estado. Se um elemento no tem um ID, ento ele no pode salvar seu estado. Voc tambm pode parar explicitamente de salvar em seu layout seu estado, definindo o android:saveEnabled para "false" ou chamando o setSaveEnabled(). Normalmente, voc
24
no deve desativar isso, mas voc pode caso queira restaurar o estado da atividade de interface diferente. Embora a implementao padro de onSaveInstanceState() salva as informaes teis sobre a atividade da sua interface, voc ainda pode precisar substitu-lo para guardar informaes adicionais. Por exemplo, voc talvez precise salvar valores de um membro que mudou na vida da atividade (que poderiam se correlacionar com os valores restaurados na interface do usurio, mas os membros que detm esses valores UI no so restaurados, por padro). Como a implementao padro de onSaveInstanceState() ajuda a salvar o estado da interface do usurio, se voc substituir o mtodo para salvar informaes de estado adicionais, voc deve sempre chamar a implementao da superclasse de onSaveInstanceState() antes de fazer qualquer trabalho. Nota: Devido ao onSaveInstanceState() no ser garantido de ser chamado, voc deve us-lo apenas para registrar o estado transiente da atividade (o estado da interface do usurio), voc nunca deve us-lo para armazenar dados persistentes. Em vez disso, voc deve usar onPause() para armazenar dados persistentes (como os dados que devem ser salvos em um banco de dados) quando o usurio deixa a atividade. Uma boa maneira de testar a capacidade do seu aplicativo para restaurar seu estado simplesmente girar o dispositivo para fazer alteraes na orientao da tela. Quando da mudana de orientao da tela, o sistema destri e recria a atividade a fim de aplicar recursos alternativos que possam estar disponveis para a nova orientao. Por esta razo, muito importante para sua atividade restaurar completamente o seu estado quando ele recriado, pois os usurios regularmente giram a tela ao usar aplicaes.
25
para lidar adequadamente com este evento, vai ser mais resistentes a eventos inesperados no ciclo de atividade. A melhor maneira de lidar com uma mudana de configurao, tais como uma mudana na orientao da tela, simplesmente preservar o estado do seu aplicativo usando onSaveInstanceState() e onRestoreInstanceState() (ou onCreate() ), como discutido na seo anterior.
Coordenar as atividades
Quando uma atividade comea outra, ambas experimentam as transies do ciclo de vida. A primeira atividade faz uma pausa e para (embora, no vai parar se ele ainda est visvel ao fundo), enquanto a outra atividade criada. Caso esses dados compartilham atividades salvas em disco ou em outro lugar, importante entender que a primeira atividade no est completamente parada antes de a segunda ser criada. Pelo contrrio, o processo de iniciar o segundo se sobrepe ao processo de parar o primeiro. A ordem dos retornos do ciclo de vida bem definida, especialmente quando as duas atividades esto no mesmo processo e est comeando um do outro. Aqui est a ordem das operaes que ocorrem quando a atividade A comea atividade B: 1. O mtodo onPause() da atividade A executado. 2. Os mtodos onCreate(), onStart(), e onResume() de B so executados em seqncia. (Atividade B agora tem o foco do usurio.) 3. Ento, se uma atividade no mais visvel na tela, a sua onStop() executada. Esta seqncia previsvel de callbacks do ciclo de vida permite-lhe gerir a transio de informaes de uma atividade para outra. Por exemplo, se voc deve escrever em um banco de dados quando a primeira atividade pra para que esta atividade pode l-lo, ento voc deve escrever para o banco de dados durante onPause() em vez de durante onStop().
26
Fragmentos
Um Fragment representa um comportamento ou uma parte da interface de usurio em uma Activity. Voc pode combinar vrios fragmentos em uma nica atividade para construir uma interface multi-painel e reutilizao de um fragmento de atividades mltiplas. Voc pode pensar em um fragmento como uma seo modular de uma atividade, que tem seu prprio ciclo de vida, recebe os seus prprios eventos de entrada, e que voc pode adicionar ou remover, enquanto a atividade est em execuo. Um fragmento deve sempre ser incorporado em uma atividade e o ciclo de vida do fragmento diretamente afetado pelo ciclo de vida da atividade de acolhimento. Por exemplo, quando a atividade interrompida, assim so todos os fragmentos nele, e quando a atividade destruda, assim so todos os fragmentos. No entanto, enquanto uma atividade est em execuo (que na retomada do ciclo de vida do estado), voc pode manipular cada fragmento de forma independente, como adicionar ou remover. Quando voc executa uma operao deste tipo de fragmento, voc tambm pode adicion-la a uma pilha de volta que gerenciado pela atividade de cada pilha de volta na entrada da atividade que um registro da transao de fragmento que ocorreu. A volta da pilha permite que o usurio possa reverter uma transao (navegar para trs), pressionando a tecla BACK. Quando voc adiciona um fragmento como uma parte do seu layout, ele vive em um ViewGroup dentro da view de hierarquia e define o seu prprio layout de pontos de vista. Voc pode inserir um fragmento em seu layout declarando o fragmento na atividade de distribuio de arquivos, como <fragment>, ou a partir de seu cdigo de aplicativo, adicionando-o a um j existente ViewGroup. No entanto, um fragmento no obrigado a fazer parte do esquema de atividade, voc tambm pode utilizar um fragmento como um trabalhador invisvel para a atividade.
Filosofia de design
Android apresenta fragmentos no Android 3.0 (API Level "Honeycomb"), principalmente para apoiar projetos mais dinmicos e flexveis de interface do usurio em telas grandes, como os Tablets. Como uma tela de tablet muito maior do que a de um telefone, h mais espao para combinar e trocar os componentes de interface do usurio. Fragmentos permitem tais projetos sem a necessidade de gerenciar mudanas
27
complexas hierarquia vista. Ao dividir o layout de uma atividade em fragmentos, voc se torna capaz de modificar a aparncia da atividade em tempo de execuo e preservar essas mudanas em uma pilha de volta que gerenciada pela atividade. Por exemplo, um aplicativo de notcias pode usar um fragmento para mostrar uma lista de artigos esquerda e outro fragmento para mostrar um artigo direita, ento os fragmentos aparecem em uma atividade, lado a lado, e cada fragmento tem seu prprio conjunto do ciclo de vida, mtodos callback e lidam com seus prprios eventos de entrada do usurio. Assim, em vez de usar uma atividade para selecionar um artigo e outra atividade para ler o artigo, o usurio pode selecionar um artigo e ler tudo dentro da mesma atividade, conforme ilustrado na figura 1.
Figura 1. Um exemplo de como dois mdulos de interface do usurio que normalmente so separados em duas atividades podem ser combinados em uma atividade, utilizando fragmentos.
Um fragmento deve ser um componente modular e reutilizvel em sua aplicao. Ou seja, porque o fragmento define o seu prprio layout e seu prprio comportamento, usando seu prprio ciclo de vida callbacks, voc pode incluir um fragmento em mltiplas atividades. Isto especialmente importante porque permite adaptar a sua experincia de usurio para diferentes tamanhos de tela. Por exemplo, voc pode incluir vrios fragmentos de uma atividade apenas quando o tamanho da tela suficientemente grande, e, quando no , lanar atividades distintas que utilizam diferentes fragmentos. Por exemplo, para continuar com o aplicativo de notcia, a aplicao pode inserir dois fragmentos da atividade, quando rodando em uma grande tela extra (um tablet, por exemplo). No entanto, em um tamanho de tela normal (um telefone, por exemplo), no h lugar suficiente para os dois fragmentos, de modo a Atividade A inclui somente o fragmento para a lista de artigos, e quando o usurio seleciona um artigo, ele comea a
28
Atividade B, que inclui o fragmento para ler o artigo. Assim, a aplicao suporta os padres de projeto sugerido na figura 1.
Criando um fragmento
29
Para criar um fragmento, voc deve criar uma subclasse de Fragment (ou uma subclasse existente do mesmo). O cdigo da classe Fragment se parece muito com uma Activity. Ele contm mtodos de retorno semelhante a uma atividade, como onCreate(), onStart(), onPause(), e onStop(). Na verdade, se voc est convertendo uma aplicao Android existentes para usar fragmentos, voc pode simplesmente mover o cdigo de mtodos de retorno de sua atividade sobre os mtodos de retorno de seus respectivos fragmentos. Normalmente, voc deve implementar pelo menos os mtodos do ciclo de vida a seguir: onCreate(): O sistema chama isso ao criar o fragmento. Dentro de sua aplicao, voc deve inicializar os componentes essenciais do fragmento que pretende manter quando o fragmento pausado ou parado, ento retomado. onCreateView(): O sistema chama isso quando est na hora de extrair o fragmento de sua interface de usurio pela primeira vez. Para desenhar uma interface para o seu fragmento, voc deve retornar um View a partir deste mtodo que a raiz do fragmento do seu layout. Voc pode retornar nulo se o fragmento no fornece uma interface do usurio. onPause(): O sistema chama este mtodo como o primeiro indcio de que o usurio est saindo do fragmento (embora nem sempre significa que o fragmento est sendo destrudo). Isso geralmente onde voc deve cometer quaisquer alteraes que devem ser mantidas para alm da sesso atual do usurio (porque o usurio pode no voltar). A maioria dos aplicativos devem implementar pelo menos estes trs mtodos para cada fragmento, mas existem vrios mtodos de retorno que voc tambm deve usar para lidar com diferentes fases do ciclo de vida do fragmento. Todos os mtodos de retorno do ciclo de vida so discutidos mais adiante, na seo sobre o manuseio do Ciclo de Vida do fragmento. Existem tambm algumas subclasses que voc pode querer estender:
DialogFragment
Mostra uma janela flutuante. Usar essa classe para criar uma caixa de dilogo uma boa alternativa para usar os mtodos auxiliares de dilogo na Activity, porque voc pode incorporar um fragmento de dilogo para a volta da pilha de fragmentos gerido pela atividade, permitindo que o usurio retorne a um fragmento rejeitado. ANDROID, uma viso geral Anderson Duarte de Amorim
30
ListFragment
Exibe uma lista de itens que so gerenciados por um adaptador (como um SimpleCursorAdapter), semelhante ao ListActivity. Ele fornece diversos mtodos para gerenciar uma lista, como o onListItemClick() de callback para manipular eventos de clique.
PreferenceFragment
Exibe uma hierarquia de objetos Preference como uma lista, semelhante PreferenceActivity. Isso til quando se cria um "settings" para sua aplicao.
31
Criando um layout
No exemplo acima, R.layout.example_fragment uma referncia a um recurso chamado layout example_fragment.xml salvo na aplicao dos recursos. O parmetro passado para onCreateView() o pai ViewGroup (da atividade do layout), em que o layout do fragmento ser inserido. O parmetro savedInstanceState um Bundle que fornece dados sobre a instncia anterior do fragmento, se o fragmento est sendo retomado. O mtodo inflate() utiliza trs argumentos: A identificao de recurso do layout que voc deseja inserir. O ViewGroup ser o pai do layout j em utilizao. Passando o container importante para que o sistema possa aplicar os parmetros de layout para o modo de exibio raiz do layout inflado, especificado pela posio do pai em que ele est indo. Um booleano que indica se o layout desenvolvido dever ser anexado ao ViewGroup (segundo parmetro) durante a chamada do procedimento inflate(). (Neste caso, isso falso, porque o sistema j est inserindo o layout inflado no container de passagem verdade seria criar um grupo de vista redundantes no layout final.)
32
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="horizontal" android:layout_width="match_parent" android:layout_height="match_parent"> <fragment android:name="com.example.news.ArticleListFragment" android:id="@+id/list" android:layout_weight="1" android:layout_width="0dp" android:layout_height="match_parent" /> <fragment android:name="com.example.news.ArticleReaderFragment" android:id="@+id/viewer" android:layout_weight="2" android:layout_width="0dp" android:layout_height="match_parent" /> </LinearLayout>
O atributo android:name na <fragment> especifica o Fragment para instanciar no layout. Quando o sistema cria esse layout, ele instancia cada fragmento especificado no layout e chama o onCreateView() para cada um, para recuperar o layout de cada fragmento. O sistema insere a View retornada pelo fragmento diretamente no local do elemento <fragment>. Nota: Cada fragmento requer um identificador nico que o sistema pode usar para restaurar o fragmento se a atividade for reiniciada (e que voc pode usar para capturar o fragmento para realizar transaes, como remov-lo). Existem trs formas para fornecer uma identificao de um fragmento:
o o o
Fornea o android:id com um ID nico. Fornea o android:tag com uma string nica. Se voc no fornecer nenhum dos dois anteriores, o sistema utiliza a identificao de exibio de recipiente.
Ou ento, programaticamente adicionar o fragmento de um j existente ViewGroup . A qualquer momento, enquanto sua atividade est sendo executada, voc pode adicionar fragmentos ao seu layout. Voc s precisa especificar um ViewGroup para colocar o fragmento.
33
Para fazer transaes em sua atividade (como adicionar, remover ou substituir um fragmento), voc deve usar as APIs do FragmentTransaction. Voc pode obter uma instncia de FragmentTransaction de sua Activity como esta:
FragmentManager fragmentManager = getFragmentManager() FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
Voc pode ento adicionar um fragmento ao usar o mtodo add(), especificando o fragmento a adicionar e a viso para inseri-lo. Por exemplo:
ExampleFragment fragment = new ExampleFragment(); fragmentTransaction.add(R.id.fragment_container, fragment); fragmentTransaction.commit();
O primeiro argumento passado para add() o ViewGroup em que o fragmento deve ser colocado, especificado por identificao do recurso, e o segundo parmetro o fragmento a acrescentar. Depois que voc fizer as alteraes com FragmentTransaction , voc deve chamar commit() para que as alteraes tenham efeito.
34
Gerenciando fragmentos
Para gerenciar os fragmentos em sua atividade, voc precisar usar FragmentManager. Para obt-lo, chame getFragmentManager() em sua atividade. Algumas coisas que voc pode fazer com FragmentManager incluem: Obter fragmentos que existem na atividade, com findFragmentById() (para os fragmentos que fornecem uma interface de usurio no layout de atividade) ou findFragmentByTag() (para os fragmentos que fazem ou no uma interface do usurio). Retirar fragmentos da pilha, com popBackStack() (simulando um comando BACK pelo usurio). Registre-se um ouvinte de alterao de parte de trs da pilha, com addOnBackStackChangedListener(). Conforme demonstrado na seo anterior, voc tambm pode usar FragmentManager para abrir uma FragmentTransaction, que lhe permite realizar transaes, tais como adicionar e remover fragmentos.
Cada transao um conjunto de mudanas que se deseja realizar, ao mesmo tempo. Voc pode configurar todas as alteraes que pretendem efetuar uma operao
35
determinada utilizando mtodos como add(), remove(), e replace(). Em seguida, para aplicar a operao para a atividade, voc deve chamar commit(). Antes de chamar commit(), no entanto, voc pode querer chamar addToBackStack(), a fim de acrescentar a operao a uma volta da pilha de transaes. Esta volta na pilha gerida pela atividade e permite que ao usurio retornar ao estado de fragmento anterior, pressionando a tecla BACK. Por exemplo, aqui est como voc pode substituir um fragmento a outro e preservar o estado anterior da pilha de volta:
// Create new fragment and transaction Fragment newFragment = new ExampleFragment(); FragmentTransaction transaction = getFragmentManager().beginTransaction(); // Replace whatever is in the fragment_container view with this fragment, // and add the transaction to the back stack transaction.replace(R.id.fragment_container, newFragment); transaction.addToBackStack(null); // Commit the transaction transaction.commit();
Neste exemplo, newFragment substitui qualquer fragmento (se houver) atualmente no continer de layout identificado pelo R.id.fragment_container ID. Ao chamar addToBackStack(), salvado na pilha de volta a operao para que o usurio possa anular a operao e trazer de volta o fragmento anterior pressionando a tecla BACK. Se voc adicionar vrias alteraes operao (como um outro add() ou remove()) e chamar addToBackStack(), ento todas as mudanas aplicadas antes de chamar commit() so adicionados volta da pilha como uma nica operao e a tecla BACK ir inverter-los todos juntos. A ordem na qual voc adiciona as alteraes em um FragmentTransaction no importa, exceto: Voc deve chamar commit() por ltimo. Se voc est adicionando vrios fragmentos para o mesmo recipiente, ento a ordem em que voc adicion-los determina a ordem em que aparecem na hierarquia.
36
Se voc no chamar addToBackStack() quando voc executar uma operao que remove um fragmento, em seguida, esse fragmento destrudo quando a transao for confirmada e o usurio no pode navegar de volta para ela. Considerando que, se voc chamar addToBackStack() quando da remoo de um fragmento, o fragmento interrompido e ser retomado se o usurio navega de volta. Dica: Para cada transao, voc pode aplicar uma animao de transio, chamando setTransition() antes do commit(). Chamar commit() no executa a operao imediatamente. Em vez disso, ele agenda a execuo no segmento da atividade de interface do usurio (a thread "main"), logo que o segmento for capaz de faz-lo. Se necessrio, no entanto, voc pode chamar executePendingTransactions() no seu segmento de interface do usurio para executar imediatamente as operaes apresentadas por commit(). Fazer isso geralmente no necessrio a menos que a transao uma dependncia para o emprego em outros segmentos. Cuidado: voc pode cometer uma transao usando commit() apenas antes da atividade salvar seu estado (quando o usurio deixa a atividade). Se a tentativa for cometer depois desse ponto, uma exceo ser lanada. Isso ocorre porque o estado, aps a confirmao, pode ser perdido se a atividade precisa ser restaurada. Para as situaes em que no tem problema voc perder o commit, use
commitAllowingStateLoss().
Da mesma forma, sua atividade pode chamar mtodos no fragmento atravs da aquisio de uma referncia para o Fragment de FragmentManager, usando findFragmentById() ou findFragmentByTag(). Por exemplo:
37
Em
seguida,
atividade
que
hospeda
fragmento
implementa
OnArticleSelectedListener e substitui onArticleSelected() para notificar o fragmento B do evento a partir do fragmento A. Para garantir que a atividade de acolhimento implemente essa interface, um fragmento do mtodo onAttach() de retorno (que chama o sistema quando adicionando o fragmento para a atividade) instancia uma instncia de OnArticleSelectedListener pelo casting da Activity que passado para onAttach():
public static class FragmentA extends ListFragment { OnArticleSelectedListener mListener; ... @Override public void onAttach(Activity activity) { super.onAttach(activity); try { mListener = (OnArticleSelectedListener) activity; } catch (ClassCastException e) { throw new ClassCastException(activity.toString() + " must implement OnArticleSelectedListener"); }
38
} ... }
Se a atividade no tenha aplicado a interface, ento o fragmento lana um ClassCastException. Em caso de sucesso, o membro mListener mantm uma referncia para a implementao da atividade de OnArticleSelectedListener, de modo que um fragmento pode compartilhar eventos com a atividade, chamando os mtodos definidos pela interface OnArticleSelectedListener. Por exemplo, se um fragmento uma extenso do ListFragment, cada vez que o usurio clica em um item da lista, o sistema chama onListItemClick() no fragmento, o que chama onArticleSelected() para compartilhar o evento com a atividade:
public static class FragmentA extends ListFragment { OnArticleSelectedListener mListener; ... @Override public void onListItemClick(ListView l, View v, int position, long id) { // Append the clicked item's row ID with the content provider Uri Uri noteUri = ContentUris.withAppendedId(ArticleColumns.CONTENT_URI, id); // Send the event and Uri to the host activity mListener.onArticleSelected(noteUri); } ... }
O parmetro id passado para onListItemClick() o ID da linha do item clicado, que a atividade (ou outro fragmento) utiliza para buscar o artigo a partir do aplicativo ContentProvider.
39
Voc tambm pode registrar uma exibio em seu layout para fornecer um menu de contexto, chamando registerForContextMenu(). Quando o usurio abre o menu de contexto, o fragmento recebe uma chamada para onCreateContextMenu(). Quando o usurio seleciona um item, o fragmento recebe uma chamada para
onContextItemSelected(). Nota: Embora o fragmento receba um on-item-selected na chamada de retorno para cada item de menu que acrescenta, a atividade a primeira a receber o respectivo retorno quando o usurio seleciona um item de menu. Se a execuo da atividade da chamada de retorno no item selecionado no lidar com o item selecionado, o evento transmitido para retorno do fragmento. Isso verdadeiro para o menu de opes e menus de contexto.
40
Gerenciar o ciclo de vida de um fragmento um pouco como gerir o ciclo de vida de uma atividade. Como uma atividade, um fragmento pode existir em trs estados: Retomado: O fragmento visvel na atividade de execuo. Em pausa: Outra atividade est em primeiro plano e tem o foco, mas a atividade em que vive esse fragmento ainda visvel (a atividade do primeiro plano parcialmente transparente ou no cobre a tela inteira). Parado: O fragmento no visvel. A atividade host foi parada ou o fragmento foi retirado da atividade, mas adicionado volta da pilha. Um fragmento que parou ainda est vivo (todas as informaes do estado e membro so mantidas pelo sistema). No entanto, j no visvel para o usurio e sero mortos se a atividade morta. Tambm como uma atividade, voc pode manter o estado de um fragmento com um Bundle, no caso de a atividade do processo ser morta e voc precisar restaurar o estado do fragmento, quando a atividade recriada. Voc pode salvar o estado durante o fragmento onSaveInstanceState() de callback e restaur-lo durante onCreate(), onCreateView() ou onActivityCreated(). A diferena mais significativa no ciclo de vida entre uma atividade e um fragmento como so armazenados em suas respectivas pilhas. Uma atividade colocada em uma pilha de volta das atividades que gerido pelo sistema quando ela est parada, por padro (para que o usurio possa navegar de volta a ele com a chave de volta, como discutido em Tarefas e pilha de volta). No entanto, um fragmento colocado em uma pilha de volta gerido pela atividade de acolhimento somente quando voc solicitar explicitamente que a instncia deve ser salva chamando addToBackStack() durante uma operao que remove o fragmento. Gerenciar o ciclo de vida do fragmento muito semelhante gesto do ciclo de vida da atividade. Assim, as mesmas prticas de gesto do ciclo de vida de atividade tambm se aplicam aos fragmentos. O que voc tambm precisa entender, porm, como a vida da atividade afeta a vida do fragmento.
41
em um retorno semelhante para cada fragmento. Por exemplo, quando a atividade recebe onPause(), cada fragmento na atividade recebe onPause(). Fragmentos tm alguns retornos do ciclo de vida extra, no entanto, para lidar com uma interao nica com a atividade, a fim de realizar aes como construir e destruir UI do fragmento. Estes mtodos de callback adicionais so: onAttach(): Chamado quando o fragmento foi associado com a atividade. onCreateView(): Chamado para criar a hierarquia de viso associada com o fragmento. onActivityCreated(): Chamado quando onCreate() da atividade foi retornado. onDestroyView(): Chamado quando a hierarquia de viso associada com o fragmento est sendo removida. onDetach(): Chamado quando o fragmento est sendo dissociado da atividade. O fluxo do ciclo de vida de um fragmento, como ele afetado por sua atividade de acolhimento, ilustrado pela figura 3. Nesta figura, voc pode ver o que cada estado sucessivo da atividade que determina os mtodos de retorno de um fragmento pode receber. Por exemplo, quando a atividade tenha recebido uma onCreate() de callback, um fragmento da atividade no recebe mais do que o onActivityCreated() de callback. Uma vez que a atividade atinge o estado retomado, voc pode adicionar livremente e remover fragmentos na a atividade. Assim, somente quando a atividade est em estado de retomada, o ciclo de vida de um fragmento pode mudar de forma independente. No entanto, quando a atividade deixa o estado de retomada, o fragmento novamente inserido atravs do ciclo de vida da atividade.
42
Loaders
Loaders tornam fcil carregar os dados de forma assncrona, em uma atividade ou um fragmento. Loaders tm estas caractersticas: Eles esto disponveis para cada Activity e Fragment. Eles fornecem carga assncrona de dados. Eles monitoram a fonte de seus dados e entregam novos resultados quando muda o contedo. Eles reconectam automaticamente o cursor do gestor passado, quando est sendo recriado aps uma mudana de configurao. Assim, eles no precisam de voltar a consultar os seus dados.
43
Loader
Uma classe abstrata que executa o carregamento assncrono de dados. Esta a classe base para um gestor. Voc usaria normalmente CursorLoader, mas voc pode implementar sua prpria subclasse. Enquanto os carregadores esto ativos, eles devem acompanhar a fonte de seus dados e apresentar resultados novos quando alterar o contedo.
AsyncTaskLoader
CursorLoader
Uma subclasse de AsyncTaskLoader que consulta o ContentResolver e retorna um Cursor. Essa classe implementa o protocolo Loader de uma forma padro para consultar cursores, com base em AsyncTaskLoader para realizar a consulta de cursor em uma discusso de fundo para que ele no bloqueie os aplicativo de interface do usurio. Utilizar este carregador a melhor maneira de carregar os dados de forma assncrona a partir de um ContentProvider, ao invs de realizar uma consulta gerida atravs do fragmento ou de APIs.
As classes e interfaces na tabela acima so os componentes essenciais que voc vai usar para implementar um carregador em sua aplicao. Voc no vai precisar de todos eles para cada gestor, mas voc sempre precisa de uma referncia ao LoaderManager para inicializar um carregador e uma implementao de um Loader, como CursorLoader. As sees a seguir mostram como usar essas classes e interfaces em uma aplicao.
44
Um CursorLoader para carregar dados apoiado por uma ContentProvider. Alternativamente, voc pode implementar sua prpria subclasse de Loader ou AsyncTaskLoader para carregar dados de alguma outra fonte. Uma implementao para LoaderManager.LoaderCallbacks. Isto onde voc cria novos loaders e gerencia suas referncias aos carregadores existentes. Uma maneira de mostrar o carregador de dados, como um
Iniciando um Loader
O LoaderManager gerencia um ou mais instncias Loader dentro de uma Activity ou Fragment. H apenas um LoaderManager por atividade ou fragmento. Normalmente, voc inicializa um Loader com o mtodo onCreate() dentro da atividade ou mtodo onActivityCreated() dentro do fragmento. Voc pode fazer isso da seguinte forma:
// Prepare the loader. Either re-connect with an existing one, // or start a new one. getLoaderManager().initLoader(0, null, this);
O mtodo initLoader() utiliza os seguintes parmetros: Um ID exclusivo que identifica o carregador. Neste exemplo, a identificao 0. Os argumentos opcionais para fornecer ao loader a construo (null neste exemplo). A execuo de LoaderManager.LoaderCallbacks, em que a LoaderManager chamada para relatar eventos carregador. Neste exemplo, a classe local implementa a interface LoaderManager.LoaderCallbacks, assim que passa uma referncia para si, this.
45
A chamada ao initLoader() assegura que um carregador inicializado e ativo. Ele tem dois resultados possveis: Se o carregador especificado pelo ID j existe, o ltimo carregador criado reutilizado. Se o carregador especificado pela ID no existir, initLoader() aciona o mtodo LoaderManager.LoaderCallbacks em onCreateLoader(). Isto onde voc implementa o cdigo para instanciar e retornar um carregador novo. Em ambos os casos, a aplicao determinada LoaderManager.LoaderCallbacks est associada com o carregador, e ser chamada quando o estado muda carregador. Se no momento da chamada, o chamador est em seu estado inicial e o carregador solicitado j existe e tem gerado os seus dados, o sistema solicita onLoadFinished() (durante initLoader()), ento voc deve estar preparado para isso acontecer. Observe que o mtodo initLoader() retorna o Loader que criado, mas voc no precisa capturar uma referncia a ele. O LoaderManager gerencia a vida do carregador automaticamente. O LoaderManager inicia e pra de carregar quando necessrio, e mantm o estado do carregador e do seu contedo associado. Isso implica que voc raramente interage com carregadores diretamente. mais comumente usar o LoaderManager.LoaderCallbacks para intervir no processo de carregamento quando ocorrem eventos especficos.
Reiniciando o Loader
Quando voc usa initLoader(), como mostrado acima, ele usa um carregador existente com a identificao especificada, se houver. Se no houver, ele cria um. Mas s vezes voc deseja descartar os dados antigos e comear de novo. Para descartar os dados antigos, use restartLoader(). Por exemplo, essa implementao de SearchView.OnQueryTextListener reinicia o carregador quando o usurio muda de consulta. O loader precisa ser reiniciado para que ele possa usar a pesquisa de reviso de filtro para fazer uma nova consulta:
46
public boolean onQueryTextChanged(String newText) { // Called when the action bar search text has changed. Update // the search filter, and restart the loader to do a new query // with this filter. mCurFilter = !TextUtils.isEmpty(newText) ? newText : null; getLoaderManager().restartLoader(0, null, this); return true; }
47
Neste exemplo, o onCreateLoader() cria um mtodo de retorno CursorLoader. Voc deve construir o CursorLoader usando o mtodo construtor, que exige um conjunto completo de informaes necessrias para realizar uma consulta para o
ContentProvider. Especificamente, necessrio: URI - A URI para o contedo para recuperar. projeo - uma lista de quais colunas retornar. Passando null ir retornar todas as colunas, que ineficiente. seleo - Um filtro que declara que as linhas de retorno, formatado como uma clusula WHERE SQL (excluindo o prprio WHERE). Passando null retornar todas as linhas para o URI especificado. selectionArgs - Voc pode incluir ?s na seleo, que sero substitudas pelos valores da selectionArgs, na ordem em que aparecem na seleo. Os valores sero vinculados como Strings. SortOrder - Como adquirir as linhas, formatado como uma clusula ORDER BY de SQL (excluindo-se o ORDER BY). Passando null usar a ordem de classificao padro, que pode ser desordenada.
// If non-null, this is the current filter the user has provided. String mCurFilter; ... public Loader<Cursor> onCreateLoader(int id, Bundle args) { // This is called when a new Loader needs to be created. This // sample only has one Loader, so we don't care about the ID. // First, pick the base URI to use depending on whether we are // currently filtering. Uri baseUri; if (mCurFilter != null) { baseUri = Uri.withAppendedPath(Contacts.CONTENT_FILTER_URI, Uri.encode(mCurFilter)); } else { baseUri = Contacts.CONTENT_URI; } // Now create and return a CursorLoader that will take care of // creating a Cursor for the data being displayed. String select = "((" + Contacts.DISPLAY_NAME + " NOTNULL) AND (" + Contacts.HAS_PHONE_NUMBER + "=1) AND (" + Contacts.DISPLAY_NAME + " != '' ))"; return new CursorLoader(getActivity(), baseUri, CONTACTS_SUMMARY_PROJECTION, select, null, Contacts.DISPLAY_NAME + " COLLATE LOCALIZED ASC"); }
48
onLoadFinished Este mtodo chamado quando um loader criado anteriormente terminou sua carga. Este mtodo garantido para ser chamado antes do lanamento do ltimo dado que foi fornecido para este carregador. Neste ponto, voc deve remover todo uso dos dados antigos (desde que ser lanado em breve), mas no deve fazer a seu prprio lanamento dos dados desde o seu carregador o dono e vai cuidar disso. O carregador vai lanar os dados, uma vez que conhece que o aplicativo no est mais usando. Por exemplo, se os dados so um cursor de um CursorLoader, voc no deve chamar close() sobre ele mesmo. Se o cursor est sendo colocado em um CursorAdapter, voc deve usar o mtodo swapCursor() para que o antigo Cursor no seja fechado. Por exemplo:
// This is the Adapter being used to display the list's data. SimpleCursorAdapter mAdapter; ... public void onLoadFinished(Loader<Cursor> loader, Cursor data) { // Swap the new cursor in. (The framework will take care of closing the // old cursor once we return.) mAdapter.swapCursor(data); }
onLoaderReset Este mtodo chamado quando um loader criado anteriormente est sendo redefinido, tornando os seus dados indisponveis. Este retorno permite saber quando o dado est prestes a ser liberado assim voc pode remover a referncia a ele. Esta aplicao chama swapCursor() com um valor null:
// This is the Adapter being used to display the list's data. SimpleCursorAdapter mAdapter; ... public void onLoaderReset(Loader<Cursor> loader) { // This is called when the last Cursor provided to onLoadFinished() // above is about to be closed. We need to make sure we are no // longer using it. mAdapter.swapCursor(null); }
49
Exemplo
Como exemplo, aqui a implementao completa de um Fragment que apresenta um ListView com os resultados de uma consulta contra o provedor de contedo contatos. Ele usa um CursorLoader para gerenciar a consulta do fornecedor. Para uma aplicao para acessar os contatos de um usurio, como mostrado neste exemplo, o manifesto deve incluir a permisso READ_CONTACTS .
public static class CursorLoaderListFragment extends ListFragment implements OnQueryTextListener, LoaderManager.LoaderCallbacks<Cursor> { // This is the Adapter being used to display the list's data. SimpleCursorAdapter mAdapter; // If non-null, this is the current filter the user has provided. String mCurFilter; @Override public void onActivityCreated(Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); // Give some text to display if there is no data. In a real // application this would come from a resource. setEmptyText("No phone numbers"); // We have a menu item to show in action bar. setHasOptionsMenu(true); // Create an empty adapter we will use to display the loaded data. mAdapter = new SimpleCursorAdapter(getActivity(), android.R.layout.simple_list_item_2, null, new String[] { Contacts.DISPLAY_NAME, Contacts.CONTACT_STATUS }, new int[] { android.R.id.text1, android.R.id.text2 }, 0); setListAdapter(mAdapter); // Prepare the loader. Either re-connect with an existing one, // or start a new one. getLoaderManager().initLoader(0, null, this); } @Override public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { // Place an action bar item for searching. MenuItem item = menu.add("Search"); item.setIcon(android.R.drawable.ic_menu_search); item.setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM); SearchView sv = new SearchView(getActivity()); sv.setOnQueryTextListener(this); item.setActionView(sv); } public boolean onQueryTextChange(String newText) {
50
// Called when the action bar search text has changed. Update // the search filter, and restart the loader to do a new query // with this filter. mCurFilter = !TextUtils.isEmpty(newText) ? newText : null; getLoaderManager().restartLoader(0, null, this); return true; } @Override public boolean onQueryTextSubmit(String query) { // Don't care about this. return true; } @Override public void onListItemClick(ListView l, View v, int position, long id) { // Insert desired behavior here. Log.i("FragmentComplexList", "Item clicked: " + id); } // These are the Contacts rows that we will retrieve. static final String[] CONTACTS_SUMMARY_PROJECTION = new String[] { Contacts._ID, Contacts.DISPLAY_NAME, Contacts.CONTACT_STATUS, Contacts.CONTACT_PRESENCE, Contacts.PHOTO_ID, Contacts.LOOKUP_KEY, }; public Loader<Cursor> onCreateLoader(int id, Bundle args) { // This is called when a new Loader needs to be created. This // sample only has one Loader, so we don't care about the ID. // First, pick the base URI to use depending on whether we are // currently filtering. Uri baseUri; if (mCurFilter != null) { baseUri = Uri.withAppendedPath(Contacts.CONTENT_FILTER_URI, Uri.encode(mCurFilter)); } else { baseUri = Contacts.CONTENT_URI; } // Now create and return a CursorLoader that will take care of // creating a Cursor for the data being displayed. String select = "((" + Contacts.DISPLAY_NAME + " NOTNULL) AND (" + Contacts.HAS_PHONE_NUMBER + "=1) AND (" + Contacts.DISPLAY_NAME + " != '' ))"; return new CursorLoader(getActivity(), baseUri, CONTACTS_SUMMARY_PROJECTION, select, null, Contacts.DISPLAY_NAME + " COLLATE LOCALIZED ASC"); } public void onLoadFinished(Loader<Cursor> loader, Cursor data) { // Swap the new cursor in. (The framework will take care of closing the // old cursor once we return.) mAdapter.swapCursor(data); }
51
public void onLoaderReset(Loader<Cursor> loader) { // This is called when the last Cursor provided to onLoadFinished() // above is about to be closed. We need to make sure we are no // longer using it. mAdapter.swapCursor(null); } }
52
53
includas e excludas da pilha - inseridas na pilha quando iniciado pela atividade atual e retiradas quando o usurio deixa-as usando a tecla BACK. Como tal, a parte de trs da pilha funciona como uma estrutura de objetos "last in, first out". A Figura 1 mostra esse comportamento com uma linha do tempo mostrando o progresso entre as atividades junto com a atual pilha de volta em cada momento.
Figura 1. Uma representao de como cada nova atividade em uma tarefa adiciona um item na parte de trs da pilha. Quando o usurio pressiona a tecla BACK, a atividade atual destruda e volta atividade anterior.
Se o usurio continuar a pressionar BACK, ento cada atividade da pilha retirada para revelar a anterior, at que o usurio retorna tela inicial (ou de qualquer atividade que estava sendo executada quando a tarefa comeou). Quando todas as atividades so removidas da pilha, a tarefa no existe mais.
Figura 2. Duas tarefas tarefa esto no fundo, esperando para ser retomado, enquanto a Tarefa B recebe interao do usurio em primeiro plano.
54
Uma tarefa uma unidade coesa, que pode passar para o "background" quando os usurios comeam uma nova tarefa ou vo para a tela inicial, atravs da tecla HOME. Enquanto no fundo, todas as atividades na tarefa esto paradas, mas a pilha de volta para a tarefa permanece intacta, a tarefa simplesmente perdeu o foco enquanto outra tarefa se realiza como mostrado na figura 2. Uma tarefa pode, em seguida, voltar ao "primeiro plano" para que os usurios possam continuar de onde pararam. Suponha, por exemplo, que a tarefa atual (Tarefa A) tenha trs atividades em sua pilha e dois no mbito da atividade corrente. O usurio pressiona a tecla HOME, e em seguida, inicia uma nova aplicao a partir do lanador de aplicao. Quando a tela inicial aparece, uma tarefa vai para o fundo. Quando inicia o novo aplicativo, o sistema inicia uma tarefa para a aplicao (Tarefa B) com sua prpria pilha de atividades. Aps a interao com esse aplicativo, o usurio volta para HOME novamente e seleciona o aplicativo que originalmente comeou Tarefa A. Agora, a tarefa A vem para o primeiro plano - todas as trs atividades em sua pilha esto intactas e as atividades no topo da pilha so retomadas. Neste ponto, o usurio tambm pode voltar Tarefa B indo para a HOME e selecionando o cone do aplicativo que iniciou essa tarefa (ou tocando e segurando a tecla HOME para revelar as tarefas recentes e selecionando uma). Este um exemplo de multitarefa no Android. Nota: Vrias tarefas podem ser realizadas no fundo de uma vez. No entanto, se o usurio estiver executando muitas tarefas em segundo plano ao mesmo tempo, o sistema pode comear a destruir as atividades do fundo, a fim de recuperar a memria, fazendo com que os estados de atividade possam ser perdidos. Como as atividades na parte de trs da pilha nunca so reorganizadas, se seu aplicativo permite que usurios iniciem uma atividade especfica de mais de uma atividade, uma
55
nova instncia daquela atividade criada e colocada na pilha (ao invs de trazer qualquer instncia anterior da atividade para o topo). Como tal, uma atividade em seu aplicativo pode ser instanciada vrias vezes (mesmo de diferentes tarefas), como mostrado na figura 3. Como tal, se o usurio navega para trs usando a tecla BACK, cada instncia da atividade revelada na ordem em que foi aberta (cada um com seu estado prprio de UI). No entanto, voc pode modificar esse comportamento se voc no quer uma atividade a ser instanciada mais de uma vez. Para resumir o comportamento padro de atividades e tarefas: Quando a atividade A comea atividade B, uma atividade interrompida, mas o sistema mantm o seu estado (como a posio de rolagem e texto inseridos em formulrios). Se o usurio pressiona a tecla de volta, enquanto na Atividade B, a atividade A continua com o seu estado restaurado. Quando o usurio deixa uma tarefa, pressionando a tecla HOME, a atividade em curso interrompida e sua tarefa vai para o fundo. O sistema mantm o estado de cada atividade na tarefa. Se o usurio depois recomea a tarefa de selecionar o cone do lanador, que comeou a tarefa, ela vem para o primeiro plano e retoma a atividade no topo da pilha. Se o usurio pressionar a tecla BACK, a atividade atual removida da pilha e destruda. A atividade anterior na pilha retomada. Quando uma atividade destruda, o sistema no mantm atividade do Estado. As atividades podem ser instanciadas vrias vezes, at mesmo de outras tarefas.
56
informaes sobre o estado da atividade so perdidas. Se isso acontecer, o sistema ainda sabe que a atividade tem um lugar na parte de trs da pilha, mas quando a atividade trazida para o topo da pilha, o sistema deve recri-la (em vez de retom-la). A fim de evitar a perda do trabalho do usurio, voc deve mant-la de forma proativa atravs da aplicao do mtodo onSaveInstanceState() de retorno de sua atividade.
Gerenciando tarefas
A forma como o Android gerencia as tarefas e a pilha de volta, como descrito acima colocando todas as atividades que comearam sucessivamente na mesma tarefa e em uma pilha "last in, first out" - funciona muito bem para a maioria das aplicaes e voc no deve se preocupar em como suas atividades esto associadas a tarefas ou como eles existem na parte de trs da pilha. No entanto, voc pode decidir que voc deseja interromper o comportamento normal. Talvez voc queira uma atividade em seu aplicativo para iniciar uma nova tarefa quando iniciada (em vez de ser colocada dentro da tarefa atual), ou, quando voc comea uma atividade, que pretende apresentar uma instncia existente da mesma (em vez de criar uma nova instncia no topo da pilha de volta), ou, voc quer a sua pilha para ser limpas de todas as activitiesstart, com exceo para a atividade de raiz quando o usurio deixa a tarefa. Voc pode fazer essas coisas e mais, com atributos no manifesto da <activity> e com bandeiras de inteno que voc passa para startActivity(). Neste sentido, os principais atributos de <activity> que voc pode usar so: taskAffinity launchMode allowTaskReparenting clearTaskOnLaunch alwaysRetainTaskState finishOnTaskLaunch E as principais bandeiras de inteno voc pode usar so: FLAG_ACTIVITY_NEW_TASK FLAG_ACTIVITY_CLEAR_TOP FLAG_ACTIVITY_SINGLE_TOP ANDROID, uma viso geral Anderson Duarte de Amorim
57
Ateno: A maioria dos aplicativos no deve interromper o comportamento padro de atividades e tarefas. Se voc determinar que seja necessrio para a sua atividade modificar o comportamento padro, tenha cuidado e no se esquea de testar a usabilidade da atividade durante o lanamento e quando se navega de volta a ele de outras atividades e tarefas com a tecla BACK. Certifique-se de teste para os comportamentos de navegao que possam ser incompatveis com o comportamento esperado do usurio.
58
59
instncia existente de uma atividade lida com uma nova inteno, o usurio no poder pressionar a tecla Voltar para retornar ao estado da atividade antes da nova inteno chegaram a onNewIntent(). "singleTask" O sistema cria uma nova tarefa e instancia a atividade na raiz da nova tarefa. No entanto, se uma instncia da atividade j existe em uma tarefa separada, o sistema mapeia a inteno da instncia existente atravs de um convite sua onNewIntent(), ao invs de criar uma nova instncia. Apenas uma instncia da atividade pode existir ao mesmo tempo. Nota: Embora a atividade comee em uma nova tarefa, a tecla BACK ainda retorna o usurio para a atividade anterior. "singleInstance" . O mesmo que "singleTask", exceto que o sistema no inicia qualquer outra atividade para a tarefa, segurando a instncia. A atividade sempre e nico membro dessa tarefa; quaisquer atividades iniciadas por este abrem um em uma tarefa separada. Como outro exemplo, o navegador Android declara que a atividade do navegador web deve sempre aberta em sua prpria tarefa, especificando o modo de lanamento singleTask no elemento <activity>. Isto significa que, se o aplicativo emite a inteno de abrir o navegador do Android, a sua atividade no colocada na mesma tarefa que a sua aplicao. Em vez disso, ou uma nova tarefa para o navegador iniciada ou, se o navegador j tem uma tarefa em execuo em segundo plano, essa tarefa antecipada para lidar com a nova inteno. Independentemente de uma atividade ser iniciada em uma nova tarefa ou na mesma tarefa como a atividade que comeou, a tecla BACK sempre leva o usurio para a atividade anterior. Entretanto, se voc iniciar uma atividade de sua tarefa (Tarefa A), que especifica o modo de lanamento sendo singleTask, ento a atividade pode ter uma instancia em background que pertence a uma tarefa com a sua prpria pilha de volta (Tarefa B). Neste caso, quando a tarefa B antecipada para lidar com uma nova
60
inteno, a tecla BACK navega de volta atravs das atividades na tarefa B antes de retornar atividade do topo da tarefa A. Figura 4 visualiza este tipo de cenrio.
Figura 4. A representao de como uma atividade com o modo de lanar "singleTask" adicionada pilha de volta. Se a atividade j faz parte de uma tarefa em segundo plano com a sua prpria pilha de volta (Tarefa B), ento toda a volta da pilha tambm vem para a frente, em cima da tarefa atual (Tarefa A).
Nota: O comportamento que voc especificar para a sua atividade com a launchMode pode ser anulado por bandeiras includas com a inteno de iniciar a sua atividade, como discutido na prxima seo.
61
Isso produz o mesmo comportamento que a "singleTask", discutido na seo anterior. FLAG_ACTIVITY_SINGLE_TOP Se a atividade que est sendo iniciado a atividade atual (no topo da pilha de volta), ento a instncia existente recebe uma chamada para onNewIntent(), em vez de criar uma nova instncia da atividade. Isso produz o mesmo comportamento que a "singleTop", discutido na seo anterior. FLAG_ACTIVITY_CLEAR_TOP Se a atividade a ser iniciada j est em execuo na tarefa atual, ento ao invs de lanar uma nova instncia da atividade, todas as outras atividades em cima dela so destrudas e essa inteno entregue instncia retomada da atividade (agora no topo, atravs onNewIntent()). No h nenhum valor para o launchMode que produz esse comportamento. FLAG_ACTIVITY_CLEAR_TOP mais freqentemente utilizado em conjunto com FLAG_ACTIVITY_NEW_TASK. Quando usados em conjunto, essas bandeiras so uma maneira de localizar uma atividade existente em outra tarefa e coloc-la em uma posio onde ela pode responder inteno. Nota: Se o modo de lanamento da atividade designada "standard", ela tambm removida da pilha e uma nova instncia lanada em seu lugar para lidar com o intuito de entrada. Isso porque uma nova instncia sempre criada para uma nova inteno, quando a modalidade de lanamento "standard.
Manipulao de afinidades
A afinidade indica a qual tarefa uma atividade prefere pertencer. Por padro, todas as atividades da mesma aplicao tm afinidade entre si. Ento, por padro, todas as atividades no mesmo aplicativo preferem estar na mesma tarefa. No entanto, voc pode modificar o padro de afinidade para uma atividade. Atividades definidas em diferentes aplicaes podem compartilhar uma afinidade, ou atividades definidas no mesmo aplicativo podem ter diferentes afinidades de tarefas.
62
Voc pode modificar a afinidade de uma atividade especfica com o atributo taskAffinity do <activity> elemento. O atributo taskAffinity tem um valor de seqncia, que deve ser exclusivo do nome do pacote padro declarada no elemento <manifest>, porque o sistema usa esse nome para identificar a afinidade de tarefas padro para o aplicativo. A afinidade entra em jogo em duas circunstncias: Quando a inteno que inicia uma atividade contm
FLAG_ACTIVITY_NEW_TASK. o Uma nova atividade , por padro, lanada na tarefa da atividade que chamou startActivity(). empurrada para o topo da pilha do chamador. No entanto, se a inteno passada para startActivity() contm o
FLAG_ACTIVITY_NEW_TASK, o sistema procura por uma tarefa diferente para abrigar a nova atividade. Muitas vezes, uma nova tarefa. No entanto, ele no tem que ser. Se j existe uma tarefa, com a mesma afinidade que a nova atividade, a atividade lanada nessa tarefa. Se no, ele comea uma nova tarefa. o Se este sinalizador faz uma atividade para iniciar uma nova tarefa e que o usurio pressiona a tecla HOME para deix-lo, deve haver alguma maneira para o usurio navegar de volta para a tarefa. Algumas entidades (como o gerente de comunicao) sempre iniciam as atividades em uma tarefa externa, nunca como parte de si prpria, assim eles sempre colocam FLAG_ACTIVITY_NEW_TASK nas intenes para passar a startActivity(). Se voc tiver uma atividade que pode ser invocada por uma entidade externa que possa usar esta bandeira, tome cuidado para que o usurio tenha uma maneira independente para voltar para a tarefa que comeou como um cone do lanador (a atividade radicular da tarefa tem uma inteno de filtro CATEGORY_LAUNCHER). Quando uma atividade tem seu atributo allowTaskReparenting definido como "true". Neste caso, a atividade pode se mover da tarefa que comeou para a tarefa que tem afinidade, quando essa tarefa vem em primeiro plano.
63
Por exemplo, suponha que uma atividade que relata as condies meteorolgicas em cidades selecionadas definida como parte de um aplicativo de viagens. Ele tem a mesma afinidade como outras atividades na mesma aplicao (a afinidade aplicativo padro) e permite que re-parentalidade com esse atributo. Quando uma de suas atividades inicia a atividade de reportar o tempo, inicialmente pertencente mesma tarefa que a sua atividade. No entanto, quando a tarefa da aplicao de viagens volta ao primeiro plano, a atividade de reportar oo tempo designada para essa tarefa e exibida dentro dela. Dica: Se um arquivo .apk contiver mais de uma "aplicao" do usurio, voc provavelmente vai querer usar o atributo taskAffinity para atribuir diferentes afinidades para as atividades associadas a cada "pedido".
64
finishOnTaskLaunch Esse atributo como clearTaskOnLaunch, mas opera em uma nica atividade, no em uma tarefa inteira. Ela tambm pode fazer alguma atividade ir embora, incluindo a atividade de raiz. Quando definido como "true", a atividade continua a ser parte da tarefa apenas para a sesso atual. Se o usurio sai e depois volta para a tarefa, ela no est mais presente.
A inteno do filtro deste tipo faz um cone e uma legenda para a atividade a ser exibida na tela do menu, dando aos usurios uma maneira de iniciar a atividade e para retornar para a tarefa que ele cria em qualquer momento depois de ter sido lanado. Esta segunda habilidade importante: o usurio deve ser capaz de deixar uma tarefa e, em seguida, voltar a ela mais tarde com o lanador de atividade. Por esta razo, os dois modos de iniciar as atividades que marcam o incio, como sempre, uma tarefa, "singleTask" e " "singleInstance" , devem ser usados somente quando a atividade tem um filtro ACTION_MAIN e CATEGORY_LAUNCHER. Imagine, por exemplo, o que poderia acontecer se o filtro estiver faltando: Uma inteno lana uma atividade "singleTask", iniciando uma nova tarefa, e o usurio passa algum tempo a trabalhar nessa tarefa. O usurio pressiona o HOME. A tarefa agora enviada para o fundo e fica invisvel. Porque ele no representado na tela do aplicativo, o usurio no tem como voltar para a tarefa. Para os casos onde voc no deseja que o usurio seja capaz de retornar a uma atividade, defina o elemento de <activity>, finishOnTaskLaunch, para "true".
65
Servios
Um Service um componente da aplicao que pode executar operaes de longa durao em segundo plano e no oferece uma interface de usurio. Outro componente do aplicativo pode iniciar um servio e vai continuar a rodar em segundo plano, mesmo se o usurio muda para outro aplicativo. Alm disso, um componente pode se ligar a um servio para interagir com ele e at mesmo realizar a comunicao entre processos (IPC). Por exemplo, um servio pode lidar com as transaes de rede, tocar msica, executar I/O, ou interagir com um provedor de contedo, todos no fundo. Um servio pode essencialmente de duas formas: Iniciado Um servio "iniciado" quando um componente da aplicao (como uma atividade) inicia-o chamando startService(). Uma vez iniciado, o servio pode ser executado em segundo plano por tempo indeterminado, mesmo se o componente que o comeou destrudo. Normalmente, um servio iniciado executa uma nica operao e no retorna um resultado para o chamador. Por exemplo, pode fazer o download ou upload de um arquivo pela rede. Quando a operao feita, o servio deve parar. Ligado Um servio "ligado" quando um componente da aplicao liga-se a ele chamando bindService(). Um servio vinculado oferece uma interface clienteservidor que permite que os componentes interajam com o servio, enviar pedidos, obter resultados, e at mesmo faz-lo atravs de processos de comunicao entre processos (IPC). Um servio vinculado s executado enquanto outro componente de aplicao est vinculado a ele. Vrios componentes podem ligar para o servio de uma s vez, mas quando todos eles se desvinculam, o servio destrudo. Embora essa documentao geralmente aborda esses dois tipos de servios separadamente, o servio pode funcionar nos dois sentidos, ele pode ser iniciado (para rodar indefinidamente) e tambm permitir a ligao. simplesmente uma questo de
66
saber se voc implementa a dupla de mtodos: onStartCommand() para permitir ao os componentes inici-lo e onBind() para permitir a ligao. Independentemente de sua aplicao ser iniciada, ligada, ou ambos, qualquer componente de aplicativo pode usar o servio (mesmo a partir de um aplicativo separado), da mesma forma que qualquer componente pode usar uma atividade iniciando-a com uma Intent. No entanto, voc pode declarar o servio como privado, no arquivo de manifesto, e bloquear o acesso de outros aplicativos. Ateno: O servio executado no segmento principal de sua hospedagem, o servio de processo no cria seu prprio segmento e no executado em um processo separado (a menos que voc especifique o contrrio). Isso significa que, se o servio vai fazer todo o trabalho intensivo da CPU ou o bloqueio de operaes (como a reproduo de MP3 ou de rede), voc deve criar um novo segmento dentro do servio para fazer esse trabalho. Ao utilizar uma thread separada, voc vai reduzir o risco de erros como aplicao no responde (ANR) e o thread principal do aplicativo pode permanecer dedicado interao do usurio com suas atividades.
O bsico
Voc deve utilizar um servio ou um thread?
O servio simplesmente um componente que pode ser executado em segundo plano, mesmo quando o usurio no est interagindo com o aplicativo. Assim, voc deve criar um servio s para o que voc precisa. Se voc precisa realizar o trabalho fora de sua linha principal, mas apenas enquanto o usurio est interagindo com o aplicativo, ento voc deve, provavelmente, criar uma nova thread e no um servio. Por exemplo, se voc quiser tocar algumas msicas, mas apenas quando sua atividade est em execuo, voc pode criar uma lista de discusso em onCreate(), comear a utilizar em onStart() , e depois parar em onStop(). Tambm considere usar AsyncTask ou HandlerThread, em vez da tradicional classe Thread. Lembre-se que se voc usar um servio, ele ainda executado no
67
Para criar um servio, voc deve criar uma subclasse de Service (ou
thread principal do aplicativo por padro, ento voc deve ainda criar um novo segmento dentro do servio se executa operaes intensivas ou bloqueio.
uma de suas subclasses existentes). Em sua execuo, necessrio substituir alguns mtodos de callback para lidar com aspectos essenciais do ciclo de vida do servio e fornecer um mecanismo de componentes para ligar para o servio, se for o caso. Os mtodos mais importantes de retorno so: onStartCommand() O sistema chama este mtodo quando outro componente, como uma atividade, solicita que o servio seja iniciado, chamando startService(). Uma vez que este mtodo executado, o servio iniciado e pode rodar em segundo plano por tempo indeterminado. Se voc implementar essa, sua a responsabilidade parar o servio quando seu trabalho feito, chamando stopSelf() ou stopService(). (Se voc apenas quiser fornecer ligao, voc no precisa aplicar esse mtodo.) onBind() O sistema chama este mtodo quando um outro componente quer se vincular com o servio (por exemplo, executar RPC), chamando bindService(). Na implementao deste mtodo, voc deve fornecer uma interface que os clientes usam para se comunicar com o servio, retornando um IBinder. Voc sempre deve implementar este mtodo, mas se voc no quer permitir a ligao, ento voc deve retornar null. onCreate() O sistema chama este mtodo quando o servio criado, para executar os procedimentos de configurao (antes de chamar qualquer onStartCommand() ou onBind()). Se o servio j est em execuo, este mtodo no chamado. onDestroy() O sistema chama este mtodo quando o servio no mais usado e est sendo destrudo. Seu servio deve implementar isso para limpar quaisquer recursos, tais como threads, ouvintes registrados, receptores, etc. Esta a ltima chamada que o servio recebe. ANDROID, uma viso geral Anderson Duarte de Amorim
68
Se um componente inicia o servio chamando startService() (o que resulta em uma chamada para onStartCommand()), o servio continua funcionando at que ele pare com stopSelf() ou outro componente deixa-o chamando stopService(). Se um componente chama bindService() para criar o servio (e onStartCommand() no chamado), o servio funciona somente enquanto o componente est ligado a ele. Depois que o servio desvinculado de todos os clientes, o sistema se destri. O sistema Android fora a parada de um servio somente quando estiver com pouca memria e deve recuperar os recursos do sistema para a atividade que tem o foco do usurio. Se o servio est vinculado a uma atividade que tem o foco do usurio, ento menos provvel de ser morto, e se o servio declarado a ser executado no primeiro plano (discutido mais tarde), ento ele quase nunca vai ser morto. Caso contrrio, se o servio foi iniciado e est rodando h muito tempo, ento o sistema ir baixar a sua posio na lista de tarefas em segundo plano ao longo do tempo e o servio se tornar altamente suscetvel a matar-se - se o servio iniciado, ento voc deve projet-lo elegantemente para lanar reincio pelo sistema. Se o sistema mata o seu servio, ele reinicia logo que os recursos se tornam novamente disponveis (embora isso tambm dependa do valor que voc retornar do onStartCommand(), como ser discutido mais tarde).
Existem outros atributos que voc pode incluir no <service> para definir propriedades, como as permisses necessrias para iniciar o servio e o processo em que o servio deve ser executado.
69
Assim como uma atividade, um servio pode definir filtros que permitem a inteno de outros componentes para invocar o servio utilizando as intenes implcitas. Ao declarar a inteno de filtros, componentes de qualquer aplicativo instalados no aparelho do usurio podem, potencialmente, iniciar o seu servio se o servio de declarar a inteno de filtro que corresponde inteno outro aplicativo passa a startService() . Se voc planeja usar o seu servio apenas localmente (as outras aplicaes no o usam), ento voc no precisa (e no deve) prestar quaisquer filtros de inteno. Sem qualquer inteno de filtros, voc deve iniciar o servio usando uma inteno explcita dos nomes de classe do servio. Alm disso, voc pode garantir que seu servio seja privado, basta somente voc incluir o atributo android:exported e defini-lo como "false". eficaz mesmo se o servio fornece filtros de inteno.
startService(), resultando em uma chamada para o mtodo onStartCommand() do servio. Quando um servio iniciado, ele tem um ciclo de vida que independente do componente que comeou e o servio pode funcionar em segundo plano por tempo indeterminado, mesmo se o componente que o comeou destrudo. Como tal, o servio deve parar quando seu trabalho feito chamando stopSelf(), ou outro componente pode par-lo, chamando stopService().
onStartCommand() (no Android 2.0, onStart() foi depreciado em favor do onStartCommand()). Para obter mais informaes sobre a prestao de compatibilidade com
onStartCommand().
Um componente de aplicao, como uma atividade, pode iniciar o servio chamando startService() e passando uma Intent que especifica o servio e inclui todos os dados para o servio deve usar. O servio recebe essa Intent no mtodo onStartCommand().
70
Por exemplo, suponha que uma atividade precisa salvar alguns dados para um banco de dados on-line. A atividade pode iniciar um servio e entreg-lo para guardar os dados, passando a inteno de startService(). O servio recebe a inteno em
onStartCommand(), se conecta Internet e executa a operao de banco de dados. Quando a transao estiver concluda, o servio o pra e ele destrudo. Ateno: Um servio executa no mesmo processo do aplicativo no qual ele declarado e na thread principal da aplicao, por padro. Assim, se o servio realiza intensivo ou o bloqueio de operaes, enquanto o usurio interage com uma atividade a partir do mesmo aplicativo, o servio vai abrandar o desempenho da atividade. Para evitar afetar o desempenho do aplicativo, voc deve iniciar uma nova thread dentro do servio. Tradicionalmente, h duas classes que voc pode estender para criar um servio iniciado: Service Esta a classe base para todos os servios. Quando voc estender essa classe, importante que voc crie um novo segmento para fazer todo o trabalho, pois o servio usa a linha principal do aplicativo, por padro, o que poderia diminuir o desempenho de qualquer atividade de sua aplicao que est rodando. IntentService Esta uma subclasse de Service que utiliza um thread de trabalho para lidar com todos os pedidos de incio, um de cada vez. Esta a melhor opo se voc no exigir que o servio de lidar com vrias solicitaes em simultneo. Tudo que voc precisa fazer implementar onHandleIntent(), que recebe a inteno de cada solicitao de incio para que voc possa fazer o trabalho de fundo.
71
Cria um thread de trabalho padro que executa todas as intenes entregues ao onStartCommand() em separado do thread principal de sua aplicao. Cria uma fila de trabalho que passa uma inteno de cada vez para seu onHandleIntent() de execuo, para que no tenha que se preocupar com multithreading. Interrompe o servio, aps todos os pedidos de incio ter sido manipulados, ento voc nunca tem que chamar stopSelf(). Fornece implementao padro de onBind() que retorna nulo. Fornece uma implementao padro de onStartCommand() que envia a inteno da fila de trabalho e, em seguida, onHandleIntent() de execuo. Tudo isto se acrescenta ao fato de que tudo que voc precisa fazer implementar onHandleIntent() para fazer o trabalho fornecido pelo cliente. (Embora, voc tambm precisa fornecer um construtor pequeno para o servio). Aqui est um exemplo de implementao de IntentService :
public class HelloIntentService extends IntentService { /** * A constructor is required, and must call the super IntentService(String) * constructor with a name for the worker thread. */ public HelloIntentService() { super("HelloIntentService"); } /** * The IntentService calls this method from the default worker thread with * the intent that started the service. When this method returns, IntentService * stops the service, as appropriate. */ @Override protected void onHandleIntent(Intent intent) { // Normally we would do some work here, like download a file. // For our sample, we just sleep for 5 seconds. long endTime = System.currentTimeMillis() + 5*1000; while (System.currentTimeMillis() < endTime) { synchronized (this) { try { wait(endTime - System.currentTimeMillis()); } catch (Exception e) { }
72
} } } }
Isso tudo que voc precisa: um construtor e uma implementao de onHandleIntent(). Se voc decidir tambm substituir os mtodos de retorno de chamada, tais como onCreate(), onStartCommand(), ou onDestroy(), no se esquea de chamar a implementao de super, de modo que o IntentService possa lidar corretamente com a vida do thread. Por exemplo, onStartCommand() deve retornar a implementao padro (que como a inteno entregue a onHandleIntent()):
@Override public int onStartCommand(Intent intent, int flags, int startId) { Toast.makeText(this, "service starting", Toast.LENGTH_SHORT).show(); return super.onStartCommand(intent,flags,startId); }
Alm do onHandleIntent(), o nico mtodo a partir do qual voc no precisa chamar o super classe onBind() (mas voc s precisa implementar caso o servio permita a ligao).
73
super(looper); } @Override public void handleMessage(Message msg) { // Normally we would do some work here, like download a file. // For our sample, we just sleep for 5 seconds. long endTime = System.currentTimeMillis() + 5*1000; while (System.currentTimeMillis() < endTime) { synchronized (this) { try { wait(endTime - System.currentTimeMillis()); } catch (Exception e) { } } } // Stop the service using the startId, so that we don't stop // the service in the middle of handling another job stopSelf(msg.arg1); } } @Override public void onCreate() { // Start up the thread running the service. Note that we create a // separate thread because the service normally runs in the process's // main thread, which we don't want to block. We also make it // background priority so CPU-intensive work will not disrupt our UI. HandlerThread thread = new HandlerThread("ServiceStartArguments", Process.THREAD_PRIORITY_BACKGROUND); thread.start(); // Get the HandlerThread's Looper and use it for our Handler mServiceLooper = thread.getLooper(); mServiceHandler = new ServiceHandler(mServiceLooper); } @Override public int onStartCommand(Intent intent, int flags, int startId) { Toast.makeText(this, "service starting", Toast.LENGTH_SHORT).show(); // For each start request, send a message to start a job and deliver the // start ID so we know which request we're stopping when we finish the job Message msg = mServiceHandler.obtainMessage(); msg.arg1 = startId; mServiceHandler.sendMessage(msg); // If we get killed, after returning from here, restart return START_STICKY; } @Override public IBinder onBind(Intent intent) { // We don't provide binding, so return null return null; }
74
75
Como voc pode ver, d muito mais trabalho do que usar um IntentService. No entanto, como voc lida com cada chamada para onStartCommand() por si s, voc pode executar vrias solicitaes em simultneo. Isso no o que este exemplo faz, mas se isso que voc quer ento voc pode criar um novo tpico para cada pedido e execut-los imediatamente (em vez de aguardar a solicitao anterior para terminar). Observe que o mtodo onStartCommand() deve retornar um inteiro. O inteiro um valor que descreve como o sistema deve continuar o servio a partir do evento em que o sistema o mata (como discutido acima, a implementao padro para IntentService trata isso para voc, mas voc capaz de modific-lo). O valor de retorno de onStartCommand() deve ser uma das seguintes constantes: START_NOT_STICKY Se o sistema mata o servio aps onStartCommand() retornar, no recria o servio, salvo se houver pendncia de intenes para entregar. Esta a opo mais segura para evitar a execuo de seu servio quando no for necessrio e quando a sua aplicao pode simplesmente reiniciar os trabalhos inacabados. START_STICKY Se o sistema mata o servio aps onStartCommand() retornar, recria o servio e chamar onStartCommand(), mas no entrega novamente a ltima inteno. Em vez disso, o sistema chama onStartCommand() com uma inteno nula, a menos que houver pendncia de intenes para iniciar o servio, nesse caso, os propsitos so entregues. Isso adequado para media players (ou afins) que no esto executando comandos, mas rodam indefinidamente espera de uma interao. START_REDELIVER_INTENT Se o sistema mata o servio aps onStartCommand() retornar, recria o servio e chama onStartCommand() com a ltima inteno que foi entregue para o servio. Quaisquer intenes pendentes so entregues em troca. Isso adequado para os servios que esto ativamente realizando um trabalho que deve ser imediatamente reiniciado, como baixar um arquivo.
76
Iniciando um servio
Voc pode iniciar um servio de uma atividade ou componente de outro aplicativo por meio de um Intent (especificando o servio para iniciar) para startService(). O sistema Android chama o mtodo onStartCommand() do servio do e passa a Intent. (Voc nunca deve chamar onStartCommand() diretamente.) Por exemplo, uma atividade pode iniciar o servio de exemplo na seo anterior (HelloSevice) com a inteno explcita com startService():
Intent intent = new Intent(this, HelloService.class); startService(intent);
O startService() retorna imediatamente e o sistema Android chama o mtodo onStartCommand() do servio. Se o servio no estiver sendo executado, o sistema chama primeiro onCreate(), em seguida, chama onStartCommand(). Se o servio no prov ligao, a inteno entregue com startService() o nico modo de comunicao entre o componente de aplicao e o servio. No entanto, se voc quiser o servio para enviar um resultado de volta, o cliente que inicia o servio pode criar uma PendingIntent para uma transmisso (com getBroadcast()) e entreg-lo ao servio da Intent que inicia o servio. O servio pode ento usar a transmisso para fornecer um resultado. Vrios pedidos para iniciar o resultado do servio em vrias correspondncias chamam o onStartCommand() do servio. No entanto, apenas um pedido para parar o servio (com stopSelf() ou stopService()) necessrio.
Parando um servio
O servio iniciado deve gerenciar seu prprio ciclo de vida. Ou seja, o sistema no para ou destri o servio a menos que ele deva recuperar a memria do sistema e o servio continua a funcionar aps onStartCommand() retornar. Assim, o servio deve parar, chamando stopSelf() ou outro componente pode par-lo, chamando stopService(). Uma vez solicitado a parar com stopSelf() ou stopService(), o sistema destri o servio o mais rapidamente possvel. No entanto, se o servio trabalha com pedidos mltiplos para onStartCommand() ao mesmo tempo, ento voc no deve interromper o servio quando tiver terminado o ANDROID, uma viso geral Anderson Duarte de Amorim
77
processamento de um pedido inicial, porque voc pode ter uma vez recebido um pedido novo comeo (parando no final do primeiro pedido iria encerrar a segunda). Para evitar esse problema, voc pode usar stopSelf(int) para garantir que o seu pedido para parar o servio sempre baseado no incio pedido mais recente. Ou seja, quando voc chamar stopSelf(int), voc passa o ID do pedido inicial (o startId entregue para onStartCommand()) ao qual o pedido de parada corresponde. Ento, se o servio recebeu um pedido antes de voc fosse capaz de chamar stopSelf(int) , o ID no corresponder e o servio no vai parar. Ateno: importante que o aplicativo pare seus servios quando o trabalho est pronto, para evitar o desperdcio de recursos do sistema e consumo de bateria. Se necessrio, outros componentes podem interromper o servio pela chamada de stopService(). Mesmo se voc permitir chamada ao servio, voc deve sempre parar o servio a si mesmo se ele j recebeu uma chamada para onStartCommand().
78
seu servio deve retornar a partir do mtodo de retorno onBind(). Uma vez que o cliente recebe a IBinder , pode comear a interagir com o servio por meio dessa interface. Vrios clientes podem se ligar ao servio de uma s vez. Quando um cliente concluiu a interao com o servio, ele chama unbindService() para se desvincular. Uma vez que no h clientes vinculados ao servio, o sistema destri o servio.
79
Para solicitar que o servio seja executado em primeiro plano, chame startForeground(). Este mtodo tem dois parmetros: um nmero inteiro que identifica a notificao e a notificao na barra de status. Por exemplo:
Notification notification = new Notification(R.drawable.icon, getText(R.string.ticker_text), System.currentTimeMillis()); Intent notificationIntent = new Intent(this, ExampleActivity.class); PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, notificationIntent, 0); notification.setLatestEventInfo(this, getText(R.string.notification_title), getText(R.string.notification_message), pendingIntent); startForeground(ONGOING_NOTIFICATION, notification);
Para remover o servio do primeiro plano, chama-se stopForeground(). Este mtodo tem um valor booleano, indicando se deseja remover a notificao de barra de status tambm. Este mtodo no para o servio. No entanto, se voc parar o servio enquanto ele ainda est executando em primeiro plano a notificao tambm removida. Nota: Os mtodos startForeground() e stopForeground() foram introduzidos no Android 2.0 (API Nvel 5).
80
pode fechar a conexo chamando unbindService(). Vrios clientes podem chamar o mesmo servio e quando todos eles desvincularem-se, o sistema destri o servio. (O servio no precisa parar si mesmo). Estes dois caminhos no so totalmente distintos. Ou seja, voc pode chamar um servio que j foi iniciado com startService(). Por exemplo, um servio de msica de fundo pode ser iniciado chamando startService() com uma Intent que identifica a msica a tocar. Mais tarde, possivelmente quando o usurio deseja exercer algum controle sobre o player ou obter informaes sobre a msica atual, uma atividade pode se ligar ao servio chamando bindService(). Em casos como este, stopService() ou stopSelf() no chegam a parar o servio at que todos os clientes se desacoplem.
Figura 2. O ciclo de vida do servio. O diagrama esquerda mostra o ciclo de vida quando o servio criado com startService() e o diagrama da direita mostra o ciclo de vida quando o servio criado com bindService().
81
public class ExampleService extends Service { int mStartMode; // indicates how to behave if the service is killed IBinder mBinder; // interface for clients that bind boolean mAllowRebind; // indicates whether onRebind should be used @Override public void onCreate() { // The service is being created } @Override public int onStartCommand(Intent intent, int flags, int startId) { // The service is starting, due to a call to startService() return mStartMode; } @Override public IBinder onBind(Intent intent) { // A client is binding to the service with bindService() return mBinder; } @Override public boolean onUnbind(Intent intent) { // All clients have unbound with unbindService() return mAllowRebind; } @Override public void onRebind(Intent intent) { // A client is binding to the service with bindService(), // after onUnbind() has already been called } @Override public void onDestroy() { // The service is no longer used and is being destroyed } }
Nota: Ao contrrio mtodos de retorno do ciclo de vida da atividade, voc no obrigado a chamar a implementao da superclasse dos mtodos de callback. Ao implementar esses mtodos, voc pode controlar dois loops aninhados do ciclo de vida do servio: A vida inteira de um servio acontece entre o momento onCreate() ser chamado e o tempo onDestroy() retornado. Como uma atividade, um servio tem a sua configurao inicial em onCreate() e libera todos os recursos remanescentes em onDestroy(). Por exemplo, um servio de reproduo de msica pode criar o segmento onde a msica ser tocada em onCreate(), ento para a thread em onDestroy().
82
Os mtodos onCreate() e onDestroy() so chamados para todos os servios, sejam eles criados por startService() ou bindService() . A vida ativa de um servio comea com uma chamada de um onStartCommand() ou onBind(). Cada mtodo entrega a Intent que foi passado tanto startService() quanto bindService(), respectivamente. Se o servio for iniciado, o tempo de vida ativa termina ao mesmo tempo em que toda a vida termina (o servio continua ativo mesmo aps onStartCommand() retornar). Se o servio est vinculado, a vida ativa termina quando onUnbind() retorna. Nota: Apesar de um servio iniciado ser interrompido por uma chamada para uma stopSelf() ou stopService(), no h um retorno para o respectivo servio (no h onStop() de callback). Ento, a menos que o servio esteja vinculado a um cliente, o sistema destri quando o servio for interrompido, onDestroy() o retorno recebido apenas. A figura 2 ilustra os mtodos tpicos de retorno de um servio. Embora a figura separa os servios que so criados por startService() daquelas criadas pelos bindService() , tenha em mente que qualquer servio, no importa como ele iniciado, pode potencialmente permitir que os clientes chamem-no. Assim, um servio que foi inicialmente iniciado com onStartCommand() (por um cliente chamando startService() ) pode ainda receber uma chamada para onBind() (quando um cliente solicita bindService()).
83
Servios vinculados
Um servio vinculado o servidor em uma interface cliente-servidor. O servio permite que os componentes ligados (como em atividades) vinculem-se ao servio, enviem pedidos, recebam respostas, e at mesmo realizem a comunicao entre processos (IPC). Um servio ligado normalmente vive apenas enquanto ela serve a outro componente da aplicao e no executado em segundo plano por tempo indeterminado.
O bsico
Um servio ligado uma implementao Service que da permite classe que
outros aplicativos se liguem e interajam com ele. fornecer servio, implementar mtodo de ligao voc o para Para um deve onBind() Esse
retorno.
mtodo retorna um objeto IBinder que define a interface de programao podem que usar os para
clientes
permitir o servio a ser executado indefinidamente e tambm fornecer vnculo. Desta forma, uma atividade pode iniciar o servio para jogar alguma msica e a msica continua a tocar mesmo se o usurio sai do aplicativo. Ento, quando o usurio retorna para a aplicao, a atividade pode ligar para o servio para recuperar o controle da reproduo. Certifique-se de ler a seo sobre Gerenciamento do ciclo de vida de um servio vinculado, para obter mais informaes sobre o ciclo de vida do servio, quando for feita adio de ligao para um servio iniciado.
bindService(). Quando isso acontecer, ele deve fornecer uma implementao de que
ServiceConnection,
84
mas quando o sistema Android cria a conexo entre o cliente e o servio, ele chama onServiceConnected() na ServiceConnection para entregar o IBinder que o cliente pode usar para se comunicar com o servio. Vrios clientes podem se conectar ao servio de uma s vez. No entanto, o sistema chama o mtodo onBind() do servio para recuperar o IBinder somente quando o cliente liga-se em primeiro lugar. O sistema, em seguida, oferece os mesmos IBinder para quaisquer clientes que ligam, sem chamar onBind() novamente. Quando o libera ltimo cliente do servio, o sistema destri o servio (a menos que o servio tambm foi iniciado por startService() ). Quando voc implementar o seu servio vinculado, a parte mais importante definir a interface que o seu mtodo callback onBind() retorna. Existem algumas maneiras diferentes que voc pode definir o seu servio da interface IBinder e a seo a seguir discute cada tcnica.
85
Usando um Messenger Se voc precisa de sua interface para trabalhar em processos diferentes, voc pode criar uma interface para o servio com um Messenger. Desta forma, o servio define um Handler, que responde a diferentes tipos de mensagem de objetos. Este Handler a base para um Messenger que podem compartilhar um IBinder com o cliente, permitindo que o cliente envie comandos para o servio usando mensagem de objetos. Alm disso, o cliente pode definir um Messenger prprio para que o servio possa enviar mensagens de volta. Esta a maneira mais simples para realizar a comunicao entre processos (IPC), porque o Messenger enfilera todas as solicitaes em um nico segmento para que voc no tenha que projetar seu servio a ser um thread-safe. Usando AIDL AIDL (Android Interface Definition Language) realiza todo o trabalho de decompor os objetos primitivos em que o sistema operacional possa entender atravs de processos para executar IPC. A tcnica anterior, usando um Messenger, realmente baseado em AIDL como a sua estrutura subjacente. Como mencionado acima, o Messenger cria uma fila de todas as solicitaes do cliente em um nico segmento, para que o servio receba solicitaes de um de cada vez. Se, no entanto, voc quiser que o seu servio lide com mltiplas solicitaes ao mesmo tempo, ento voc pode usar AIDL diretamente. Neste caso, o servio deve ser capaz de multi-threading e ser construdo thread-safe. Para usar AIDL diretamente, voc deve criar uma arquivo .aidl que define a interface de programao. As ferramentas do Android SDK usam esse arquivo para gerar uma classe abstrata que implementa a interface e lida com o IPC, que voc pode estender dentro do seu servio. Nota: A maioria dos aplicativos no devem usar AIDL para criar um servio ligado, porque ele pode exigir recursos de multithreading e pode resultar em uma implementao mais complicada. Como tal, AIDL no adequado para a maioria das aplicaes e este documento no explica como us-lo para seu servio.
86
contm mtodos pblicos que o cliente pode chamar retorna o atual Service, que tem mtodos pblicos que o cliente pode chamar
ou, retorna uma instncia de outra classe hospedada pelo servio com mtodos pblicos que o cliente pode chamar
2. 3.
Retornar essa instncia do Binder do mtodo de retorno onBind(). No cliente, receber a Binder do mtodo de retorno onServiceConnected() e fazer chamadas para o servio vinculado usando os mtodos fornecidos.
Nota: A razo pela qual o servio e o cliente devem estar no mesmo pedido porque o cliente pode converter o objeto retornado e chamar propriamente de sua API. O servio e o cliente tambm devem estar no mesmo processo, porque essa tcnica no exerce qualquer triagem em todos os processos. Por exemplo, aqui est um servio que oferece aos clientes o acesso a mtodos no servio por meio de um Binder de execuo:
public class LocalService extends Service { // Binder given to clients private final IBinder mBinder = new LocalBinder(); // Random number generator private final Random mGenerator = new Random();
87
/** * Class used for the client Binder. Because we know this service always * runs in the same process as its clients, we don't need to deal with IPC. */ public class LocalBinder extends Binder { LocalService getService() { // Return this instance of LocalService so clients can call public methods return LocalService.this; } } @Override public IBinder onBind(Intent intent) { return mBinder; } /** method for clients */ public int getRandomNumber() { return mGenerator.nextInt(100); } }
O LocalBinder fornece o mtodo getService() de clientes para recuperar a instncia atual do LocalService. Isso permite aos clientes chamarem mtodos pblicos no servio. Por exemplo, os clientes podem chamar getRandomNumber() do servio. Aqui est uma atividade que se liga a LocalService e solicita getRandomNumber() quando um boto clicado:
public class BindingActivity extends Activity { LocalService mService; boolean mBound = false; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); } @Override protected void onStart() { super.onStart(); // Bind to LocalService Intent intent = new Intent(this, LocalService.class); bindService(intent, mConnection, Context.BIND_AUTO_CREATE); } @Override protected void onStop() { super.onStop(); // Unbind from the service if (mBound) {
88
unbindService(mConnection); mBound = false; } } /** Called when a button is clicked (the button in the layout file attaches to * this method with the android:onClick attribute) */ public void onButtonClick(View v) { if (mBound) { // Call a method from the LocalService. // However, if this call were something that might hang, then this request should // occur in a separate thread to avoid slowing down the activity performance. int num = mService.getRandomNumber(); Toast.makeText(this, "number: " + num, Toast.LENGTH_SHORT).show(); } } /** Defines callbacks for service binding, passed to bindService() */ private ServiceConnection mConnection = new ServiceConnection() { @Override public void onServiceConnected(ComponentName className, IBinder service) { // We've bound to LocalService, cast the IBinder and get LocalService instance LocalBinder binder = (LocalBinder) service; mService = binder.getService(); mBound = true; } @Override public void onServiceDisconnected(ComponentName arg0) { mBound = false; } }; }
O exemplo acima mostra como o cliente liga para o servio usando uma implementao do ServiceConnection e o callback de onServiceConnected(). Nota: O exemplo acima no explicitamente desvinculado do servio, mas todos os clientes devem desvincular em um tempo adequado (por exemplo, quando a atividade pausa).
89
Usando um Messenger
Se voc precisar de seu servio para se comunicar com processos remotos, ento voc pode usar um Messenger para fornecer a interface para o servio. Esta tcnica permite realizar a
Comparado com AIVD Quando voc precisa realizar IPC, utilizar um Messenger para a sua interface mais simples do que implement-la com AIDL, porque Messenger enfilera todas as chamadas para o servio, que, uma interface AIDL pura envia pedidos
comunicao entre processos (IPC), sem a necessidade de utilizar AIDL. Aqui est um resumo de como usar um Messenger: O servio implementa um
simultneos para o servio, que deve, ento, lidar com multi-threading. Para a maioria das aplicaes, o servio no precisa executar multi-threading, portanto, usar um Messenger permite ao servio lidar com uma chamada ao mesmo tempo. Se importante que o seu servio seja multi-threaded, ento voc deve usar AIDL para definir sua interface.
O Handler usado para criar uma Messenger (que uma referncia para o Handler). O Messenger cria um IBinder que o servio retorna para clientes de onBind(). Os clientes usam o IBinder para instanciar o Messenger (que faz referncia ao servio Handler), que o cliente usa para enviar mensagens para o servio. O servio recebe cada mensagem em seu Handler, especificamente, no mtodo handleMessage(). Desta forma, no existem "mtodos" para o cliente para chamar o servio. Em vez disso, o cliente fornece as "mensagens" (objetos Message) que o servio recebe em seu Handler. Aqui est um exemplo de servio simples que usa um Messenger interface:
public class MessengerService extends Service { /** Command to the service to display a message */ static final int MSG_SAY_HELLO = 1; /** * Handler of incoming messages from clients.
90
*/ class IncomingHandler extends Handler { @Override public void handleMessage(Message msg) { switch (msg.what) { case MSG_SAY_HELLO: Toast.makeText(getApplicationContext(), "hello!", Toast.LENGTH_SHORT).show(); break; default: super.handleMessage(msg); } } } /** * Target we publish for clients to send messages to IncomingHandler. */ final Messenger mMessenger = new Messenger(new IncomingHandler()); /** * When binding to the service, we return an interface to our messenger * for sending messages to the service. */ @Override public IBinder onBind(Intent intent) { Toast.makeText(getApplicationContext(), "binding", Toast.LENGTH_SHORT).show(); return mMessenger.getBinder(); } }
Observe que o mtodo handleMessage() no Handler onde o servio recebe a entrada Message e decide o que fazer, com base no membro what. Tudo o que um cliente precisa fazer criar um Messenger com base no IBinder retornado pelo servio e enviar uma mensagem usando o send(). Por exemplo, aqui uma atividade simples, que liga para o servio e oferece a mensagem MSG_SAY_HELLO para o servio:
public class ActivityMessenger extends Activity { /** Messenger for communicating with the service. */ Messenger mService = null; /** Flag indicating whether we have called bind on the service. */ boolean mBound; /** * Class for interacting with the main interface of the service. */ private ServiceConnection mConnection = new ServiceConnection() { public void onServiceConnected(ComponentName className, IBinder service) {
91
// This is called when the connection with the service has been // established, giving us the object we can use to // interact with the service. We are communicating with the // service using a Messenger, so here we get a client-side // representation of that from the raw IBinder object. mService = new Messenger(service); mBound = true; } public void onServiceDisconnected(ComponentName className) { // This is called when the connection with the service has been // unexpectedly disconnected -- that is, its process crashed. mService = null; mBound = false; } }; public void sayHello(View v) { if (!mBound) return; // Create and send a message to the service, using a supported 'what' value Message msg = Message.obtain(null, MessengerService.MSG_SAY_HELLO, 0, 0); try { mService.send(msg); } catch (RemoteException e) { e.printStackTrace(); } } @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); } @Override protected void onStart() { super.onStart(); // Bind to the service bindService(new Intent(this, MessengerService.class), mConnection, Context.BIND_AUTO_CREATE); } @Override protected void onStop() { super.onStop(); // Unbind from the service if (mBound) { unbindService(mConnection); mBound = false; } } }
92
Observe que este exemplo no mostra como o servio pode responder ao cliente. Se voc deseja que o servio responda, ento voc tambm precisa criar um Messenger no cliente. Ento, quando o cliente recebe a chamada onServiceConnected(), ele envia uma mensagem para o servio, que inclui o Messenger do cliente no parmetro replyTo d mtodo send(). Voc pode ver um exemplo de como fornecer mensagens bidirecionais no MessengerService.java (servio) e MessengerServiceActivities.java (cliente).
Vinculao a um servio
Componentes da aplicao (clientes) podem se ligar a um servio chamando bindService(). O sistema Android, em seguida, chama o servio de onBind(), mtodo que retorna um IBinder para interagir com o servio. A ligao assncrona, bindService() retorna imediatamente e no retorna a IBinder para o cliente. Para receber o IBinder, o cliente deve criar uma instncia de ServiceConnection e o passa para bindService(). O ServiceConnection inclui um mtodo de resposta que o sistema chama para entregar o IBinder. Nota: S as atividades, servios e provedores de contedo podem se ligar a um servio - voc no pode se ligar a um servio a partir de um receptor de broadcast. Assim, para ligar a um servio de seu cliente, voc deve: 1. Implementar ServiceConnection . A implementao deve substituir dois mtodos: onServiceConnected(): O sistema chama isso para entregar o IBinder retornado pelo mtodo onBind() do servio. onServiceDisconnected(): O sistema Android chama isso quando a conexo com o servio perdida inesperadamente, como quando o servio foi paralisada ou tenha sido morta. Isto no chamado quando o cliente libera. 2. Call bindService(), passando a implementao ServiceConnection.
93
3. Quando o sistema chama o mtodo de retorno onServiceConnected(), voc pode comear a fazer chamadas para o servio, utilizando os mtodos definidos pela interface. 4. Para desligar do servio, chame unbindService(). Quando o cliente for destrudo, ele ir desvincular-se do servio, mas voc deve sempre desvincular quando terminar a interao com o servio ou quando a atividade pausar, ento o servio pode parar enquanto no est sendo utilizado. Por exemplo, o seguinte trecho liga o cliente ao servio criado anteriormente por estender a classe Binder, ento tudo o que deve fazer o lanar o IBinder retornado ao LocalService e solicitar a LocalService:
LocalService mService; private ServiceConnection mConnection = new ServiceConnection() { // Called when the connection with the service is established public void onServiceConnected(ComponentName className, IBinder service) { // Because we have bound to an explicit // service that is running in our own process, we can // cast its IBinder to a concrete class and directly access it. LocalBinder binder = (LocalBinder) service; mService = binder.getService(); mBound = true; } // Called when the connection with the service disconnects unexpectedly public void onServiceDisconnected(ComponentName className) { Log.e(TAG, "onServiceDisconnected"); mBound = false; } };
Com este ServiceConnection, o cliente pode ligar para um servio, passando este para bindService(). Por exemplo:
Intent intent = new Intent(this, LocalService.class); bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
O primeiro parmetro de bindService() uma Intent que, explicitamente, nomeia o servio a ser vinculado (pensando que a inteno pode ser implcita). O segundo parmetro o objeto ServiceConnection. O terceiro parmetro um sinalizador que indica as opes para a ligao. Deve ser geralmente BIND_AUTO_CREATE, a fim de criar o servio se ainda no ANDROID, uma viso geral Anderson Duarte de Amorim
94
Notas adicionais
Aqui esto algumas anotaes importantes sobre a ligao a um servio: Voc deve sempre lanar excees DeadObjectException, que so lanados quando a conexo foi quebrada. Esta a nica exceo acionada por mtodos remotos. Os objetos so referncia contada atravs de processos. Voc normalmente dever emparelhar a ligao e desligamento durante a correspondente destruio e desmontagem de momentos do ciclo de vida do cliente. Por exemplo:
o
Se voc s precisa interagir com o servio, enquanto sua atividade visvel, voc deve se ligar durante onStart() e desvincular durante onStop().
Se voc quiser que a sua atividade receba as respostas, mesmo quando ele est parado no fundo, ento voc pode se ligar durante onCreate() e desvincular durante onDestroy(). Cuidado com o que isso implica que a sua atividade necessita para usar o servio durante todo o tempo ele est rodando (mesmo no fundo), por isso, se o servio est em outro processo, ento voc aumentar o peso do processo e torna-se mais provvel do sistema mat-lo.
Nota: Voc normalmente no deveria vincular e desvincular a sua atividade durante o onResume() e onPause(), porque esses retornos ocorrem em todas as transies do ciclo de vida e voc deve manter o processamento que ocorre nessas transies para um nvel mnimo. Alm disso, se h vrias atividades em sua aplicao para vincular o mesmo servio e no h uma transio entre duas dessas atividades, o servio pode ser destrudo e recriado como desassocia a atividade atual (durante a pausa) antes da prxima ligao (durante a retomada).
95
Quando um servio desvinculado de todos os clientes, o sistema Android o destri (a menos foi iniciado com onStartCommand()). Como tal, voc no tem que gerenciar o ciclo de vida do seu servio se ele meramente um limite de servio - o sistema Android gerencia isso para voc saber se ele est ligado a algum cliente. No entanto, se voc optar por implementar o mtodo de retorno onStartCommand(), ento voc deve explicitamente parar o servio, porque o servio considerado agora a
96
ser iniciado. Neste caso, o servio executado at que o servio para com stopSelf() ou outro componente chama stopService(), independentemente se est ligado a outros clientes. Alm disso, se o servio iniciado e aceita a ligao, ento quando o sistema solicita sua onUnbind(), voc pode opcionalmente retornar true se voc gostaria de receber uma chamada para onRebind() na prxima vez que um cliente chama o servio (ao invs de receber uma chamada para onBind()). onRebind() retorna void, mas o cliente ainda recebe o IBinder na sua onServiceConnected(). A figura 1 ilustra a lgica para este tipo de ciclo de vida.
97
Processos e threads
Quando um componente de aplicativo se inicia e a aplicao no possui nenhum outro componente rodando, o sistema Android inicia um novo processo Linux para a aplicao com um nico thread. Por padro, todos os componentes do mesmo aplicativo executam no mesmo processo e thread (chamada de thread "main"). Se um componente do aplicativo iniciado e j existe um processo para aquela aplicao (porque um outro componente do aplicativo existe), ento o componente iniciado dentro desse processo e usa o mesmo thread de execuo. No entanto, voc pode arranjar para diferentes componentes em seu aplicativo para serem executados em processos separados, e voc pode criar threads adicionais para qualquer processo.
Processos
Por padro, todos os componentes do mesmo aplicativo executam no mesmo processo e a maioria das aplicaes no devem mudar isso. No entanto, se voc achar que voc precisa controlar a que processo um determinado componente pertence, pode faz-lo no arquivo de manifesto. A entrada de manifesto para cada tipo de elemento - <activity>, <service , <receiver> e <provider> - suporta um atributo android:process que pode indicar um processo em que esse componente deve ser executado. Voc pode definir esse atributo para que cada componente seja executado em seu prprio processo, ou que algumas componentes compartilham um processo, enquanto outros no. Voc tambm pode definir android:process de modo que os componentes de diferentes aplicaes sejam executados no mesmo processo - desde que as aplicaes compartilhem o mesmo ID de usurio do Linux e assinem com os mesmos certificados. O elemento <application> tambm suporta um atributos android:process, para definir um valor padro que se aplica a todos os componentes. Android pode decidir encerrar um processo em algum momento, quando houver pouca memria e exigido por outros processos que esto mais imediatamente servindo ao usurio. Componentes de aplicativos em execuo no processo que est morto so conseqentemente destrudos. Um processo iniciado novamente para esses componentes, quando h trabalho novamente para que eles faam.
98
Ao decidir quais os processos matar, o sistema Android pesa a sua importncia relativa para o usurio. Por exemplo, mais facilmente desligado um processo hospedando atividades que no so mais visveis na tela, em comparao com um processo hospedando atividades visveis. A deciso de encerrar um processo, portanto, depende do estado dos componentes em execuo no processo.
99
pouca que ele no pode continuar rodando. Geralmente, nesse ponto, o dispositivo atingiu um estado de paginao de memria, ento, matar alguns processos de primeiro plano necessrio para manter a interface de usurio sensvel. 2. Processo Visvel Um processo que no tem nenhum componente de primeiro plano, mas ainda pode afetar o que o usurio v na tela. Um processo considerado visvel se qualquer uma das seguintes condies forem verdadeiras: Abriga uma Activity que no est em primeiro plano, mas ainda visvel para o usurio (seu mtodo onPause() foi chamado). Isso pode ocorrer, por exemplo, se a atividade iniciou um plano de dilogo, que permite que a atividade anterior possa ser vista por trs dele. Abriga um Service que est vinculado a uma atividade (ou plano) visvel. Um processo visvel considerado extremamente importante e no vai ser morto a menos que isso necessrio para manter todos os processos de primeiro plano em execuo. 3. Processo de servio Um processo que est executando um servio que foi iniciado com o mtodo startService() e no se enquadra em nenhuma das duas categorias acima. Embora os processos de servio no estejam diretamente ligados a qualquer coisa que o usurio v, eles esto geralmente fazendo coisas que o usurio se preocupa (como a reproduo de msica no fundo ou baixando arquivo na rede), ento o sistema os mantm rodando, a menos que no haja memria suficiente para retlos, juntamente com o primeiro plano e processos visveis. 4. Processo em segundo plano Um processo que mantm uma atividade que no visvel para o usurio no momento (o mtodo onStop() da atividade foi chamado). Esses processos no tm impacto direto sobre a experincia do usurio, e o sistema pode mat-los a qualquer momento para recuperar a memria para primeiro plano, visibilidade, ou processo de servio. Normalmente, h muitos processos em execuo no
100
fundo, ento eles so mantidos em uma LRU (menos recentemente usada), lista para garantir que o processo com a atividade que mais recentemente foi visto pelo usurio o ltimo a ser morto. Se uma atividade implementa mtodos de seu ciclo de vida corretamente, e salva o seu estado atual, matar o seu processo no ter um efeito visvel sobre a experincia do usurio, pois quando o usurio navega de volta para a atividade, a atividade restaura todo o seu estado visvel. 5. Processo vazio Um processo que no possui todos os componentes do aplicativo ativos. A nica razo para manter esse tipo de processo vivo para fins de armazenamento em cache, para melhorar o tempo de inicializao da prxima vez que um componente precisa ser executado. O sistema mata muitas vezes estes processos a fim de equilibrar os recursos do sistema global entre os caches do processo e os cachs do kernel subjacente. Android enfileira um processo ao mais alto nvel que pode, com base na importncia do componente ativo no processo. Por exemplo, se um processo hospeda um servio e uma atividade visvel, o processo classificado como um processo visvel, e no um processo de servio. Alm disso, o ranking de um processo pode ser acrescido, pois outros processos so dependentes dele - um processo que est servindo a outro processo nunca pode ser menor classificado do que o processo que est servindo. Por exemplo, se um provedor de contedo em um processo A est a servir um cliente no processo de B, ou se um servio em um processo A est ligado a um componente no processo de B, processo A sempre considerado pelo menos to importante como o processo B. Porque um processo executando um servio melhor classificado do que um processo com atividades em segundo plano, uma atividade que inicia uma operao de longa durao pode muito bem comear um servio para essa operao, ao invs de simplesmente criar uma thread de trabalhador - particularmente se a operao provavelmente durar mais que a atividade. Por exemplo, uma atividade que carrega uma foto em um site deve iniciar um servio para realizar o upload, ento o upload pode continuar em segundo plano, mesmo se o usurio deixar a atividade. Usar um servio garante que a operao ter, pelo menos, prioridade "no processo do servio",
101
independentemente do que acontece com a atividade. Este o mesmo motivo que os receptores de broadcast devem contratar servios ao invs de simplesmente colocar operaes demoradas em um thread.
Thread
Quando uma aplicao lanada, o sistema cria um thread de execuo para o aplicativo, chamado de "main". Esta thread muito importante, pois responsvel por despachar os eventos para os apropriados widgets de interface de usurio, incluindo eventos de desenho. tambm o segmento em que sua aplicao interage com os componentes da UI Toolkit Android (componentes da android.widget e pacotes android.view). Como tal, o thread principal chamado tambm s vezes de UI thread. O sistema no cria um thread separado para cada instncia de um componente. Todos os componentes que so executados no mesmo processo so instanciados no thread de interface do usurio e as chamadas do sistema para cada componente so despachadas a partir desse thread. Conseqentemente, os mtodos que respondem s callbacks do sistema (como onKeyDown() para relatar as aes do usurio ou um mtodo de retorno do ciclo de vida) sempre executam no thread da interface do usurio do processo. Por exemplo, quando o usurio toca um boto na tela, seu thread UI do aplicativo despacha o evento de toque para o widget, que por sua vez, define seu estado pressionado e lana uma requisio invlida para a fila de eventos. O thread UI desenfilera a requisio e notifica o widget que deve se redesenhar. Quando o aplicativo executa um trabalho intensivo em resposta interao do usurio, este nico thread pode produzir mal desempenho a menos que voc implemente a sua aplicao de forma adequada. Especificamente, se tudo est acontecendo no thread de interface do usurio, realizando longas operaes, tais como acesso rede ou consultas de banco de dados, ir bloquear a interface toda. Quando o thread est bloqueado, nenhum evento pode ser enviado, incluindo eventos de desenho. Do ponto de vista do usurio, o aplicativo parece travar. Pior ainda, se o segmento de interface do usurio estiver bloqueado por mais de alguns segundos (cerca de 5 segundos atualmente) ao usurio apresentado o abominvel "aplicativo no responde" (ANR). O usurio pode, ento, decidir abandonar a aplicao e desinstal-la se est infeliz.
102
Alm disso, o Andoid UI Toolkit no thread-safe. Ento, voc no deve manipular a sua interface a partir de um thread de trabalho - voc deve fazer toda a manipulao de sua interface a partir de um thread UI. Assim, existem apenas duas regras para o modelo de thread nica no Android: 1. 2. No bloquear o thread de UI No acessar o Android UI Toolkit de fora do thread UI
Threads funcionais
Devido ao modelo de thread nico acima descrito, vital para a capacidade de resposta da interface do usurio do seu aplicativo que voc no bloqueie o thread. Se voc tiver de realizar operaes que no so instantneas, voc deve certificar-se de faz-las em threads separados ("background" ou threads "worker"). Por exemplo, abaixo est um cdigo para um usurio que faz o download de uma imagem de um thread separado e exibida em uma ImageView:
public void onClick(View v) { new Thread(new Runnable() { public void run() { Bitmap b = loadImageFromNetwork("http://example.com/image.png"); mImageView.setImageBitmap(b); } }).start(); }
Em princpio, isso parece funcionar bem, porque cria uma nova thread para lidar com a operao da rede. No entanto, ele viola a segunda regra do modelo de nica thread: no acessar o Android UI Toolkit de fora da UI-thread - esta amostra modifica o ImageView do thread de trabalho em vez do thread UI. Isso pode resultar em um comportamento indefinido e inesperado, que pode ser difcil e demorado para rastrear. Para corrigir esse problema, o Android oferece vrias maneiras para acessar a thread de interface do usurio a partir de outros threads. Aqui est uma lista de mtodos que podem ajudar: Activity.runOnUiThread(Runnable) View.post(Runnable) View.postDelayed(Runnable, long)
103
Por
exemplo,
voc
pode
corrigir
cdigo
acima
usando
mtodo
View.post(Runnable):
public void onClick(View v) { new Thread(new Runnable() { public void run() { final Bitmap bitmap = loadImageFromNetwork("http://example.com/image.png"); mImageView.post(new Runnable() { public void run() { mImageView.setImageBitmap(bitmap); } }); } }).start(); }
Agora, essa implementao thread-safe: o funcionamento da rede feito a partir de um segmento separado, enquanto o ImageView manipulado a partir do thread de interface de usurio. No entanto, como a complexidade da operao cresce, este tipo de cdigo pode ser complicado e difcil de manter. Para lidar com interaes mais complexas com um thread de trabalho, voc pode considerar usar um Handler, para processar as mensagens entregues a partir do thread. Talvez a melhor soluo, porm, estender a classe AsyncTask, o que simplifica a execuo de tarefas do thread de trabalho que precisam interagir com a interface do usurio.
Usando AsyncTask
AsyncTask permite executar trabalho assncrono em sua interface com o usurio. Ela executa as operaes de bloqueio em um segmento de trabalho e, em seguida, publica os resultados no segmento de interface do usurio, sem que voc precise lidar com tpicos e/ou manipuladores de si mesmo. Para us-lo, voc deve incorporar AsyncTask e implementar o mtodo de retorno doInBackground(), que executado em um pool de threads de background. Para atualizar sua interface, voc deve implementar onPostExecute(), que fornece o resultado da doInBackground() e executado no thread da interface do usurio, assim voc pode escolher atualizar o UI. Voc pode ento executar a tarefa, chamando execute() do thread UI.
104
Por exemplo, voc pode implementar o exemplo anterior usando AsyncTask desta forma:
public void onClick(View v) { new DownloadImageTask().execute("http://example.com/image.png"); } private class DownloadImageTask extends AsyncTask<String, Void, Bitmap> { /** The system calls this to perform work in a worker thread and * delivers it the parameters given to AsyncTask.execute() */ protected Bitmap doInBackground(String... urls) { return loadImageFromNetwork(urls[0]); } /** The system calls this to perform work in the UI thread and delivers * the result from doInBackground() */ protected void onPostExecute(Bitmap result) { mImageView.setImageBitmap(result); } }
Agora a interface do usurio segura e o cdigo simples, porque separa o trabalho na parte que deve ser feita em um thread de trabalho e a parte que deve ser feita no thread de interface de usurio. Voc deve ler o AsyncTask de referncia para um entendimento completo de como usar essa classe, mas aqui est uma viso geral de como funciona: Voc pode especificar o tipo dos parmetros, os valores de progresso e o valor final da tarefa, usando genricos O mtodo doInBackground() executado automaticamente em um segmento de trabalho onPreExecute(), onPostExecute(), e onProgressUpdate() so invocados no thread de interface do usurio O valor retornado por doInBackground() enviado para onPostExecute() Voc pode chamar publishProgress() em qualquer outro momento do doInBackground() para executar onProgressUpdate() na thread da UI Voc pode cancelar a tarefa a qualquer hora, de qualquer thread Ateno: Outro problema que se pode encontrar ao usar um segmento de trabalho reincios inesperados na sua atividade devido a uma alterao de configurao em tempo de execuo (como quando o usurio muda a orientao da tela), que podem
105
destruir seu segmento de trabalho. Para ver como voc pode manter a sua tarefa durante um desses reincios e como fazer corretamente um cancelamento da tarefa quando a atividade for destruda, veja o cdigo fonte para o aplicativo de amostra da Prateleira.
Mtodos de Thread-safe
Em algumas situaes, os mtodos a implementar poderiam ser chamados de mais de um thread e, portanto, deve ser escrito para ser thread-safe. Isto principalmente verdadeiro para mtodos que podem ser chamados remotamente, como mtodos de um servio vinculado. Quando uma chamada de um mtodo implementado em um IBinder se origina no mesmo processo em que o IBinder est executando, o mtodo executado na thread de quem chamou. No entanto, quando a chamada originada em outro processo, o mtodo executado em um thread escolhido de um pool de threads que o sistema mantm no mesmo processo que o IBinder (no executado no thread da interface do usurio do processo). Por exemplo, considerando que um mtodo onBind() do servio seria chamado do de interface do usurio do processo de servio, mtodos implementados no objeto que onBind() retorna (por exemplo, uma subclasse que implementa mtodos RPC) seriam chamados threads no pool. Como um servio pode ter mais de um cliente, mais de uma pool de threads pode envolver o mesmo mtodo IBinder, ao mesmo tempo. Mtodos IBinder devem, portanto, ser implementadas para ser thread-safe. Da mesma forma, um provedor de contedo pode receber dados de pedidos que se originam em outros processos. Embora o ContentResolver e ContentProvider ocultam os detalhes de como a comunicao entre processos gerenciada, mtodos ContentProvider que respondem a esses pedidos - os mtodos query(), insert(), delete(), update(), e getType() so chamados a partir de um pool de threads no processo de provedor de contedo, e no o thread UI para o processo. Como esses mtodos podem ser chamados a partir de qualquer nmero de threads ao mesmo tempo, eles tambm devem ser implementados para ser thread-safe.
106
atividade ou um componente de outro aplicativo, mas executado remotamente (em outro processo), com qualquer resultado retornado de volta para o chamador. Isto implica a decomposio de uma chamada de mtodo e de seus dados a um nvel que o sistema operacional possa entender, transmiti-lo a partir do processo do processo local e espao de endereamento para o processo remoto e espao de endereo, em seguida, remontar e reencenar a chamada. Os valores de retorno so transmitidos na direo oposta. Android fornece todo o cdigo para executar essas operaes IPC, para que voc possa se concentrar na definio e implementao da interface de programao do RPC. Para executar o IPC, o aplicativo deve ligar para um servio, utilizando bindService().
107
Interface de usurio
Em um aplicativo do Android, a interface do usurio construda usando objetos View e ViewGroup. Existem muitos tipos de views e view groups, cada um dos quais um descendente da classe View. Objetos view so as unidades bsicas de expresso da interface do usurio na plataforma Android. A classe View serve como base para as subclasses chamadas de "widgets", que oferecem completa implementao de objetos de interface do usurio, como campos de texto e botes. A classe ViewGroup serve como base para as subclasses chamadas de "layouts", que oferecem diferentes tipos de layout de arquitetura, como a linear, tabular e relativa. Um objeto View uma estrutura de dados, cujas propriedades armazenam os parmetros de layout e de contedo para uma determinada rea retangular da tela. Um objeto View lida com sua prpria medida, layout, desenho, mudana de foco, scrolling e interaes telcla/gesto para a rea retangular da tela na qual ele reside. Como um objeto na interface do usurio, uma View tambm um ponto de interao para o usurio e o receptor de eventos de interao.
Hierarquia de view
Sobre a plataforma Android, voc define uma interface de atividades, usando uma hierarquia de view e ns ViewGroup, como mostrado no diagrama abaixo. Esta rvore de hierarquia pode ser to simples ou complexa como voc precisa que ela seja, e voc pode constru-la usando o conjunto do Android de widgets e layouts pr-definidos, ou com views customizados que voc mesmo cria.
108
A fim de fixar a rvore de hierarquia de views tela para renderizao, sua atividade deve chamar o mtodo setContentView() e passar uma referncia ao objeto n raiz. O sistema Android recebe esta referncia e usa-o para invalidar, medir e desenhar a rvore. O n raiz da hierarquia requisita que seus ns filhos desenhem a si prprios - por sua vez, cada n do ViewGroup responsvel por chamar cada um de seus views filhos para desenhar a si mesmos. Os filhos podem solicitar um tamanho e localizao com os pais, mas o objeto-me tem a deciso final sobre onde e qual o tamanho que cada criana pode ter. Android analisa os elementos do layout em ordem (a partir do topo da rvore de hierarquia), instanciando os Views e adicionando-os aos seus pais. Porque estes so desenhados em ordem, se h elementos que se sobrepem posies, o ltimo a ser elaborado vai ficar em cima dos outros previamente elaborados para aquele espao.
109
Desenhar o layout um processo de duas passagens: a passagem de medidas e uma passagem de layout. A passagem de medio implementada com measure(int, int) e uma passagem top-down da rvore. Cada view empurra as especificaes de dimenso para baixo na rvore durante a recursividade. No final da passagem de medidas, cada View tem armazenado suas medidas. A segunda fase acontece no layout(int, int, int, int) e tambm top-down. Durante o passar, cada pai responsvel pelo posicionamento de todos os seus filhos usando os tamanhos computados na passagem de medidas. Durante um mtodo de retorno measure() da view, os valores getMeasuredWidth() e getMeasuredHeight() devem ser definidos, juntamente com as de todos os descendentes da view. Os valores de medio de largura e altura da view devem respeitar as restries impostas pelos pais da view. Isso garante que, no final da passagem de medidas, todos os pais aceitam todas as medies de seus filhos. Um pai view pode chamar measure() mais de uma vez sobre seus filhos. Por exemplo, os pais podem medir cada filho uma vez com dimenses no especificadas para descobrir o quo grande eles querem ser, ento chama measure() neles novamente com nmeros reais, se a soma dos tamanhos dos filhos irrestrita muito grande ou muito pequena (Ou seja, se os filhos no concordam entre si a respeito de quanto espao cada um ganha, o pai vai intervir e estabelecer as regras na segunda passagem). A passagem de medidas utiliza duas classes para comunicar dimenses. A classe
Para dar incio a um esquema, chamase requestLayout(). Este mtodo
View.MeasureSpec usada por views para contar aos pais como eles querem ser medidos e posicionados. A classe base LayoutParams apenas descreve quo grandes as views querem
normalmente chamado por uma view sobre si mesma quando se acredita que possvel no caber mais dentro de seus limites atuais.
ser para a largura e altura. Para cada dimenso, pode especificar um dos seguintes: um nmero exato FILL_PARENT, o que significa que o view quer ser to grande quanto seu pai (menos padding) WRAP_CONTENT, o que significa que o view quer ser grande o suficiente para colocar o seu contedo (mais padding).
110
H subclasses de LayoutParams para diferentes subclasses de ViewGroup. Por exemplo, RelativeLayout tem a sua prpria subclasse de LayoutParams, que inclui a capacidade de centralizar os filhos horizontalmente e verticalmente. MeasureSpecs so usados para empurrar os requisitos para baixo da rvore de pai para filho. Um MeasureSpec pode estar em um dos trs modos: NO ESPECIFICADO: Isto usado por um dos pais para determinar a dimenso desejada de um filho View. Por exemplo, um LinearLayout pode chamar measure() em seu filho com a altura indefinida e uma largura de exatamente 240. EXATAMENTE: Este usado pelos pais para impor um tamanho exato sobre a criana. A criana deve usar esse tamanho, e garante que todos os seus descendentes se encaixem dentro desse tamanho. NO MXIMO: Este usado pelos pais para impor um tamanho mximo para a criana. A criana deve garantir que ele e todos os seus descendentes vo caber dentro deste tamanho.
Layout
A maneira mais comum para definir o seu layout e expressar a hierarquia de view com um arquivo de layout XML. XML oferece uma estrutura legvel para o layout, muito parecido com HTML. Cada elemento em XML ou um View ou ViewGroup (ou descendentes dos mesmos). Objetos view so folhas da rvore, objetos ViewGroup so ramos da rvore. O nome de um elemento XML respectivo para a classe Java que representa. Assim, um elemento <TextView> cria um na sua interface do usurio, e um elemento <LinearLayout> cria um ViewGroup. Quando voc carregar um recurso de layout, o sistema Android inicializa esses objetos em tempo de execuo, correspondentes aos elementos em seu layout. Por exemplo, um layout simples vertical, com um text view e um boto parece com este:
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent"
111
android:layout_height="fill_parent" android:orientation="vertical" > <TextView android:id="@+id/text" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Hello, I am a TextView" /> <Button android:id="@+id/button" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Hello, I am a Button" /> </LinearLayout>
Observe que o elemento LinearLayout contm o TextView e o Boto. Voc pode aninhar outro LinearLayout (ou outro tipo de grupo de exibio) aqui dentro, para alongar a hierarquia de view e criar um layout mais complexo. Dica: Voc tambm pode desenhar View e ViewGroups em cdigo Java, utilizando mtodos para inserir dinamicamente novos objetos View e ViewGroup. H uma variedade de maneiras em que voc pode formatar os seus view. Usando mais tipos diferentes de grupos de exibio, voc pode estruturar views herdados e view groups em um nmero infinito de maneiras. Alguns view groups pr-definidos oferecidas pelo Android (chamando layouts) incluem LinearLayout, RelativeLayout, TableLayout, GridLayout e outros. Cada um oferece um conjunto exclusivo de parmetros de layout que so usados para definir as posies das views herdadas e a estrutura de layout. To learn about some of the different kinds of view groups used for a layout, read . Para saber mais sobre alguns dos diferentes tipos de grupos de vista usado para um layout, leia os objetos de layout comum .
Widgets
Um widget um objeto View que serve como uma interface de interao com o usurio. Android fornece um conjunto de widgets plenamente implementadas, como botes, caixas de seleo, e os campos de entrada de texto, assim voc pode construir rapidamente sua interface do usurio. Alguns widgets fornecidos pelo Android so mais complexos, como um selecionador de data, um relgio, e controles de zoom. Mas voc no est limitado aos tipos de elementos fornecidos pela plataforma Android. Se voc quiser fazer algo mais personalizado e criar seus prprios elementos, pode, atravs da
112
definio de seu objeto View prprio ou atravs da extenso e combinao de elementos existentes.
113
Eventos UI
Uma vez que voc adicionou alguns views/widgets para a interface do usurio, voc provavelmente quer saber sobre a interao do usurio com eles, para que voc possa executar aes. Para ser informado de eventos de interface, voc precisa fazer uma de duas coisas: Definir um receptor de evento e registr-lo com a view. Muitas vezes, assim que voc vai receber os eventos. A classe View contm uma coleo de interfaces aninhadas nomeadas <something> Listener, cada um com um mtodo de retorno de chamada On <something>(). Por exemplo, View.OnClickListener (para lidar com os "cliques" na View), View.OnTouchListener (para lidar com eventos de tela de toque em uma exibio), e View.OnKeyListener (para lidar com teclas pressionadas no dispositivo dentro de uma View). Ento se voc quer sua View para ser notificado quando ela "clicada" (como quando um boto selecionado), implemente OnClickListener e defina o seu mtodo de retorno onClick() (onde voc executar a ao aps o clique), e registra-o para a View com setOnClickListener(). Substituir um mtodo de retorno existente para a View. Isto o que voc deve fazer quando voc implementou sua prpria classe View e quer receber eventos especficos que ocorrem dentro dele. Exemplificando eventos voc pode manipular incluso quando a tela tocada (onTouchEvent()), quando o trackball movido (onTrackballEvent()), ou quando uma tecla no dispositivo pressionada (onKeyDown()). Isso permite que voc defina o comportamento padro para cada evento dentro da sua View personalizada e determinar se o evento deve ser transmitido para alguma outra View filho. Novamente, essas so chamadas de retorno para a classe View, assim, sua nica chance de defini-los quando voc cria um componente personalizado.
Menus
Os menus de aplicativos so outra parte importante da interface do usurio de um aplicativo. Menus oferecem uma interface confivel, que revela funes de aplicativos e configuraes. O menu de aplicativos mais comuns revelado, pressionando a tecla MENU no dispositivo. No entanto, voc tambm pode adicionar menus de contexto,
114
que podem ser revelados quando o usurio pressiona e mantm pressionado em um item. Os menus tambm so estruturados usando uma hierarquia View, mas voc no define essa estrutura por si mesmo. Em vez disso, voc define mtodos de retorno como onCreateOptionsMenu() ou onCreateContextMenu() para a sua atividade, e declara os itens que voc deseja incluir em seu menu. Em momento oportuno, o Android ir criar automaticamente a necessria hierarquia View para o menu e desenhar cada um dos seus itens de menu na mesma. Menus tambm lidam com seus prprios eventos, por isso no h necessidade de registrar eventos listeners sobre os itens do seu menu. Quando um item no seu menu selecionado, o mtodo onOptionsItemSelected() ou onContextItemSelected() ser chamado pelo framework. E, assim como o layout do aplicativo, voc tem a opo de declarar os itens para seu menu em um arquivo XML.
Tpicos Avanados
Uma vez que voc aprendeu os fundamentos da criao de uma interface, voc pode explorar algumas caractersticas avanadas para a criao de uma interface de aplicao mais complexa.
Adaptadores
s vezes voc deseja preencher um view group com algumas informaes que no podem ser codificados, em vez disso, voc quer associar a sua view a uma fonte externa de dados. Para fazer isso, use um AdapterView como seu grupo de viso e cada filho view inicializado e preenchido com os dados do adaptador. O objeto AdapterView uma implementao do ViewGroup que determina as views dos filhos com base em um determinado adaptador. O adaptador funciona como um mensageiro entre a fonte de dados (talvez um array de strings externa) e os AdapterView, que exibe. Existem vrias implementaes da classe Adapter, para tarefas especficas, como a CursorAdapter para leitura de dados banco de dados de um cursor ou um ArrayAdapter para a leitura de uma matriz arbitrria.
115
Estilos e Temas
Talvez voc no esteja satisfeito com a aparncia dos widgets padro. Para rev-los, voc pode criar alguns dos seus prprios estilos e temas. Um estilo um conjunto de um ou mais atributos de formatao que voc pode aplicar como uma unidade de elementos individuais em seu layout. Por exemplo, voc pode definir um estilo que especifica um determinado tamanho de texto e cor, em seguida, aplic-lo apenas a elementos especficos. Um tema um conjunto de um ou mais atributos de formatao que voc pode aplicar como uma unidade para todas as atividades em uma aplicao, ou apenas uma atividade nica. Por exemplo, voc pode definir um tema que define as cores especficas para a moldura da janela e o fundo do painel, e define o tamanho dos textos e cores dos menus. Este tema pode ser aplicado a atividades especficas ou todo o aplicativo. Estilos e temas so recursos. Android oferece alguns recursos de estilo padro e tema que voc pode usar, ou voc pode declarar o seu prprio estilo customizado e recursos de tema.
116
Declarando Layout
Seu layout a arquitetura para interface de usurio em uma atividade. Ela define a estrutura de layout e possui todos os elementos que aparecem para o usurio. Voc pode declarar o seu layout de duas maneiras: Declare elementos UI em XML - Android fornece um vocabulrio XML simples que corresponde s classes View e subclasses, tais como widgets e layouts. Instanciar elementos de layout em tempo de execuo - O aplicativo pode criar objetos de View e ViewGroup (e manipular suas propriedades) de forma programaticamente. O framework Android lhe d a flexibilidade para usar um ou ambos os mtodos para declarar e gerenciar a interface do usurio do seu aplicativo. Por exemplo, voc poderia declarar layouts padro de seu aplicativo em XML, incluindo os elementos da tela que aparecero nela e suas propriedades. Voc pode ento adicionar o cdigo em seu aplicativo que iria alterar o estado dos objetos da tela, incluindo aqueles declarados em XML, em tempo de execuo. A vantagem de declarar a sua interface em XML que ela permite melhor separar a apresentao da sua aplicao do cdigo que controla o seu comportamento. Suas descries de interface do usurio so externas sua aplicao, o que significa que voc pode modific-lo ou adapt-lo sem ter que modificar seu cdigofonte e recompilar. Por exemplo, voc pode criar layouts de tela de XML para
O plugin ADT para Eclipse oferece um preview do seu layout XML - com o arquivo XML aberto, selecione a guia Layout. Voc tambm deve tentar a ferramenta de Hierarquia Viewer para depurao de layouts ela revela propriedade de layout, desenha wireframes e com view indicadores completas
padding/margin
renderizadas enquanto voc depurar no emulador ou dispositivo. A ferramenta layoutopt permite analisar rapidamente os seus layouts e hierarquias de ineficincias ou outros problemas.
diferentes, tela do
tamanhos e
lnguas
diferentes.
Alm disso, declarar o layout em XML torna mais fcil visualizar a estrutura de sua
117
interface do usurio, por isso mais fcil depurar problemas. Como tal, este documento centra-se em ensin-lo a declarar o seu layout em XML. Se voc estiver interessado em instanciar objetos view em tempo de execuo, consulte as classes ViewGroup e View. Em geral, o vocabulrio XML para a declarao de elementos da interface segue de perto a estrutura e nomenclatura das classes e mtodos, onde os nomes dos elementos correspondem aos nomes de classes e nomes de atributos correspondem aos mtodos. De fato, a correspondncia muitas vezes to direta que voc pode adivinhar o atributo XML corresponde a um mtodo de classe, ou adivinhar o que a classe corresponde a um determinado elemento XML. No entanto, note que nem todo vocabulrio idntico. Em alguns casos, existem ligeiras diferenas de nomenclatura. Por exemplo, o elemento EditText tem um atributo text que corresponde a EditText.setText() . Dica: Saiba mais sobre os diferentes tipos de layout em Common Layout Objects.
Escreve o XML
Usando o vocabulrio do Android XML, voc pode rapidamente criar layouts de interface do usurio e os elementos de tela que eles contm, da mesma forma que voc cria pginas web em HTML - com uma srie de elementos aninhados. Cada arquivo de layout deve conter exatamente um elemento de raiz, que deve ser um objeto de view ou ViewGroup. Depois de definir o elemento raiz, voc pode adicionar objetos de layout adicionais ou widgets como elementos filho para criar gradualmente uma hierarquia de exibio que define o layout. Por exemplo, aqui est um esquema XML que usa um LinearLayout vertical que contm um TextView e um Button :
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent" android:orientation="vertical" > <TextView android:id="@+id/text" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Hello, I am a TextView" /> <Button android:id="@+id/button" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Hello, I am a Button" /> </LinearLayout>
118
Depois de ter declarado o seu layout em XML, salve o arquivo com a extenso .xml em seu projeto Android no diretrio res/layout/, assim ele vai compilar corretamente.
O mtodo de retorno onCreate() em sua atividade chamado pelo framework Android quando sua atividade lanada.
Atributos
Cada objeto View e ViewGroup apia a sua prpria variedade de atributos XML. Alguns atributos so especficos para um objeto View (por exemplo, TextView apia o atributo textSize), mas esses atributos tambm so herdadas por qualquer objetos View que podem estender esta classe. Alguns so comuns a todos objetos View, porque eles so herdados da classe View raiz (como o atributo id). E, outros atributos so considerados "parmetros de layout", que so atributos que descrevem determinadas orientaes de layout do objeto View.
ID
Qualquer objeto View pode ter um ID de inteiro associado a ele, para identificar o View dentro da rvore. Quando o aplicativo compilado, essa identificao referenciada como um inteiro, mas a identificao normalmente atribuda no layout do arquivo XML como uma string, no atributo id. Este um atributo XML comum a todos os objetos View (definido pela classe View) e voc vai us-lo muitas vezes. A sintaxe para uma identificao, dentro de uma tag XML :
119
android:id="@+id/my_button"
O smbolo de arroba (@) no incio da string indica que o analisador XML deve analisar e ampliar o resto da seqncia de identificao e identific-lo como um recurso de identificao. O sinal de mais (+) significa que este um novo nome de recurso que deve ser criado e adicionado aos nossos recursos (no arquivo R.java). H uma srie de recursos de outro tipo de identificao que so oferecidos pela estrutura do Android. Ao fazer referncia a uma identificao de recurso Android, voc no precisa do sinal de mais, mas deve adicionar o namespace de pacote android, assim:
android:id="@android:id/empty"
Com o namespace de pacote android no lugar, agora estamos fazendo referncia a uma ID da classe de recursos android.R, ao invs da classe de recursos locais. A fim de criar views e referenci-los a partir da aplicao, um padro comum : 1. Definir uma view/widget no arquivo de layout e atribuir um ID nico:
<Button android:id="@+id/my_button" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/my_button_text"/>
2. Em seguida, crie uma instncia do objeto view e capture-o a partir do layout (geralmente no mtodo onCreate()):
Button myButton = (Button) findViewById(R.id.my_button);
Definir os IDs dos objetos view importante ao criar um RelativeLayout. Em um RelativeLayout, views irmos podem definir a sua disposio em relao a outro view irmo, que referenciada pela ID exclusiva. Uma identificao no precisa ser nica para toda a rvore, mas deve ser exclusiva dentro da parte da rvore que voc est procurando (o que pode muitas vezes ser a rvore inteira, por isso melhor ser completamente original quando possvel).
Parmetros de layout
Atributos de layout XML chamados layout_something definem os parmetros de layout para a view que sejam adequadas para a ViewGroup em que ele reside.
120
Cada
classe
ViewGroup
implementa
uma
classe
aninhada
que
estende
ViewGroup.LayoutParams. Esta subclasse contm os tipos de propriedades que definem o tamanho e a posio de cada view filha, conforme apropriado para o view group. Como voc pode ver na figura 1, o grupo de exibio pai define os parmetros de layout para cada view filho (incluindo o view group dos filhos).
Figura 1. Visualizao de uma hierarquia de views com os parmetros de layout associado a cada exibio.
Note que cada subclasse LayoutParams tem sua prpria sintaxe para definir valores. Cada elemento filho deve definir LayoutParams que so apropriadas para seu pai, embora possa tambm definir LayoutParams diferentes para seus filhos. Todos os view groups incluem uma largura e altura (layout_width e layout_height), e cada view necessria para defini-los. Muitos LayoutParams tambm incluem margens opcional e fronteiras. Voc pode especificar a largura e altura com medidas exatas, embora voc provavelmente no ir querer fazer isso com freqncia. Mais freqentemente, voc vai usar uma dessas constantes para definir a largura ou altura: wrap_content diz a seu view a arranjar a si prprio para as dimenses exigidas pelo seu contedo.
121
fill_parent (rebatizada match_parent na API Nvel 8) diz sua view para se tornar to grande quanto o view group dos pais ir permitir. Em geral, especificar uma largura de layout e altura, utilizando unidades absolutas, tais como pixels no recomendada. Em vez disso, por meio de medidas como a densidade relativa independente unidades de pixel (DP), wrap_content ou fill_parent, uma abordagem melhor, porque ajuda a garantir que seu aplicativo ir exibir corretamente atravs de uma variedade de tamanhos de tela do dispositivo. Os tipos de medio aceitos so definidos no documento Recursos Disponveis.
Posio de Layout
A geometria de uma view a de um retngulo. Uma view tem uma localizao, expresso como um par de coordenadas esquerda e superior, e duas dimenses, expressa em uma largura e uma altura. A unidade para a localizao e as dimenses o pixel. possvel recuperar o local de uma viso chamando os mtodos getLeft() e getTop(). O primeiro retorna a esquerda, ou X, de coordenadas do retngulo que representa o view. O segundo retorna o topo, ou Y, coordenadas do retngulo que representa o view. Estes dois mtodos devolvem o local da view em relao ao seu pai. Por exemplo, quando o Getleft() retorna 20, significa que o ponto de vista est localizado a 20 pixels para a direita da borda esquerda da sua controladora direta. Alm disso, vrios mtodos de convenincia so oferecidos para evitar clculos desnecessrios, ou seja, getRight() e getBottom(). Esses mtodos retornam as coordenadas das bordas direita e inferior do retngulo que representa o view. Por exemplo, chamando getRight() semelhante ao seguinte clculo: getLeft() + getWidth().
122
O segundo par conhecido simplesmente como largura e altura, ou s vezes a largura de desenho e altura de desenho. Essas dimenses definem o tamanho real do view sobre tela, em tempo de desenho e depois de layout. Esses valores podem ser, mas no tem que ser diferentes da largura e altura medidos. A largura e altura podem ser obtidas chamando getWidth() e getHeight(). Para medir as suas dimenses, uma view leva em conta o seu preenchimento. O preenchimento expresso em pixels para as partes esquerda, superior, direita e inferior do view. Padding pode ser utilizado para compensar o contedo da viso de uma determinada quantidade de pixels. Por exemplo, um padding-left de 2 vai empurrar o contedo do view por 2 pixels direita da margem esquerda. Padding pode ser definido usando o mtodo setPadding(int, int, int, int) e consultado chamando getPaddingLeft(), getPaddingTop(), getPaddingRight() e getPaddingBottom(). Apesar de uma exibio poder definir um padding, isso no prev qualquer apoio para as margens. No entanto, view groups prestam esse apoio.
123
Criando Menus
Os menus so uma parte importante da interface de uma atividade do usurio, que fornecem aos usurios uma forma familiar para executar aes. Android oferece um quadro simples para voc adicionar menus padro para seu aplicativo. Existem trs tipos de menus de aplicao:
Menu de Opes
A coleo de itens do menu principal para uma atividade, que aparece quando o usurio toca no boto MENU. Quando o aplicativo est rodando o Android 3.0 ou posterior, voc pode fornecer acesso rpido para selecionar itens de menu, colocando-os diretamente na barra de ao, como "itens de ao."
Menu de Contexto
Uma lista de itens de menu flutuante que aparece quando o usurio toca e tem uma viso que est registrada para fornecer um menu de contexto.
Submenu
Uma lista de itens de menu flutuante que aparece quando o usurio toca um item de menu que contm um menu aninhado.
124
<menu> deve ser o n raiz para o arquivo e pode conter um ou mais <item> e elementos <group>. <item> Cria um MenuItem, o que representa um nico item em um menu. Este elemento pode conter um elemento <menu> aninhado, a fim de criar um submenu. <group> Um opcional, recipiente invisvel para elementos <item>. Ele permite que voc categorize itens de menu para que compartilhe as propriedades tais como estado ativo e visibilidade. Aqui est um exemplo de menu chamado game_menu.xml:
<?xml version="1.0" encoding="utf-8"?> <menu xmlns:android="http://schemas.android.com/apk/res/android"> <item android:id="@+id/new_game" android:icon="@drawable/ic_new_game" android:title="@string/new_game" /> <item android:id="@+id/help" android:icon="@drawable/ic_help" android:title="@string/help" /> </menu>
Este exemplo define um menu com dois itens. Cada item inclui os atributos: android:id A identificao do recurso que nico para o item, que permite que o aplicativo possa reconhecer o item quando o usurio seleciona-o. android:icon Uma referncia para um desenho para usar como cone do item. android:title Uma referncia a uma string para usar como ttulo do item.
125
H muito mais atributos que voc pode incluir em um <item>, incluindo alguns que especificam como o item pode aparecer na barra de ao.
O mtodo getMenuInflater() retorna uma MenuInflater para a atividade. Com este objetivo, voc pode chamar inflate(),que infla um recurso de menu em um objeto Menu. Neste exemplo, o recurso de menu definido por game_menu.xml inflado no Menu que foi passado para onCreateOptionsMenu().
126
No Android 3.0 e superior, os itens do Menu de Opes so colocados na barra de ao, que aparece no topo da atividade no lugar da barra de ttulo tradicional. Por padro todos os itens do Menu de Opes so colocados no menu de estouro, que o usurio pode abrir ao tocar no cone do menu no lado direito da barra de ao. No entanto, voc pode colocar itens de menu diretamente na Barra de ao como "itens de ao", para acesso instantneo, como mostrado na figura 2.
Figura 2. Imagem da barra de ao na aplicao de e-mail, com dois itens de ao do Menu de Opes, alm do menu de estouro.
Quando o sistema Android cria o Menu de Opes, pela primeira vez, ele chama o mtodo onCreateOptionsMenu() da sua atividade. Substituir este mtodo em sua atividade e preencher o Menu que passado para o mtodo, Menu inflando um recurso de menu como descrito acima em Inflating a Menu Resource. Por exemplo:
@Override public boolean onCreateOptionsMenu(Menu menu) { MenuInflater inflater = getMenuInflater(); inflater.inflate(R.menu.game_menu, menu); return true; }
Voc tambm pode preencher o menu em cdigo, usando add() para adicionar itens ao Menu. Nota: No Android 2.3 e inferiores, o sistema chama onCreateOptionsMenu() para criar o menu de opes quando o usurio abre pela primeira vez, mas no Android 3.0 e superior, o sistema cria assim que a atividade criada, a fim e preencher a barra de ao.
Respondendo ao do usurio
Quando o usurio seleciona um item de menu do Menu de Opes (incluindo itens de ao na barra de ao), o sistema chama o mtodo onOptionsItemSelected() da sua atividade. Este mtodo passa o MenuItem que o usurio selecionou. Voc pode identificar o item de menu chamando getItemId(), que retorna o ID nico para o item de menu (definido pelo atributo android:id no recurso de menu ou com um nmero inteiro
127
dado ao mtodo add()). Voc pode combinar esta identificao contra itens do menu conhecidos e executar a ao apropriada. Por exemplo:
@Override public boolean onOptionsItemSelected(MenuItem item) { // Handle item selection switch (item.getItemId()) { case R.id.new_game: newGame(); return true; case R.id.help: showHelp(); return true; default: return super.onOptionsItemSelected(item); } }
Neste exemplo, getItemId() consulta o ID do item de menu selecionado e o comando switch compara o ID contra os IDs de recursos que foram atribudos aos itens do menu no recurso XML. Quando um switch case manipula o item de menu, ela retorna true para indicar que a seleo de item foi tratada. Caso contrrio, a declarao padro passa o item de menu para a super classe, no caso dele poder lidar com o item selecionado. (Se voc diretamente estendeu a classe Activity, ento, a super classe retorna false, mas uma boa prtica passar itens de menu no tratados para a classe super em vez de diretamente retornar false). Alm disso, o Android 3.0 adiciona a capacidade de definir o comportamento de clicar em um item de menu no menu de recursos XML, usando o atributo android:onClick. Ento voc no precisa implementar onOptionsItemSelected(). Usando o atributo android:onClick, voc pode especificar um mtodo a ser chamado quando o usurio seleciona o item de menu. Sua atividade deve, ento, aplicar o mtodo especificado no android:onClick para que ele aceite um nico MenuItem de parmetro, quando o sistema chama este mtodo, ele passa o item de menu selecionado. Dica: Se seu aplicativo contm atividades mltiplas e algumas delas oferecem o mesmo Menu de Opes, considere a criao de uma atividade que no executa nada, exceto os mtodos onCreateOptionsMenu() e onOptionsItemSelected(). Em seguida, estenda esta classe para cada atividade que deve compartilhar o mesmo menu de opes. Dessa forma, voc tem que gerenciar apenas um conjunto de cdigo para manipular aes de menu e cada classe descendente herda o comportamento do menu.
128
Se voc quiser adicionar itens de menu para um dos descendentes de suas atividades, sobreponha onCreateOptionsMenu() nessa atividade. Chame
super.onCreateOptionsMenu(menu) para que os itens do menu inicial sejam criados, em seguida, adicione novos itens de menu com menu.add(). Voc tambm pode substituir o comportamento da super classe para os itens de menu individuais.
129
interface do usurio. No Android, um menu de contexto exibido quando o usurio executa um "toque longo" (pressiona e segura) em um item. Voc pode criar um menu de contexto para qualquer view, apesar de menus de contexto serem mais freqentemente utilizados para os itens em um ListView. Quando o usurio pressiona longamente em um item em uma ListView e a lista est registrada para fornecer um menu de contexto, o item da lista sinaliza para o usurio que um menu de contexto est disponvel animando sua cor de fundo, que faz a transio do laranja ao branco antes de abrir o menu de contexto. (O aplicativo Contatos demonstra esta caracterstica.) A fim de fornecer um menu de contexto, voc deve "registrar" a view de um menu de contexto. Chame
registerForContextMenu() e passe a View que voc quer dar um menu de contexto. Quando esta view receber um toque de longa durao, ela exibe um menu de contexto. Para definir a aparncia e comportamento do menu de contexto, substitua seus mtodos de retorno do menu de contexto
como esta:
registerForContextMenu( getListView() );
da atividade, onCreateContextMenu() e onContextItemSelected(). Por exemplo, aqui est um onCreateContextMenu() que usa o recurso de menu context_menu.xml:
@Override public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) { super.onCreateContextMenu(menu, v, menuInfo); MenuInflater inflater = getMenuInflater(); inflater.inflate(R.menu.context_menu, menu); }
MenuInflater usado para inflar o menu de contexto de um recurso de menu. (Voc tambm pode usar o add() para adicionar itens de menu). Os parmetros de mtodo de retorno incluem o View que o usurio selecionou e ContextMenu.ContextMenuInfo que
130
fornece informaes adicionais sobre o item selecionado. Voc pode usar esses parmetros para determinar qual menu de contexto deve ser criado, mas neste exemplo, todos os menus de contexto para a atividade so os mesmos. Ento, quando o usurio seleciona um item no menu de contexto, o sistema chama onContextItemSelected(). Aqui est um exemplo de como voc pode manipular os itens selecionados:
@Override public boolean onContextItemSelected(MenuItem item) { AdapterContextMenuInfo info = (AdapterContextMenuInfo) item.getMenuInfo(); switch (item.getItemId()) { case R.id.edit: editNote(info.id); return true; case R.id.delete: deleteNote(info.id); return true; default: return super.onContextItemSelected(item); } }
A estrutura deste cdigo semelhante ao exemplo de criao de um Menu de Opes, em que getItemId() consulta o ID do item de menu selecionado e um switch corresponde ao item para as identificaes que so definidos no recurso de menu. E como o exemplo do menu de opes, a declarao padro chama a super classe no caso dela poder lidar com itens de menu no tratados aqui, se necessrio. Neste exemplo, o item selecionado um item da ListView. Para executar uma ao sobre o item selecionado, o aplicativo precisa saber o ID da lista para o item selecionado (a sua posio no ListView). Para obter o ID, o aplicativo chama getMenuInfo(), que retorna um objeto AdapterView.AdapterContextMenuInfo que inclui a identificao de lista para o item selecionado no campo id. Os mtodos locais editNote() e deleteNote() aceitam essa identificao da lista para executar uma ao nos dados especificados pelo ID da lista. Nota: Os itens em um menu de contexto no suportam cones ou teclas de atalho.
131
Criando Submenus
Um submenu um menu que o usurio pode abrir por selecionar um item em outro menu. Voc pode adicionar um submenu a qualquer menu (com exceo de um submenu). Submenus so teis quando seu aplicativo tem um monte de funes que podem ser organizadas em tpicos, como os itens na barra de uma aplicao para PC de menu (Arquivo, Editar, Exibir, etc.) Ao criar o seu recurso de menu, voc pode criar um submenu, adicionando um elemento <menu> como o filho de um <item>. Por exemplo:
<?xml version="1.0" encoding="utf-8"?> <menu xmlns:android="http://schemas.android.com/apk/res/android"> <item android:id="@+id/file" android:icon="@drawable/file" android:title="@string/file" > <!-- "file" submenu --> <menu> <item android:id="@+id/create_new" android:title="@string/create_new" /> <item android:id="@+id/open" android:title="@string/open" /> </menu> </item> </menu>
Quando o usurio seleciona um item do submenu, o respectivo mtodo de retorno onitem-selected do menu pai recebe o evento. Por exemplo, se o menu acima aplicado como um Menu de Opes, ento o mtodo onOptionsItemSelected() chamado quando um item de submenu selecionado. Voc tambm pode usar addSubMenu() para adicionar dinamicamente um SubMenu a um Menu j existente. Isso retorna o novo objeto SubMenu, para o qual voc pode adicionar itens de submenu, usando add().
Grupos de Menu
Um grupo de menu uma coleo de itens de menu que compartilham certas caractersticas.
132
Com um grupo, voc pode: Mostrar ou ocultar todos os itens com setGroupVisible() Ativar ou desativar todos os itens com setGroupEnabled() Especificar se todos os itens so verificados com setGroupCheckable() Voc pode criar um grupo aninhando elementos <item> dentro de um elemento <group> em seu recurso de menu ou pela especificao de um ID de grupo com o mtodo add(). Aqui est um exemplo de recurso de menu que inclui um grupo:
<?xml version="1.0" encoding="utf-8"?> <menu xmlns:android="http://schemas.android.com/apk/res/android"> <item android:id="@+id/item1" android:icon="@drawable/item1" android:title="@string/item1" /> <!-- menu group --> <group android:id="@+id/group1"> <item android:id="@+id/groupItem1" android:title="@string/groupItem1" /> <item android:id="@+id/groupItem2" android:title="@string/groupItem2" /> </group> </menu>
Os itens que esto no grupo aparecem da mesma forma que o primeiro item que no est em um grupo - todos os trs itens no menu so irmos. No entanto, voc pode modificar as caractersticas dos dois elementos do grupo, referenciando o ID do grupo e utilizando os mtodos listados acima.
133
Nota: Os itens de menu no menu de cone (no menu Opes) no podem exibir uma caixa de seleo ou radio button. Se voc optar por fazer os itens no menu do cone selecionveis, voc deve manualmente indicar o estado marcado por trocar o cone e/ou texto cada vez que ocorrem as mudanas de estado. Voc pode definir o comportamento checkable para itens individuais de menu usando o atributo android:checkable no elemento <item>, ou para um grupo inteiro com o atributo android:checkableBehavior no elemento <group>. Por exemplo, todos os itens deste grupo de menu so verificados com um boto de rdio:
<?xml version="1.0" encoding="utf-8"?> <menu xmlns:android="http://schemas.android.com/apk/res/android"> <group android:checkableBehavior="single"> <item android:id="@+id/red" android:title="@string/red" /> <item android:id="@+id/blue" android:title="@string/blue" /> </group> </menu>
O atributo android:checkableBehavior aceita tanto: single Apenas um item do grupo pode ser verificado (botes de rdio) all Todos os itens podem ser verificados (caixas) none Nenhum item pode ser verificado Voc pode aplicar um estado padro verificado de um item usando o atributo android:checked no elemento <item> e alter-lo em cdigo com o mtodo setChecked(). Quando um item checkable selecionado, o sistema chama o seu mtodo de retorno item-selected (como onOptionsItemSelected()). aqui que voc deve definir o estado da caixa, pois um boto de opo ou de rdio no muda o seu estado automaticamente.
134
Voc pode consultar o estado atual do item (como era antes que o usurio selecionou) com isChecked() e, em seguida, definir o estado de verificado com setChecked(). Por exemplo:
@Override public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { case R.id.vibrate: case R.id.dont_vibrate: if (item.isChecked()) item.setChecked(false); else item.setChecked(true); return true; default: return super.onOptionsItemSelected(item); } }
Se voc no definir o estado de verificado dessa forma, o estado visvel do item (a caixa de seleo ou boto de rdio) no vai mudar quando o usurio selecion-lo. Quando voc definir o estado, a atividade preserva o estado de verificado do item para que quando o usurio abra o menu mais tarde, o estado de verificado que voc definiu esteja visvel. Nota: os itens de menu verificveis se destinam a serem usados apenas em uma sesso base e no sero salvos aps a aplicao ser destruda. Se voc tiver as configuraes do aplicativo que voc gostaria de salvar para o usurio, voc deve armazenar os dados usando Preferncias Compartilhadas.
As teclas de atalho
Para facilitar o acesso rpido aos itens do menu de opes quando o dispositivo do usurio tem um teclado fsico, voc pode adicionar atalhos de acesso rpido usando letras e/ou nmeros, com os atributos android:alphabeticShortcut e
android:numericShortcut no elemento <item>. Voc tambm pode usar os mtodos setAlphabeticShortcut(char) e setNumericShortcut(char). Teclas de atalho no so case sensitive. Por exemplo, se voc aplicar o caractere "s" como um atalho alfabtico para um item "salvar" de menu, ento quando o menu est aberto (ou quando o usurio segura o boto MENU) e o usurio pressiona a tecla "s", o item "Salvar" selecionado.
135
Esta tecla de atalho exibida como uma dica no item de menu, abaixo do nome do item de menu (com exceo de itens no menu do cone, que so exibidas somente se o usurio segura o boto MENU). Nota: as teclas de atalho para itens de menu s funcionam em dispositivos com um teclado de hardware. Atalhos no podem ser adicionado a itens de um menu de contexto.
136
Nota: CATEGORY_SELECTED_ALTERNATIVE usada para segurar o elemento selecionado atualmente na tela. Assim, ele s deve ser utilizado para a criao de um menu em onCreateContextMenu(). Por exemplo:
@Override public boolean onCreateOptionsMenu(Menu menu){ super.onCreateOptionsMenu(menu); // Create an Intent that describes the requirements to fulfill, to be included // in our menu. The offering app must include a category value of Intent.CATEGORY_ALTERNATIVE. Intent intent = new Intent(null, dataUri); intent.addCategory(Intent.CATEGORY_ALTERNATIVE); // Search and populate the menu with acceptable offering applications. menu.addIntentOptions( R.id.intent_group, // Menu group to which new items will be added 0, // Unique item ID (none) 0, // Order for the items (none) this.getComponentName(), // The current activity name null, // Specific items to place first (none) intent, // Intent created above that describes our requirements 0, // Additional flags to control items (none) null); // Array of MenuItems that correlate to specific items (none) return true; }
Para cada atividade descoberta que fornece uma inteno de filtro correspondente a inteno definida um item de menu adicionado, utilizando o valor na inteno do filtro android:label como o ttulo do item de menu e o cone do aplicativo como o item cone do menu. O mtodo addIntentOptions() retorna o nmero de itens de menu que foram acrescentados. Nota: Quando voc chamar addIntentOptions(), ela substitui qualquer e todos os itens do menu, o grupo de menu especificado no primeiro argumento.
137
Para ser includo em outros menus de aplicativos, voc precisa definir uma inteno de filtro, como de costume, mas e/ou no se esquea de incluir o
CATEGORY_ALTERNATIVE
CATEGORY_SELECTED_ALTERNATIVE
Leia mais sobre como escrever filtros de inteno em Intents and Intents Filters.
138
Usando a barra de ao
A barra de ao um widget para atividades que substitui a tradicional barra de ttulo no topo da tela. Por padro, a barra de ao inclui o logotipo da aplicao do lado esquerdo, seguido do ttulo da atividade, e todos os itens disponveis no menu Opes no lado direito. A Barra de ao oferece vrios recursos teis, incluindo a capacidade de: Exibir itens do Menu de Opes diretamente na Barra de ao, como "itens de ao" - fornecendo acesso imediato s aes-chave dos usurios. Os itens de menu que no aparecem como itens de ao so colocados no menu de estouro, revelado por uma lista suspensa na barra de aes. Fornecer as guias para navegar entre os fragmentos. Fornea uma lista drop-down para a navegao. Fornecer interativas "vises de ao" no lugar de itens de ao (como uma caixa de pesquisa).
Figura 1. Uma imagem da barra de ao na aplicao de e-mail, contendo itens de ao para compor novo email e atualizar a caixa de entrada.
Adicionando a barra de ao
A barra de ao includa por padro em todas as atividades que visam o Android 3.0 ou superior. Mais especificamente, todas as atividades que usam o novo tema "hologrfico" incluem a barra de ao, e qualquer aplicao que tem como alvo o Android 3.0 automaticamente recebe esse tema. Uma aplicao considerada para "o alvo" Android 3.0 quando definido tanto o atributo android:minSdkVersion ou android:targetSdkVersion no elemento <uses-sdk> para "11" ou superior. Por exemplo:
139
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.example.helloworld" android:versionCode="1" android:versionName="1.0"> <uses-sdk android:minSdkVersion="4" android:targetSdkVersion="11" /> <application ... > ... </application> </manifest>
Neste exemplo, a aplicao requer uma verso mnima do API Nvel 4 (Android 1.6), mas tambm atinge API Nvel 11 (Android 3.0). Dessa forma, quando o aplicativo instalado em um dispositivo rodando Android 3.0 ou superior, o sistema aplica o tema hologrfico para cada atividade, e assim, cada atividade inclui a Barra de Aes. No entanto, se voc quiser usar APIs de Barra de Aes, tais como guias para adicionar ou modificar estilos da barra de ao, voc precisa definir o android:minSdkVersion para "11", assim voc pode acessar a classe ActionBar.
Removendo a barra de ao
Se voc quiser remover a barra de ao para uma determinada atividade, defina o tema da atividade para Theme.Holo.NoActionBar. Por exemplo:
<activity android:theme="@android:style/Theme.Holo.NoActionBar">
Dica: Se voc tem um tema de atividade personalizado no qual voc gostaria de remover a barra de ao, defina a propriedade de estilo android:windowActionBar false. Voc tambm pode ocultar a barra de ao em tempo de execuo chamando hide(), e depois mostr-la novamente chamando show(). Por exemplo:
ActionBar actionBar = getActionBar(); actionBar.hide();
Quando a barra de ao se esconde, o sistema ajusta seu contedo das atividades para preencher todo o espao disponvel na tela. Nota: Se voc remover a Barra de ao usando um tema, a janela no vai permitir a barra de ao a todos, ento voc no pode adicion-la em tempo de execuo chamar getActionBar() ir retornar null.
140
Adicionando itens de ao
Um item de ao que simplesmente um item do menu de opes que voc declara deve aparecer diretamente na barra de aes. Um item de ao pode incluir um cone e/ou texto. Se um item de menu no aparece como um item de ao, o sistema coloca no menu de estouro, que o usurio pode abrir com o cone do menu no lado direito da barra de ao.
Quando a primeira atividade comea, o sistema preenche a barra de ao e menu de estouro chamando onCreateOptionsMenu() para sua atividade. Conforme discutido no guia para a criao de menus, neste mtodo callback que voc define o menu de opes para a atividade. Voc pode especificar um item de menu para aparecer como um item de ao, se no houver espao para isso, a partir do seu recurso de menu, declarando android:showAsAction="ifRoom" para o elemento <item>. Desta forma, o item de menu aparece na barra de ao para um acesso rpido apenas se houver espao disponvel para ele. Se no houver espao suficiente, o item colocado no menu de transbordamento (revelado pelo cone do menu no lado direito da barra de ao). Voc tambm pode declarar um item de menu para aparecer como um item de ao a partir do seu cdigo de aplicativo, chamando setShowAsAction() no MenuItem e passando SHOW_AS_ACTION_IF_ROOM. Se o item de menu fornece tanto um ttulo como um cone, ento o item de ao mostra apenas o cone por default. Se voc quiser incluir o texto do item de ao, adicione a flag "with text": em XML, adicionar withText para o atributo android:showAsAction ou, no cdigo do aplicativo, use a flag SHOW_AS_ACTION_WITH_TEXT ao chamar setShowAsAction(). A Figura 2 mostra uma barra de ao que tem dois itens de ao com o texto e o cone para o menu de estouro. Aqui est um exemplo de como voc pode declarar um item de menu como um item de ao em um arquivo de recurso de menu:
141
<?xml version="1.0" encoding="utf-8"?> <menu xmlns:android="http://schemas.android.com/apk/res/android"> <item android:id="@+id/menu_add" android:icon="@drawable/ic_menu_save" android:title="@string/menu_save" android:showAsAction="ifRoom|withText" /> </menu>
Neste caso, tanto as flags ifRoom e withText esto definidas, de modo que quando este item aparece como um item de ao, inclui o texto do ttulo, juntamente com o cone. Um item de menu colocado na barra de ao dispara os mesmos mtodos de callback que outros itens do menu de opes. Quando o usurio seleciona um item de ao, sua atividade recebe uma chamada para onOptionsItemSelected(), passando o ID do item. Nota: Se voc adicionou o item de menu de um fragmento, o respectivo mtodo onOptionsItemSelected() chamado para esse fragmento. No entanto, a atividade tem a chance de manipul-lo primeiro, ento o sistema chama onOptionsItemSelected() da atividade antes de chamar o fragmento. Voc tambm pode declarar um item que sempre aparece como um item de ao, mas voc deve evitar faz-lo, porque ele pode criar uma interface confusa se houver muitos itens de ao e tambm podem colidir com outros elementos na barra de aes.
O comportamento deve ser normal para a sua aplicao para regressar "HOME" atividade ou ao estado inicial (como quando a atividade no mudou, mas os fragmentos foram alterados) quando o usurio toca o cone. Se o usurio j est em casa ou no estado inicial, ento voc no precisa fazer nada.
142
Quando o usurio toca o cone, o sistema chama o mtodo onOptionsItemSelected() de sua atividade com o ID android.R.id.home. Ento, voc precisa adicionar uma condio para o seu mtodo onOptionsItemSelected() para receber android.R.id.home e executar a ao apropriada, como iniciar a atividade inicial ou remover recentes transaes do fragmento fora da pilha. Se voc responder para o cone do aplicativo, retornando atividade inicial, voc deve incluir o flag FLAG_ACTIVITY_CLEAR_TOP na Intent. Com este indicador, se a atividade que voc est comeando j existe na tarefa atual, ento todas as atividades em cima dela so destrudas e essa trazida para frente. Voc deve favorecer essa abordagem, porque ir para "HOME" uma ao que equivalente a "voltar atrs" e voc geralmente no deve criar uma nova instncia da atividade inicial. Caso contrrio, voc pode acabar com uma longa pilha de atividades na tarefa atual. Por exemplo, aqui est uma implementao do onOptionsItemSelected() que retorna para a aplicao da "HOME" de atividade:
@Override public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { case android.R.id.home: // app icon in Action Bar clicked; go home Intent intent = new Intent(this, HomeActivity.class); intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); startActivity(intent); return true; default: return super.onOptionsItemSelected(item); } }
A maneira como voc responde a este evento a mesma de quando navegando para HOME (como discutido acima, exceto se voc iniciar uma atividade diferente, com base ANDROID, uma viso geral Anderson Duarte de Amorim
143
na atividade corrente). Tudo que voc precisa fazer para indicar ao usurio que o comportamento diferente definir a barra de ao para "mostrar a HOME como para cima". Voc pode fazer isso chamando setDisplayHomeAsUpEnabled(true) na barra de aes da sua atividade. Quando o fizer, o sistema retira o cone do aplicativo com uma seta indicando o comportamento para cima, como mostrado acima. Por exemplo, aqui est como voc pode mostrar o cone do aplicativo como uma ao "para cima":
@Override protected void onStart() { super.onStart(); ActionBar actionBar = this.getActionBar(); actionBar.setDisplayHomeAsUpEnabled(true); }
Ento, sua atividade deve responder ao usurio tocar no cone, a partir do onOptionsItemSelected(), recebendo o ID android.R.id.home (como mostrado acima). Neste caso, ao navegar para cima, ainda mais importante que voc use o FLAG_ACTIVITY_CLEAR_TOP na Intent, de modo que voc no cria uma nova instncia da atividade do pai, se j existe um.
Uma exibio de ao um widget que aparece na barra de ao como um substituto para um item de ao. Por exemplo, se voc tem um item no menu opes para "Busca", voc pode adicionar uma exibio de ao para o item que fornece um widget SearchView na barra de ao sempre que o item ativado como um item de ao. Ao adicionar uma viso de ao para um item de menu, importante que voc ainda permita ao item se comportar como um item de menu normal quando ela no aparece na barra de aes. Por exemplo, um item de menu para realizar uma pesquisa deve, por padro, abrir a janela de pesquisa do Android, mas se o item colocado na barra de ao, a viso de ao aparece com um widget SearchView. A Figura 5 mostra um exemplo do SearchView em uma viso de ao.
144
A melhor forma de declarar uma viso de ao para um item est em seu recurso de menu, usando o atributo android:actionLayout ou android:actionViewClass: O valor para android:actionLayout deve ser um ponteiro de recurso para um arquivo de layout. Por exemplo:
<?xml version="1.0" encoding="utf-8"?> <menu xmlns:android="http://schemas.android.com/apk/res/android"> <item android:id="@+id/menu_search" android:title="Search" android:icon="@drawable/ic_menu_search" android:showAsAction="ifRoom" android:actionLayout="@layout/searchview" /> </menu>
O valor para android:actionViewClass deve ser um nome de classe qualificado para o View que voc deseja usar. Por exemplo:
<?xml version="1.0" encoding="utf-8"?> <menu xmlns:android="http://schemas.android.com/apk/res/android"> <item android:id="@+id/menu_search" android:title="Search" android:icon="@drawable/ic_menu_search" android:showAsAction="ifRoom" android:actionViewClass="android.widget.SearchView" /> </menu>
Voc deve incluir android:showAsAction="ifRoom" para que o item aparea como uma viso de ao quando o room est disponvel. Se necessrio, no entanto, pode forar o item que sempre aparea como uma viso de ao, definindo android:showAsAction para "always". Agora, quando o item de menu exibido como um item de ao, esta vista de ao aparece em vez do cone e/ou texto do ttulo. No entanto, se no houver espao suficiente na barra de ao, o item aparece no menu de estouro como um item de menu normal e voc deve responder a ela a partir do mtodo de retorno
onOptionsItemSelected(). Quando a primeira atividade comea, o sistema preenche a barra de ao e menu de estouro chamando onCreateOptionsMenu(). Depois de ter inflado seu menu neste mtodo, voc pode adquirir elementos em uma viso de ao (talvez a fim de anexar ouvintes) chamando findItem() com o ID do item de menu, ento getActionView() no
145
MenuItem retornado. Por exemplo, o widget de busca do modelo acima adquirido como este:
@Override public boolean onCreateOptionsMenu(Menu menu) { getMenuInflater().inflate(R.menu.options, menu); SearchView searchView = (SearchView) menu.findItem(R.id.menu_search).getActionView(); // Set appropriate listeners for searchView ... return super.onCreateOptionsMenu(menu); }
Adicionando abas
A Barra de ao pode exibir guias que permitem ao usurio navegar entre diferentes fragmentos na atividade. Cada guia pode incluir um ttulo e/ou um cone. Para comear, o esquema deve incluir um View, em que cada Fragment associado com uma guia exibida. Tenha certeza de que tem uma identificao que pode ser usada para fazer referncia a ela em seu cdigo. Para adicionar guias para a barra de aes: 1. Criar uma aplicao de ActionBar.TabListener para manipular os eventos de interao na barra de guias de ao. Voc deve implementar todos os mtodos: onTabSelected(), onTabUnselected(), e onTabReselected(). Cada mtodo de retorno passa a ActionBar.Tab que recebeu o evento e um FragmentTransaction para voc efetuar as transaes do fragmento (adicionar ou remover fragmentos).
146
Por exemplo:
private class MyTabListener implements ActionBar.TabListener { private TabContentFragment mFragment; // Called to create an instance of the listener when adding a new tab public TabListener(TabContentFragment fragment) { mFragment = fragment; } @Override public void onTabSelected(Tab tab, FragmentTransaction ft) { ft.add(R.id.fragment_content, mFragment, null); } @Override public void onTabUnselected(Tab tab, FragmentTransaction ft) { ft.remove(mFragment); } @Override public void onTabReselected(Tab tab, FragmentTransaction ft) { // do nothing } }
Esta implementao de ActionBar.TabListener adiciona um construtor que salva o Fragment associado com um guia para que cada retorno possa adicionar ou remover esse fragmento. 2. Receba a ActionBar para a sua atividade, chamando getActionBar() de sua atividade, durante onCreate() (mas no se esquea de fazer isso depois de voc ter chamado setContentView()). 3. Chame setNavigationMode(NAVIGATION_MODE_TABS) para habilitar o modo guia para a ActionBar . 4. Criar cada guia para a barra de ao: a. Criar uma nova ActionBar.Tab chamando newTab() na ActionBar . b. Acrescentar o texto do ttulo e/ou um cone para o guia, chamando setText() e/ou setIcon(). Dica: Esses mtodos retornam a mesma instncia ActionBar.Tab, assim voc pode encadear as chamadas juntas.
147
c. Declare o ActionBar.TabListener para usar a guia por meio de um exemplo de sua aplicao para setTabListener(). 5. Adicione cada ActionBar.Tab barra de ao, chamando addTab() na ActionBar e passe a ActionBar.Tab. Por exemplo, o cdigo a seguir combina as etapas 2-5 para criar duas guias e adicionlas Barra de ao:
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); // setup Action Bar for tabs final ActionBar actionBar = getActionBar(); actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS); // remove the activity title to make space for tabs actionBar.setDisplayShowTitleEnabled(false); // instantiate fragment for the tab Fragment artistsFragment = new ArtistsFragment(); // add a new tab and set its title text and tab listener actionBar.addTab(actionBar.newTab().setText(R.string.tab_artists) .setTabListener(new TabListener(artistsFragment))); Fragment albumsFragment = new AlbumsFragment(); actionBar.addTab(actionBar.newTab().setText(R.string.tab_albums) .setTabListener(new TabListener(albumsFragment))); }
Todos os comportamentos que ocorrem quando uma guia selecionada devem ser definidos pelo seu mtodo de callback ActionBar.TabListener. Quando uma guia selecionada, ela recebe uma chamada para onTabSelected() e a que voc deve adicionar o fragmento apropriado para a exibio designada em seu layout, utilizando add() com o previsto FragmentTransaction. Da mesma forma, quando uma guia desmarcada (porque outra guia selecionada), voc deve remover o fragmento do layout, utilizando remove(). Ateno: Voc no deve chamar commit() para essas operaes, o sistema chama-o para voc e pode lanar uma exceo se voc cham-lo. Voc tambm no pode adicionar essas transaes de fragmento para o fundo da pilha. Se a sua atividade interrompida, voc deve manter a guia selecionada no momento com o estado salvo de modo que quando o usurio retorna sua aplicao, voc pode ANDROID, uma viso geral Anderson Duarte de Amorim
148
abrir a guia. Quando hora de salvar o estado, voc pode consultar a atual guia selecionada com getSelectedNavigationIndex(). Isso retorna a posio do ndice da guia selecionada. Ateno: importante que voc salve o estado de cada fragmento quando necessrio, pois quando o usurio alterna fragmentos com as guias, e em seguida, retorna a um fragmento anterior, aparece o caminho que ele deixou. Para obter informaes sobre como salvar o seu estado de fragmento, consulte o guia do desenvolvedor sobre Fragmentos.
Nota: Voc deve executar isto durante a sua atividade do mtodo onCreate(). 4. Em seguida, defina o retorno para a lista drop-down com
Este mtodo tem a sua SpinnerAdapter e ActionBar.OnNavigationListener. Essa a configurao bsica. No entanto, a implementao da SpinnerAdapter e ActionBar.OnNavigationListener onde a maioria do trabalho feito. H muitas
149
maneiras que voc pode aplicar isto para definir a funcionalidade para o seu drop-down de navegao e implementar vrios tipos de SpinnerAdapter alm do escopo deste documento (voc deve referenciar para a classe SpinnerAdapter para obter mais informaes). No entanto, abaixo h um exemplo simples para um SpinnerAdapter e ActionBar.OnNavigationListener para voc comear.
O mtodo createFromResource() usa trs parmetros: a aplicao Context, a identificao de recursos para array de string, e o layout a ser usado para cada item da lista. Um array de string definido em um recurso parecido com este:
<?xml version="1.0" encoding="utf-8"?> <resources> <string-array name="action_list"> <item>Mercury</item> <item>Venus</item> <item>Earth</item> </string-array> </pre>
O ArrayAdapter retornado por createFromResource() est completo e pronto para voc passar a setListNavigationCallbacks() (na etapa 4 acima). Antes de fazer, porm, voc precisa criar o OnNavigationListener. A implementao do ActionBar.OnNavigationListener onde voc lida com as mudanas de fragmento ou outras modificaes sua atividade quando o usurio seleciona um item da lista drop-down. H apenas um mtodo callback para implementar o receptor: onNavigationItemSelected().
150
O mtodo onNavigationItemSelected() recebe a posio do item na lista e um ID de nico item fornecido pela SpinnerAdapter. Aqui est um exemplo que instancia uma implementao annima de
OnNavigationListener, que insere um Fragment dentro do recipiente layout identificado por R.id.fragment_container:
mOnNavigationListener = new OnNavigationListener() { // Get the same strings provided for the drop-down's ArrayAdapter String[] strings = getResources().getStringArray(R.array.action_list); @Override public boolean onNavigationItemSelected(int position, long itemId) { // Create new fragment from our own Fragment class ListContentFragment newFragment = new ListContentFragment(); FragmentTransaction ft = openFragmentTransaction(); // Replace whatever is in the fragment container with this fragment // and give the fragment a tag name equal to the string at the position selected ft.replace(R.id.fragment_container, newFragment, strings[position]); // Apply changes ft.commit(); return true; } };
Esta instncia de OnNavigationListener est completo e agora voc pode chamar setListNavigationCallbacks() (na etapa 4), passando o ArrayAdapter e este OnNavigationListener. Neste exemplo, quando o usurio seleciona um item da lista drop-down, um fragmento adicionado ao layout (que substitui o fragmento atual no R.id.fragment_container vista). O fragmento adicional dada uma etiqueta que identifica-lo, que a mesma seqncia de caracteres usado para identificar o fragmento na lista drop-down.
151
Aqui est um olhar da classe ListContentFragment que define cada fragmento neste exemplo:
public class ListContentFragment extends Fragment { private String mText; @Override public void onAttach(Activity activity) { // This is the first callback received; here we can set the text for // the fragment as defined by the tag specified during the fragment transaction super.onAttach(activity); mText = getTag(); } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { // This is called to define the layout for the fragment; // we just create a TextView and set its text to be the fragment tag TextView text = new TextView(getActivity()); text.setText(mText); return text; } }
Estilizando a barra de ao
A barra de ao o ttulo do seu aplicativo e um ponto de interao primrio para os usurios, ento voc pode querer modificar alguns em seu projeto, a fim de torn-lo sentir mais integrado com o design do aplicativo. H vrias maneiras que voc pode fazer isso se quiser. Para modificaes simples para o ActionBar, voc pode usar os mtodos a seguir: setBackgroundDrawable() Define um drawable para usar como fundo da barra de ao. O drawable deve ser uma imagem Nine-patch, uma forma, ou uma cor slida, para que o sistema pode redimensionar a drawable com base no tamanho da barra de ao (voc no deve usar uma imagem bitmap de tamanho fixo). setDisplayUseLogoEnabled() Permite o uso de uma imagem alternativa (a "logo") na barra de ao, em vez do cone do aplicativo padro. Um logotipo muitas vezes uma imagem mais ampla, mais detalhada que representa a aplicao. Quando isso estiver ativado, o ANDROID, uma viso geral Anderson Duarte de Amorim
152
sistema utiliza a imagem do logotipo definido para a aplicao (ou a atividade individual) no arquivo de manifesto, com o atributo android:logo. O logotipo ser redimensionado, conforme necessrio para ajustar a altura da barra de ao. (Melhores prticas projetar o logotipo com o mesmo tamanho do cone do aplicativo.) Para personalizaes mais complexas, voc pode usar estilos e temas do Android para remodelar sua barra de ao de vrias maneiras. A Barra de ao tem dois temas padro, "dark" e "light". O tema escuro aplicado com o tema padro hologrfico, conforme especificado pelo tema Theme.Holo. Se voc quiser um fundo branco com texto escuro, em vez disso, voc pode aplicar o tema Theme.Holo.Light para a atividade no arquivo de manifesto. Por exemplo:
<activity android:name=".ExampleActivity" android:theme="@android:style/Theme.Holo.Light" />
Para ter mais controle, voc pode substituir o tema Theme.Holo ou Theme.Holo.Light e aplicar estilos personalizados para determinados aspectos da Barra de Aes. Algumas das propriedades da barra de ao voc pode personalizar incluindo o seguinte: android:actionBarTabStyle Estilo de abas na barra de ao. android:actionBarTabBarStyle Estilo para a barra que aparece abaixo das abas na barra de ao. android:actionBarTabTextStyle Estilo para o texto nos separadores. android:actionDropDownStyle Estilo para a lista drop-down utilizado para o menu de navegao de transbordamento e drop-down. android:actionButtonStyle Estilo para a imagem de fundo usado para os botes na barra de ao.
153
Por exemplo, aqui est um arquivo de recurso que define um tema personalizado para a barra de ao, baseado no tema padro Theme.Holo:
<?xml version="1.0" encoding="utf-8"?> <resources> <!-- the theme applied to the application or activity --> <style name="CustomActionBar" parent="android:style/Theme.Holo.Light"> <item name="android:actionBarTabTextStyle">@style/customActionBarTabTextStyle</item> <item name="android:actionBarTabStyle">@style/customActionBarTabStyle</item> <item name="android:actionBarTabBarStyle">@style/customActionBarTabBarStyle</item> </style> <!-- style for the tab text --> <style name="customActionBarTabTextStyle"> <item name="android:textColor">#2966c2</item> <item name="android:textSize">20sp</item> <item name="android:typeface">sans</item> </style> <!-- style for the tabs --> <style name="customActionBarTabStyle"> <item name="android:background">@drawable/actionbar_tab_bg</item> <item name="android:paddingLeft">20dp</item> <item name="android:paddingRight">20dp</item> </style> <!-- style for the tab bar --> <style name="customActionBarTabBarStyle"> <item name="android:background">@drawable/actionbar_tab_bar</item> </style> </resources>
Nota: Para que a imagem de fundo guia mude, dependendo do estado de separador atual (selecionado, pressionado, no selecionado), o recurso drawable utilizado deve ser uma lista de estado drawable. Tambm certo que o tema declara um tema principal, da qual ele herda todos os estilos no explicitamente declarados em seu tema. Voc pode aplicar o seu tema personalizado para o aplicativo inteiro ou para atividades individuais no arquivo de manifesto, como este:
<application android:theme="@style/CustomActionBar" ... />
Alm disso, se voc quer criar um tema personalizado para a sua atividade que remove a barra de ao completamente, use os atributos de estilo a seguir:
154
android:windowActionBar Defina esta propriedade de estilo como false para remover a barra de aes. android:windowNoTitle Defina esta propriedade de estilo como true tambm para remover a barra de ttulo tradicional.
155
156
o estado de cada dilogo e os ganchos para a atividade, efetivamente tornando-o o "dono" de cada dilogo. Como tal, cada dilogo herda algumas propriedades da atividade. Por exemplo, quando uma janela aberta, a tecla Menu revela o menu de opes definidas para a atividade e as teclas de volume modificam o fluxo de udio usado pela atividade. Nota: Se voc decidir criar um dilogo fora do mtodo onCreateDialog(), no ir ser anexado a uma atividade. Voc pode, entretanto, anex-lo a uma atividade com setOwnerActivity(Activity). Quando voc quer mostrar uma janela, chame showDialog(int) e passe um nmero inteiro que identifica a caixa de dilogo que voc deseja exibir. Quando uma janela solicitada pela primeira vez, o Android chama
onCreateDialog(int) de sua atividade, que onde voc deve criar uma instncia do Dialog. Neste mtodo de retorno passado o mesmo ID que voc passou para showDialog(int). Depois de criar o dilogo, retorne o objeto no final do mtodo. Antes que o dilogo ser exibido, o Android tambm chama o mtodo callback opcional onPrepareDialog(int, Dialog). Defina nesse mtodo se voc deseja alterar as propriedades da caixa de dilogo cada vez que for aberta. Este mtodo chamado toda vez que uma caixa de dilogo aberta, enquanto onCreateDialog(int) chamado apenas na primeira vez que uma caixa de dilogo aberta. Se voc no definir onPrepareDialog(), ento o dilogo continuar a ser o mesmo que era o tempo anterior que foi aberto. Este mtodo tambm passa o ID do dilogo, alm de um dilogo do objeto que voc criou na onCreateDialog(). A melhor maneira de definir os mtodos de retorno onCreateDialog(int) e onPrepareDialog(int, Dialog) com uma instruo switch que verifica o parmetro id que passado para o mtodo. Cada caso deve verificar se h uma identificao nica de dilogo e, em seguida, criar e definir o respectivo dilogo. Por exemplo, imagine um jogo que usa dois dilogos distintos: um para indicar que o jogo tem uma pausa e outra para indicar que o jogo acabou. Primeiro, defina um ID de nmero inteiro para cada caixa de dilogo:
static final int DIALOG_PAUSED_ID = 0; static final int DIALOG_GAMEOVER_ID = 1;
157
Em seguida, defina a chamada onCreateDialog(int) com um caso de interruptor para cada ID:
protected Dialog onCreateDialog(int id) { Dialog dialog; switch(id) { case DIALOG_PAUSED_ID: // do the work to define the pause Dialog break; case DIALOG_GAMEOVER_ID: // do the work to define the game over Dialog break; default: dialog = null; } return dialog; }
Nota: Neste exemplo, no h nenhum cdigo dentro da declarao de caso, porque o procedimento para a definio de seu dilogo est fora do escopo desta seo. Quando hora de mostrar um dos dilogos, chame showDialog(int) com o ID de um dilogo:
showDialog(DIALOG_PAUSED_ID);
Dispensar um dilogo
Quando estiver pronto para fechar o dilogo, voc pode descart-lo chamando dismiss() no objeto Dialog. Se necessrio, voc tambm pode chamar dismissDialog(int) da atividade, o que efetivamente chama dismiss() na caixa de dilogo para voc. Se voc estiver usando onCreateDialog(int) para gerir o seu estado de dilogos (como discutido na seo anterior), ento cada vez que o dilogo indeferido, o estado do objeto de dilogo mantido pela atividade. Se voc decidir que voc no precisa mais desse objeto ou importante que o estado esteja limpo, ento voc deve chamar removeDialog(int). Isto ir remover todas as referncias internas ao objeto e se o dilogo est mostrando, vai dispens-lo.
158
Primeiro defina a interface DialogInterface.OnDismissListener. Essa interface possui apenas um mtodo, onDismiss(DialogInterface), que ser chamado quando o dilogo for descartado. Depois, passe a sua implementao OnDismissListener para setOnDismissListener(). No entanto, note que os dilogos tambm podem estar "cancelados". Este um caso especial que indica que o dilogo foi explicitamente cancelado por parte do usurio. Isso ocorrer se o usurio pressiona o boto "BACK " para fechar a janela, ou se a caixa de dilogo solicita explicitamente cancel() (talvez a partir de um boto "Cancelar" na caixa de dilogo). Quando um dilogo for cancelado, o OnDismissListener ainda ser notificado, mas se voc gostaria de ser informado de que o dilogo foi expressamente cancelado (e no dispensado normalmente), ento voc deve registrar um DialogInterface.OnCancelListener com setOnCancelListener().
Criando um AlertDialog
Um AlertDialog uma extenso da classe Dialog. capaz de construir a maioria das interfaces de usurio de dilogo e o tipo de dilogo sugerido. Voc deve us-lo para o dilogo que usam qualquer uma das seguintes caractersticas: Um ttulo Uma mensagem de texto Um, dois ou trs botes Uma lista de itens selecionveis (com checkbox ou radio-button) Para criar um AlertDialog, use a subclasse AlertDialog.Builder. Receba um construtor com AlertDialog.Builder(Context) e depois use os mtodos pblicos de classe para definir todas as propriedades AlertDialog. Depois que est finalizado com o construtor, recupere o objeto AlertDialog com create(). Os tpicos a seguir mostram como definir vrias propriedades do AlertDialog usando a classe AlertDialog.Builder. Se voc usar qualquer um dos seguintes cdigos de exemplo dentro do seu mtodo de retorno onCreateDialog(), voc pode retornar o objeto resultante de dilogo para exibir o dilogo.
159
Adicionando botes
Para criar um AlertDialog com botes lado a lado, como a mostrada na imagem direita, use o mtodo set...Button():
AlertDialog.Builder builder = new AlertDialog.Builder(this); builder.setMessage("Are you sure you want to exit?") .setCancelable(false) .setPositiveButton("Yes", new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int id) { MyActivity.this.finish(); } }) .setNegativeButton("No", new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int id) { dialog.cancel(); } }); AlertDialog alert = builder.create();
Primeiro, adicione uma mensagem para o dilogo com setMessage(CharSequence) . Ento, comece mtodo de encadeamento e definir a janela para no ser cancelado (por isso o usurio no poder fechar o dilogo com o boto traseiro) com setCancelable(boolean) . Para cada boto, use um dos set...Button() mtodos, como setPositiveButton() , que aceita o nome do boto e um DialogInterface.OnClickListener que define as medidas a tomar quando o usurio seleciona o boto. Nota: Voc s pode adicionar um boto de cada tipo AlertDialog. Ou seja, voc no pode ter mais de um boto "positivo". Isso limita o nmero de botes possveis para trs: positivo, neutro e negativo. Estes nomes so tecnicamente irrelevantes para a funcionalidade real de seus botes, mas deve ajud-lo a acompanhar o que faz o qu.
160
Para criar um AlertDialog com uma lista de itens selecionveis como o mostrado esquerda, use o mtodo setItems():
final CharSequence[] items = {"Red", "Green", "Blue"}; AlertDialog.Builder builder = new AlertDialog.Builder(this); builder.setTitle("Pick a color"); builder.setItems(items, new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int item) { Toast.makeText(getApplicationContext(), items[item], Toast.LENGTH_SHORT).show(); } }); AlertDialog alert = builder.create();
Primeiro, adicione um ttulo para o dilogo com setTitle(CharSequence). Em seguida, adicione uma lista de itens selecionveis com setItems(), que aceita um conjunto de itens a serem exibidos e um DialogInterface.OnClickListener que define as medidas a tomar quando o usurio seleciona um item.
setMultiChoiceItems()
setSingleChoiceItems(),
respectivamente. Se voc criar uma destas listas selecionveis no mtodo de retorno onCreateDialog(), o Android gerencia o estado da lista para voc. Contanto que a atividade esteja ativa, o dilogo se lembra dos itens que foram previamente selecionados, mas quando o usurio sai da atividade, a seleo est perdida.
161
Nota: Para salvar a seleo quando o usurio deixa ou faz pausa na atividade, voc deve salvar e restaurar corretamente a configurao de todo o ciclo de vida de atividade. Para salvar permanentemente as selees, mesmo quando o processo de atividade completamente parado, voc precisa salvar as configuraes com uma das tcnicas de Armazenamento de Dados. Para criar um AlertDialog com uma lista de itens de escolha simples, como a mostrada acima, use o mesmo cdigo do exemplo anterior, mas substitua o mtodo setItems() pelo setSingleChoiceItems():
final CharSequence[] items = {"Red", "Green", "Blue"}; AlertDialog.Builder builder = new AlertDialog.Builder(this); builder.setTitle("Pick a color"); builder.setSingleChoiceItems(items, -1, new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int item) { Toast.makeText(getApplicationContext(), items[item], Toast.LENGTH_SHORT).show(); } }); AlertDialog alert = builder.create();
O segundo parmetro no mtodo setSingleChoiceItems() um valor inteiro para o checkedItem, que indica a posio de lista com base zero do item selecionado padro. Use "-1" para indicar que nenhum item deve ser selecionado por padro.
Criar um ProgressDialog
A ProgressDialog uma extenso da classe AlertDialog que pode exibir uma animao de progresso na forma de uma roda, para uma tarefa com o progresso indefinido, ou uma barra de progresso, para uma tarefa que tem uma progresso definida. O dilogo tambm pode fornecer botes, como um de cancelar um download. Abrir uma janela de progresso pode ser to simples como chamar
ProgressDialog.show(). Por exemplo, o dilogo mostrado acima pode ser facilmente alcanado sem gerenciar o dilogo atravs da chamada onCreateDialog(int), conforme mostrado abaixo: ProgressDialog dialog = ProgressDialog.show(MyActivity.this, "", "Loading. Please wait...", true);
162
O primeiro parmetro a aplicao Context, o segundo um ttulo para o dilogo (vazio), o terceiro a mensagem e o ltimo parmetro se o progresso indeterminado (isso s relevante quando cria uma barra de progresso, que discutido na prxima seo). O estilo padro de um dilogo de progresso a roda. Se voc deseja criar uma barra de progresso que mostra o progresso do carregamento com granularidade, mais cdigo necessrio, como ser discutido na prxima seo.
Para mostrar a progresso com uma barra de progresso animada: 1. Inicialize o ProgressDialog com o construtor da classe,
setProgressStyle(int) e defina as outras propriedades, como a mensagem. 3. Quando estiver pronto para mostrar o dilogo, chame show() ou devolva o ProgressDialog do onCreateDialog(int) de retorno. 4. Voc pode incrementar a quantidade de progresso exibida na barra chamando tanto setProgress(int) com um valor para a porcentagem total concluda ou incrementProgressBy(int) com um valor incremental para adicionar porcentagem total concluda at agora. Por exemplo, sua configurao pode se parecer como esta:
ProgressDialog progressDialog; progressDialog = new ProgressDialog(mContext); progressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL); progressDialog.setMessage("Loading..."); progressDialog.setCancelable(false);
163
A configurao simples. A maior parte do cdigo necessrio para criar um dilogo de progresso est realmente envolvida no processo que atualiz-lo. Voc pode achar que necessrio criar um segundo thread em sua aplicao para este trabalho e, em seguida, relatar o progresso de volta atividade do thread de interface do usurio com um Handler do objeto. Se voc no est familiarizado com o uso de threads adicionais com um manipulador, vejo o exemplo abaixo, que utiliza um segundo thread para incrementar um dilogo de progresso gerido pela atividade. Exemplo ProgressDialog com um segundo thread Este exemplo usa um segundo thread para acompanhar o andamento de um processo (que na verdade s conta at 100). O thread envia uma Message de volta atividade principal atravs de um Handler a cada hora em que algum progresso feito. A atividade principal, em seguida, atualiza o ProgressDialog.
package com.example.progressdialog; import android.app.Activity; import android.app.Dialog; import android.app.ProgressDialog; import android.os.Bundle; import android.os.Handler; import android.os.Message; import android.view.View; import android.view.View.OnClickListener; import android.widget.Button; public class NotificationTest extends Activity { static final int PROGRESS_DIALOG = 0; Button button; ProgressThread progressThread; ProgressDialog progressDialog; /** Called when the activity is first created. */ public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); // Setup the button that starts the progress dialog button = (Button) findViewById(R.id.progressDialog); button.setOnClickListener(new OnClickListener(){ public void onClick(View v) { showDialog(PROGRESS_DIALOG); } }); } protected Dialog onCreateDialog(int id) {
164
switch(id) { case PROGRESS_DIALOG: progressDialog = new ProgressDialog(NotificationTest.this); progressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL); progressDialog.setMessage("Loading..."); return progressDialog; default: return null; } } @Override protected void onPrepareDialog(int id, Dialog dialog) { switch(id) { case PROGRESS_DIALOG: progressDialog.setProgress(0); progressThread = new ProgressThread(handler); progressThread.start(); } // Define the Handler that receives messages from the thread and update the progress final Handler handler = new Handler() { public void handleMessage(Message msg) { int total = msg.arg1; progressDialog.setProgress(total); if (total >= 100){ dismissDialog(PROGRESS_DIALOG); progressThread.setState(ProgressThread.STATE_DONE); } } }; /** Nested class that performs progress calculations (counting) */ private class ProgressThread extends Thread { Handler mHandler; final static int STATE_DONE = 0; final static int STATE_RUNNING = 1; int mState; int total; ProgressThread(Handler h) { mHandler = h; } public void run() { mState = STATE_RUNNING; total = 0; while (mState == STATE_RUNNING) { try { Thread.sleep(100); } catch (InterruptedException e) { Log.e("ERROR", "Thread Interrupted"); } Message msg = mHandler.obtainMessage(); msg.arg1 = total;
165
mHandler.sendMessage(msg); total++; } } /* sets the current state for the thread, * used to stop the thread */ public void setState(int state) { mState = state; } } }
Esta XML define um ImageView e um TextView dentro de um LinearLayout. 2. Definir o layout acima como o contedo da View da caixa de dilogo e definir o contedo dos elementos ImageView e TextView:
166
Context mContext = getApplicationContext(); Dialog dialog = new Dialog(mContext); dialog.setContentView(R.layout.custom_dialog); dialog.setTitle("Custom Dialog"); TextView text = (TextView) dialog.findViewById(R.id.text); text.setText("Hello, this is a custom dialog!"); ImageView image = (ImageView) dialog.findViewById(R.id.image); image.setImageResource(R.drawable.android);
Depois de instanciar o dilogo, definir o layout personalizado de contedo como contedo da View da caixa de dilogo com setContentView(int), passando o ID do recurso de layout. Agora que o dilogo tem um layout definido, voc pode capturar objetos View do layout com findViewById(int) e modificar seu contedo. 3. isso a. Agora voc pode mostrar o dilogo como descrito em Mostrando um Dilogo. Um dilogo feito com a classe de dilogo base deve ter um ttulo. Se voc no chamar setTitle(), o espao usado para o ttulo continua vazio, mas ainda visvel. Se voc no quer um ttulo a todos, ento voc deve criar o seu dilogo personalizado usando a classe AlertDialog. No entanto, porque um AlertDialog mais fcilmente criado com o AlertDialog.Builder, voc no tem acesso ao mtodo setContentView(int) utilizado acima. Em vez disso, voc deve usar setView(View). Este mtodo aceita um objeto View, por isso necessrio inflar o layout do objeto View da raiz do XML. Para inflar o layout XML, recuperar o LayoutInflater com getLayoutInflater() (ou getSystemService()), e depois chamar inflate(int, ViewGroup), onde o primeiro parmetro o ID do recurso layout e o segundo a identificao da View raiz. Neste ponto, voc pode usar o layout inflado para encontrar objetos View no layout e definir o contedo dos elementos ImageView e TextView. Ento instanciar o
AlertDialog.Builder e definir o layout inflados para o dilogo com setView(View). Aqui est um exemplo, criando um layout personalizado em um AlertDialog:
AlertDialog.Builder builder; AlertDialog alertDialog; Context mContext = getApplicationContext(); LayoutInflater inflater = (LayoutInflater)
167
mContext.getSystemService(LAYOUT_INFLATER_SERVICE); View layout = inflater.inflate(R.layout.custom_dialog, (ViewGroup) findViewById(R.id.layout_root)); TextView text = (TextView) layout.findViewById(R.id.text); text.setText("Hello, this is a custom dialog!"); ImageView image = (ImageView) layout.findViewById(R.id.image); image.setImageResource(R.drawable.android); builder = new AlertDialog.Builder(mContext); builder.setView(layout); alertDialog = builder.create();
Usando um AlertDialog para o seu layout personalizado permite-lhe tirar partido das funcionalidades incorporadas AlertDialog como botes geridos, listas selecionveis, um ttulo, um cone e assim por diante.
168
Manipulando eventos de UI
No Android, h mais de um caminho para interceptar os eventos de interao do usurio com seu aplicativo. Ao considerar os eventos dentro de sua interface de usurio, a abordagem consiste em capturar os eventos do objeto View especfico com que o usurio interage. A classe View fornece os meios para faz-lo. Entre as diversas classes View que voc usar para compor seu layout, voc pode observar vrios mtodos de retorno pblicos que paream teis para eventos de UI. Esses mtodos so chamados pelo framework Android, quando a respectiva ao ocorre no objeto. Por exemplo, quando uma exibio (como um boto) tocada, o mtodo onTouchEvent() chamado no objeto. No entanto, a fim de interceptar isso, voc deve estender a classe e substituir o mtodo. No entanto, estender cada objeto View, a fim de lidar com um evento como esse no seria prtico. por isso que a classe View tambm contm uma coleo de interfaces aninhadas com callbacks que podem ser muito mais fcil de definir. Essas interfaces, chamadas de event listeners, so o seu bilhete para capturar a interao do usurio com sua interface do usurio. Enquanto voc vai utilizar mais comumente os ouvintes de evento para receber a interao do usurio, pode chegar um momento em que voc quer estender uma classe, no intuito de construir um componente personalizado. Talvez voc queira estender a classe Button para fazer algo mais extravagante. Neste caso, voc ser capaz de definir o comportamento de eventos padro para sua classe usando a classe de manipuladores de eventos.
Os ouvintes de eventos
Um receptor de evento uma interface na classe View que contm um mtodo de retorno nico. Esses mtodos sero chamados pelo framework Android quando o View para o receptor tenha sido registado desencadeada pela interao do usurio com o item na interface do usurio.
169
Includo nas interfaces de ouvinte de evento so os mtodos de retorno seguintes: onClick() A partir do View.OnClickListener. chamado quando o usurio toca o item (quando em modo de tocar), ou incide sobre o item com a navegao por teclas ou trackball e pressiona a tecla "enter" ou pressiona o trackball. onLongClick() De View.OnLongClickListener. Isto chamado quando o usurio toca e prende o item (quando no modo de tocar), ou incide sobre o item com a navegao por teclas ou trackball e pressiona e mantm a tecla "enter" ou pressiona e mantm pressionada a trackball (por um segundo). onFocusChange() De View.OnFocusChangeListener. Isto chamado quando o usurio navega para ou longe do ponto, utilizando atalhos ou trackball. onKey() De View.OnKeyListener. Isto chamado quando o usurio est centrado sobre o item e pressiona ou solta uma tecla no dispositivo. onTouch() De View.OnTouchListener. Isto chamado quando o usurio executa uma ao qualificada como um evento de toque, incluindo pressionar, soltar, ou qualquer movimento na tela (dentro dos limites do item). onCreateContextMenu() De View.OnCreateContextMenuListener. Isto chamado quando um menu de contexto est sendo construdo (como o resultado de um "clique longo" sustentado). Esses mtodos so os nicos habitantes da suas respectivas interfaces. Para definir um desses mtodos e lidar com seus eventos, implemente a interface aninhada em sua
170
atividade ou defina-a como uma classe annima. Em seguida, passe uma instncia da sua aplicao com os respectivos mtodos View.set...Listener(). (Por exemplo, chamar setOnClickListener() e pass-la a implementao do OnClickListener). O exemplo abaixo mostra como registrar um receptor no clique de um boto.
// Create an anonymous implementation of OnClickListener private OnClickListener mCorkyListener = new OnClickListener() { public void onClick(View v) { // do something when the button is clicked } }; protected void onCreate(Bundle savedValues) { ... // Capture our button from layout Button button = (Button)findViewById(R.id.corky); // Register the onClick listener with the implementation above button.setOnClickListener(mCorkyListener); ... }
Voc tambm pode achar mais conveniente para implementar OnClickListener como parte de sua atividade. Isso ir evitar a carga horria extra e alocao de objetos. Por exemplo:
public class ExampleActivity extends Activity implements OnClickListener { protected void onCreate(Bundle savedValues) { ... Button button = (Button)findViewById(R.id.corky); button.setOnClickListener(this); } // Implement the OnClickListener callback public void onClick(View v) { // do something when the button is clicked } ... }
Observe que a chamada de onClick()no exemplo acima no tem valor de retorno, mas alguns mtodos ouvintes devem retornar um boolean. A razo depende do evento. Para os poucos que o fazem, aqui est o porqu: onLongClick() - Retorna um booleano para indicar se voc tem consumido o evento e que no deve ser levado adiante. Ou seja, retornar true para indicar que voc tem tratado o evento e deve parar por aqui; retornar false se voc no tem
171
lidado com isso e/ou o evento deve continuar para qualquer outro receptor onclick. onKey() - Retorna um booleano para indicar se voc tem consumido o evento e que no deve ser levada adiante. Ou seja, retornar true para indicar que voc tem tratado o evento e deve parar por aqui; retornar false se voc no tem lidado com isso e/ou o evento deve continuar a todo ouvinte on-key. onTouch() - Retorna um booleano para indicar se o ouvinte consome este evento. O importante que este evento pode ter vrias aes que se sucedem. Ento, se voc retornar falso quando o evento de ao abaixo recebido, voc indica que no consumiram o evento e tambm no esto interessados em aes subseqentes deste evento. Assim, voc no ser chamado para outras aes dentro do evento, como um gesto do dedo, ou um eventual evento de ao acima. Lembre-se que os principais eventos so sempre entregues para a corrente View em foco. Eles so enviados a partir do topo da hierarquia de View e, em seguida, para baixo, at chegar ao destino apropriado. Se a sua view (ou filho de sua view) atualmente tem o foco, ento voc pode ver o curso de eventos atravs do mtodo dispatchKeyEvent(). Como alternativa captura de eventos-chave atravs da sua view, voc tambm pode receber todos os eventos dentro de sua atividade com onKeyDown() e onKeyUp(). Nota: O Android vai chamar os manipuladores de eventos e depois os manipuladores padro apropriados a partir da definio de segunda classe. Como tal, retornando true destes ouvintes de evento ir parar a propagao do evento para ouvintes de eventos e tambm ir bloquear o retorno de chamada para o manipulador de eventos padro no View. Ento, tenha a certeza de que deseja encerrar o caso quando voc retornar true.
Manipuladores de eventos
Se voc est construindo um componente personalizado de view, ento voc vai ser capaz de definir vrios mtodos de retorno usados como manipuladores de eventos padro. No documento Construindo Componentes Personalizados, voc aprender a ver alguns dos retornos comuns usados para tratamento de eventos, incluindo:
172
onKeyDown(int, KeyEvent) - Chamado quando um evento de nova tecla ocorre. onKeyUp(int, KeyEvent) - Chamado quando um evento de tecla para cima ocorre. onTrackballEvent(MotionEvent) - Chamado quando um evento de movimento de trackball ocorre. onTouchEvent(MotionEvent) - Chamado quando um evento do movimento da tela de toque ocorre. onFocusChanged(boolean, int, Rect) - Chamado quando a view ganha ou perde o foco. Existem alguns outros mtodos que voc deve estar ciente de que no so parte da classe View, mas podem impactar diretamente a forma como voc capaz de manipular eventos. Portanto, ao gerenciar eventos mais complexos dentro de um layout, considere estes outros mtodos: Activity.dispatchTouchEvent(MotionEvent) - Isso permite que sua atividade possa interceptar todos os eventos de toque antes de serem enviados para a janela. ViewGroup.onInterceptTouchEvent(MotionEvent) - Isso permite que um ViewGroup possa assistir a eventos como eles so distribudos aos views filhos. ViewParent.requestDisallowInterceptTouchEvent(boolean) - Chamar esta em cima de um pai view para indicar que ela no deve interceptar eventos de contato com onInterceptTouchEvent(MotionEvent) .
Modo de toque
Quando um usurio est navegando uma interface de usurio com as teclas direcionais ou um trackball, necessrio dar ateno aos itens de recurso (como botes) que o usurio possa ver o que vai aceitar a entrada. Se o dispositivo tem capacidades de toque, no entanto, o usurio comea a interagir com a interface ao toc-lo, ento ele no mais
173
necessrio para destacar itens, ou dar enfoque a uma viso particular. Assim, existe um modo de interao com o nome "modo de toque." Para um dispositivo sensvel ao toque, uma vez que o usurio toca a tela, o aparelho entra em modo de tocar. Deste ponto em diante, somente as views em que o isFocusableInTouchMode() est true podero ser focadas, como os widgets de edio de texto. Outros views que so palpveis, como botes, no vo tirar o foco quando tocado; eles vo simplesmente focar seus ouvintes com um clique, quando pressionados. Toda vez que um usurio pressiona uma tecla direcional ou rola com uma trackball, o aparelho sair do modo de tocar, e encontrar um visual de tirar o foco. Agora, o usurio pode continuar interagindo com a interface do usurio sem tocar na tela. O estado modo de tocar mantido ao longo de todo o sistema (todas as janelas e atividades). Para consultar o estado atual, voc pode chamar isInTouchMode() para ver se o dispositivo est no modo de tocar.
Manipulao do foco
O framework vai lidar com as rotinas de movimento do foco em resposta entrada do usurio. Isso inclui a mudana do foco nas views que so removidas ou escondidas, ou quando as views novos se tornam disponveis. Views indicam a sua disponibilidade para tirar o foco atravs do mtodo isFocusable(). Para definir se uma View pode tirar o foco, chame setFocusable(). Quando em modo de tocar, voc pode consultar se uma View permite focar com isFocusableInTouchMode(). Voc pode mudar isso com setFocusableInTouchMode(). Movimento do foco baseado em um algoritmo que encontra o vizinho mais prximo em uma determinada direo. Em casos raros, o algoritmo padro pode no coincidir com o comportamento desejado para o desenvolvedor. Nessas situaes, voc pode fornecer substituies explcitas com os atributos XML a seguir no arquivo de layout: nextFocusDown, nextFocusLeft, nextFocusRight, e nextFocusUp. Adicione um desses atributos para o View a partir do qual o foco est saindo. Defina o valor do atributo a ser o ID do view para quem o foco deve ser dado. Por exemplo:
174
<LinearLayout android:orientation="vertical" ... > <Button android:id="@+id/top" android:nextFocusUp="@+id/bottom" ... /> <Button android:id="@+id/bottom" android:nextFocusDown="@+id/top" ... /> </LinearLayout>
Normalmente, neste layout vertical, navegando a partir do primeiro boto no leva a lugar nenhum, nem iria navegar abaixo do segundo boto. Agora que o boto superior foi definido como um fundo com o nextFocusUp (e vice-versa), o foco de navegao ir circular de cima para baixo e de baixo para cima. Se voc gostaria de declarar o view como passvel de foco em sua interface do usurio (quando no tradicional), adicione o atributo XML android:focusable para a view, na sua declarao de layout. Defina o valor true. Voc pode tambm declarar uma view como passvel de foco enquanto em modo de toque com
android:focusableInTouchMode. Para solicitar uma exibio especial para ter foco, chame requestFocus(). Para ouvir os eventos de foco (ser notificado quando um view recebe ou perde foco), use onFocusChange().
175
Notificar o usurio
Vrios tipos de situaes podem surgir que requerem a notificao do usurio sobre um evento que ocorre em sua aplicao. Alguns eventos requerem que o usurio responda e outros no. Por exemplo: Quando um evento como salvar um arquivo for concluda, uma pequena mensagem deve aparecer para confirmar que o salvamento foi bem sucedido. Se o aplicativo executado em segundo plano e requer ateno do usurio, o aplicativo deve criar uma notificao que permite ao usurio responder a convenincia dele ou dela. Se o aplicativo est executando o trabalho que o usurio deve aguardar (como carregar um arquivo), o aplicativo deve mostrar uma roda de progresso pairando ou uma barra. Cada uma dessas tarefas de notificao podem ser conseguidas usando uma tcnica diferente: Uma notificao brinde, por breves mensagens que vm do fundo. Uma notificao na barra de status, lembretes persistentes que vm do fundo e solicitam resposta do usurio. Uma notificao de dilogo, para as notificaes de atividades relacionadas.
Notificao brinde
Uma notificao brinde uma mensagem que aparece na superfcie da janela. Ela s enche o espao necessrio para a mensagem e a atividade atual do usurio permanece visvel e interativa. A notificao automaticamente desaparece, e no aceita eventos de interao. Como um brinde pode ser criado a partir de um servio em background, aparece mesmo que o aplicativo no esteja visvel.
176
Um brinde melhor para mensagens de texto curtas, como "Arquivo salvo", quando voc est bastante certo de que o usurio est prestando a ateno na tela. Um brinde no pode aceitar eventos de interao do usurio, se voc gostaria que o usurio respondesse e agisse, considere usar uma notificao na barra de status.
Este exemplo demonstra tudo o que precisa para a maioria das notificaes brinde. Raramente necessrio algo a mais. Voc pode, no entanto, querer a posio do brinde diferente ou at mesmo usar o seu prprio layout, em vez de uma simples mensagem de texto. As sees a seguir descrevem como voc pode fazer essas coisas.
177
Posicionar o seu brinde Uma notificao brinde padro aparece perto da parte inferior da tela, centralizado horizontalmente. Voc pode alterar esta posio com o mtodo setGravity(int, int, int). Este aceita trs parmetros: a constante Gravity, um deslocamento da posio x e um deslocamento da posio y. Por exemplo, se voc decidir que o brinde deve aparecer no canto superior esquerdo, voc pode definir a gravidade como este:
toast.setGravity(Gravity.TOP|Gravity.LEFT, 0, 0);
Se voc quiser deslocar a posio para a direita, aumente o valor do segundo parmetro. Para empurr-lo para baixo, aumente o valor do ltimo parmetro. Criando uma exibio personalizada brinde Se uma mensagem de texto simples no suficiente, voc pode criar um layout personalizado para a sua notificao brinde. Para criar um layout personalizado, definir um layout de view, em XML ou no cdigo do aplicativo, e passar a View raiz para o mtodo setView(View). Por exemplo, voc pode criar o layout para o brinde visvel na imagem esquerda, com o seguinte XML (salvo como toast_layout.xml):
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/toast_layout_root" android:orientation="horizontal" android:layout_width="fill_parent" android:layout_height="fill_parent" android:padding="10dp" android:background="#DAAA" > <ImageView android:id="@+id/image" android:layout_width="wrap_content" android:layout_height="fill_parent" android:layout_marginRight="10dp" /> <TextView android:id="@+id/text"
178
Observe que a identificao do elemento LinearLayout "toast_layout". Voc deve usar essa identificao para inflar o layout do XML, como mostrado aqui:
LayoutInflater inflater = getLayoutInflater(); View layout = inflater.inflate(R.layout.toast_layout, (ViewGroup) findViewById(R.id.toast_layout_root)); ImageView image = (ImageView) layout.findViewById(R.id.image); image.setImageResource(R.drawable.android); TextView text = (TextView) layout.findViewById(R.id.text); text.setText("Hello! This is a custom toast!"); Toast toast = new Toast(getApplicationContext()); toast.setGravity(Gravity.CENTER_VERTICAL, 0, 0); toast.setDuration(Toast.LENGTH_LONG); toast.setView(layout); toast.show();
Primeiro, recupere o LayoutInflater com getLayoutInflater() (ou getSystemService()), e depois infle o layout de XML usando inflate(int, ViewGroup). O primeiro parmetro o ID do recurso layout e o segundo a View raiz. Voc pode usar esse layout inflado para encontrar mais objetos view no layout, agora capturar e definir o contedo dos elementos ImageView e TextView. Finalmente, crie um novo brinde com Toast(Context) e defina algumas propriedades do brinde, tais como a gravidade e durao. Em seguida, chame setView(View) e passe seu layout inflado. Agora voc pode exibir o brinde com o seu layout personalizado, chamando show(). Nota: No use o construtor pblico para um brinde, a menos que v definir o layout com setView(View). Se voc no tem um layout personalizado para o uso, voc deve usar makeText(Context, int, int) para criar o Toast.
179
expandida, o Android aciona uma Intent que definida pela notificao (geralmente para lanar uma Activity). Voc tambm pode configurar a notificao para alertar o usurio com um som, uma vibrao e as luzes piscando no dispositivo. Este tipo de notificao ideal quando o aplicativo est funcionando em um servio de fundo e h necessidade de notificar o usurio sobre um evento. Se voc precisa alertar o usurio sobre um evento que ocorre durante a sua atividade que ainda est em foco, considere usar uma notificao de dilogo em vez disso.
A imagem seguinte mostra mensagem expandida de notificao na janela "Notificaes". O usurio pode visualizar a janela de notificaes, puxando para baixo a barra de status (ou selecionando Notificaes no menu de opes da Home).
O Bsico Uma Activity ou Service pode iniciar uma notificao na barra de status. Porque uma atividade pode executar aes somente quando ela est ativa e em foco, voc deve criar suas notificaes de um servio. Desta forma, a notificao pode ser criada a partir do ANDROID, uma viso geral Anderson Duarte de Amorim
180
fundo, enquanto o usurio est usando outra aplicao ou quando o dispositivo estiver dormindo. Para criar uma notificao, voc deve usar duas classes: Notification e NotificationManager. Use uma instncia da classe Notification para definir as propriedades de sua notificao na barra de status, como o cone da barra de status, a mensagem expandida e configuraes extras, como um som para tocar. O NotificationManager um servio do sistema Android que executa e gerencia todas as notificaes. Voc no pode instanciar o NotificationManager. A fim de dar-lhe a sua notificao, voc deve recuperar uma referncia para o NotificationManager com getSystemService() e ento, quando voc quer notificar o usurio, pass-lo com seu objeto de notificao notify(). Para criar uma notificao de barra de status: 1. Obtenha uma referncia para o NotificationManager:
String ns NotificationManager getSystemService(ns); = Context.NOTIFICATION_SERVICE; mNotificationManager = (NotificationManager)
2. Instanciar a notificao:
int icon = R.drawable.notification_icon; CharSequence tickerText = "Hello"; long when = System.currentTimeMillis(); Notification notification = new Notification(icon, tickerText, when);
181
Gerenciando suas notificaes O NotificationManager um servio do sistema que gerencia todas as notificaes. Voc deve obter uma referncia a ele com o mtodo getSystemService(). Por exemplo:
String ns = Context.NOTIFICATION_SERVICE; NotificationManager mNotificationManager = (NotificationManager) getSystemService(ns);
Quando voc quiser enviar sua notificao na barra de status, passar o objeto de notificao ao NotificationManager com notify(int, Notification). O primeiro parmetro o ID nico para a notificao e o segundo o objeto de notificao. O ID identifica a notificao a partir da sua aplicao. Isso necessrio se voc precisa atualizar a notificao (se o aplicativo gerencia diferentes tipos de notificaes) ou selecionar a ao apropriada quando o usurio retornar para a sua aplicao atravs da inteno definida na notificao. Para apagar a notificao de barra de status quando o usurio seleciona a partir da janela de notificaes, adicione a flag "FLAG_AUTO_CANCEL" de seu objeto de notificao. Voc tambm pode limpar manualmente com cancel(int), passando-lhe a identificao ou notificao ou limpar todas as suas notificaes com cancelAll(). Criando uma notificao Um objeto Notification define os detalhes da mensagem de notificao que exibida na barra de status e janela de "Notificaes", e qualquer alerta de outras configuraes, tais como sons e luzes piscando. Uma notificao de barra de status exige o seguinte: Um cone da barra de status Uma mensagem expandida e ttulo para o modo expandido (a menos que voc defina uma exibio personalizada ampliada) Um PendingIntent, para ser acionado quando a notificao for selecionada As configuraes opcionais para a notificao de barra de status incluem: Uma mensagem de texto-relgio para a barra de status Um som de alerta ANDROID, uma viso geral Anderson Duarte de Amorim
182
Uma configurao vibrar Uma definio LED piscando O kit de arranque para uma nova notificao inclui o construtor Notification(int, CharSequence, long) e o mtodo setLatestEventInfo(Context, CharSequence,
CharSequence, PendingIntent). Estes definem todas as definies necessrias para uma notificao. O trecho a seguir demonstra a configurao de notificao de base:
int icon = R.drawable.notification_icon; // icon from resources CharSequence tickerText = "Hello"; // ticker-text long when = System.currentTimeMillis(); // notification time Context context = getApplicationContext(); // application Context CharSequence contentTitle = "My notification"; // expanded message title CharSequence contentText = "Hello World!"; // expanded message text Intent notificationIntent = new Intent(this, MyClass.class); PendingIntent contentIntent = PendingIntent.getActivity(this, 0, notificationIntent, 0); // the next two lines initialize the Notification, using the configurations above Notification notification = new Notification(icon, tickerText, when); notification.setLatestEventInfo(context, contentTitle, contentText, contentIntent);
Atualizando a notificao Voc pode atualizar as informaes em sua notificao de barra de status como eventos que continuam a ocorrer em seu aplicativo. Por exemplo, quando uma nova mensagem de texto SMS chega antes que as mensagens anteriores foram lidas, o aplicativo de mensagens atualiza as notificaes existentes para exibir o nmero total de novas mensagens recebidas. Esta prtica, de uma atualizao de notificao existente muito melhor do que a adio de novas notificaes NotificationManager porque evita a desordem na janela de notificaes. Porque cada notificao unicamente identificada pelo NotificationManager com um nmero de identificao inteiro, voc pode revisar a notificao chamando setLatestEventInfo() com novos valores, mudar alguns valores de campo da notificao, e depois chamar notify() novamente. Voc pode rever cada propriedade com os campos de membro de objeto (exceto para o contexto e no ttulo da mensagem expandida e texto). Voc deve sempre revisar a mensagem de texto quando voc atualizar a notificao chamando setLatestEventInfo() com novos valores para contentTitle e contentText. Em seguida, chamar notify() para
183
atualizar a notificao. (Claro, se voc criou uma exibio personalizada expandida, atualizar esses valores de texto e ttulo no ter efeito) Adicionando um som Voc pode alertar o usurio com o som de notificao padro (que definido pelo usurio) ou com um som especificado pelo seu aplicativo. Para utilizar o usurio padro do som, adicione "DEFAULT_SOUND" para o campo de padres:
notification.defaults |= Notification.DEFAULT_SOUND;
Para usar um som diferente com as suas notificaes, passe uma referncia URI para o campo de som. O exemplo a seguir usa um arquivo de udio conhecido gravado no carto SD do dispositivo:
notification.sound = Uri.parse("file:///sdcard/notification/ringer.mp3");
Neste caso, a identificao exata do arquivo de mdia ("6") conhecido e anexado ao contedo Uri. Se voc no souber a identificao exata, voc deve consultar todos os meios disponveis no MediaStore com ContentResolver. Se voc deseja que o som repeta continuamente at que o usurio responda notificao ou a notificao seja cancelada, adicione "FLAG_INSISTENT" para o campo de sinalizadores. Nota: Se o campo padro inclui "DEFAULT_SOUND", ento o som padro substitui qualquer som definido pelo campo de som. Adicionando vibrao Voc pode alertar o usurio com o modelo padro de vibrao ou com um modelo de vibrao definido pelo seu aplicativo. Para usar o modelo padro, adicione "DEFAULT_VIBRATE" para o campo de padres:
184
notification.defaults |= Notification.DEFAULT_VIBRATE;
Para definir o seu padro de vibrao prpria, passe uma matriz de valores longos para o campo vibrar:
long[] vibrate notification.vibrate = vibrate; = {0,100,200,300};
O longo array define o padro alternado para o comprimento de vibrao e desligando (em milissegundos). O primeiro valor o tempo de espera (desligado) antes de comear, o segundo valor o comprimento da primeira vibrao, o terceiro o comprimento da prxima, e assim por diante. O padro pode ser to longo quanto queira, mas no pode ser configurado para repetir. Nota: Se o campo padro inclui "DEFAULT_VIBRATE", ento a vibrao padro substitui qualquer vibrao definida pelo campo vibrate. Adicionando luzes a piscar Para alertar o usurio com luzes LED, voc pode implementar o modelo de luz padro (se disponvel), ou definir sua prpria cor e padro para as luzes. Para usar a configurao padro de luz, acrescentar "DEFAULT_LIGHTS" para o campo de padres:
notification.defaults |= Notification.DEFAULT_LIGHTS;
Para definir sua prpria cor e padro, definir um valor para o campo ledARGB (para a cor), o campo ledOffMS (perodo de tempo, em milsimos de segundo, para manter a luz apagada), o ledOnMS (perodo de tempo, em milissegundos, para manter a luz acesa), e tambm adicionar "FLAG_SHOW_LIGHTS" para o campo flags:
notification.ledARGB = notification.ledOnMS = notification.ledOffMS = notification.flags |= Notification.FLAG_SHOW_LIGHTS; 0xff00ff00; 300; 1000;
Neste exemplo, a luz verde pisca vrias vezes a cada 300 milsimos de segundo e desliga por um segundo. Nem todas as cores no espectro so suportadas pelo dispositivo de LEDs, e no todo dispositivo que suporta as mesmas cores, ento o hardware estima para o melhor de sua capacidade. Verde a cor mais comum de notificao.
185
Mais recursos Voc pode adicionar vrias caractersticas a mais s suas notificaes usando campos de notificao e flags. Algumas caractersticas teis incluem o seguinte: "FLAG_AUTO_CANCEL" Adicione isto ao campo de sinalizadores para cancelar automaticamente a notificao depois que ela selecionada a partir da janela de notificaes. "FLAG_INSISTENT" Adicione isto ao campo de sinalizadores para repetir o udio at que o usurio responda. "FLAG_ONGOING_EVENT" Adicione isto ao campo de sinalizadores para agrupar notificaes ao abrigo do ttulo "em curso" da janela de notificaes. Isso indica que o aplicativo est em curso - seus processos ainda esto em execuo em segundo plano, mesmo quando o aplicativo no visvel (como a msica ou uma chamada de telefone). "FLAG_NO_CLEAR" Adicione isto ao campo de sinalizadores para indicar que a notificao no deve ser limpa pelo boto "Limpar notificaes". Isso particularmente til se a sua notificao est em curso. nmero Esse valor indica o nmero atual de eventos representados pela notificao. O nmero apropriado sobreposto em cima do cone da barra de status. Se voc pretende usar esse campo, ento voc deve comear com "1" quando a notificao for criado pela primeira vez. (Se voc alterar o valor de zero para qualquer coisa maior durante uma atualizao, o nmero no mostrado.)
186
iconLevel Esse valor indica o nvel atual de um LevelListDrawable que usado para o cone de notificao. Voc pode animar o cone na barra de status, alterando esse valor para correlacionar com os drawable definido em um LevelListDrawable. Criar uma exibio personalizada expandida Por padro, o modo expandido utilizado na janela "Notificaes" inclui um ttulo de base e mensagem de texto. Estes so definidos por parmetros contentText e contentTitle do mtodo setLatestEventInfo(). No entanto, voc tambm pode definir um layout personalizado para o modo de exibio expandido usando RemoteViews. A imagem direita mostra um exemplo de uma exibio personalizada alargada, que usa um ImageView e TextView em LinearLayout. Para definir seu prprio layout para a mensagem expandida, instancie um objeto RemoteViews e passe-o para o campo contentView da sua notificao. Passe o PendingIntent ao campo contentIntent. Criar uma exibio personalizada expandido mais bem entendido com um exemplo: 1. Criar o layout XML para a exibio expandida. Por exemplo, crie um arquivo chamado layout custom_notification_layout.xml e construa-o assim:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="horizontal" android:layout_width="fill_parent" android:layout_height="fill_parent" android:padding="3dp" > <ImageView android:id="@+id/image" android:layout_width="wrap_content" android:layout_height="fill_parent" android:layout_marginRight="10dp" /> <TextView android:id="@+id/text" android:layout_width="wrap_content" android:layout_height="fill_parent" android:textColor="#000" /> </LinearLayout>
187
Este esquema utilizado para a visualizao expandida, mas o contedo do ImageView e TextView ainda precisam ser definidos pelo aplicativo. RemoteViews oferece alguns mtodos adequados que lhe permitem definir o contedo... 2. No cdigo do aplicativo, use os mtodos RemoveViews para definir a imagem e texto. Em seguida, passe o objeto RemoteViews ao campo contentView da notificao, conforme mostrado neste exemplo:
RemoteViews contentView = new RemoteViews(getPackageName(), R.layout.custom_notification_layout); contentView.setImageViewResource(R.id.image, R.drawable.notification_image); contentView.setTextViewText(R.id.text, "Hello, this message is in a custom expanded view"); notification.contentView = contentView;
Como mostrado aqui, passe o nome do aplicativo do pacote e a identificao de recursos de layout para o construtor RemoteViews. Em seguida, defina o contedo para o ImageView e TextView, usando o setImageViewResource() e setTextViewText(). Em cada caso, passe o ID de referncia do objeto View conveniente que voc deseja definir, juntamente com o valor para essa viso. Finalmente, o objeto RemoteViews passado para a notificao no mbito contentView. 3. Porque voc no precisa do mtodo setLatestEventInfo() quando usando uma exibio personalizada, voc deve definir as intenes para a notificao com o campo contentIntent, como neste exemplo:
Intent notificationIntent = new Intent(this, MyClass.class); PendingIntent contentIntent = PendingIntent.getActivity(this, 0, notificationIntent, 0); notification.contentIntent = contentIntent;
A classe RemoteViews tambm inclui mtodos que voc pode usar para facilmente adicionar um Chronometer ou ProgressBar na view expandida da notificao. Para obter mais informaes sobre como criar layouts personalizados com RemoteViews, consulte o RemoteViews.
188
Nota: Ao criar uma view expandida customizada, voc deve tomar cuidado especial para garantir que as funes personalizadas de seu layout haja corretamente no dispositivo em orientaes e resolues diferentes. Enquanto este conselho se aplica a todos os layouts view criados no Android, especialmente importante neste caso porque o seu layout de propriedade real muito restrito. Portanto, no faa o seu layout personalizado demasiado complexo e no se esquea de test-lo em vrias configuraes.
Notificao de dilogo
Um dilogo geralmente uma pequena janela que aparece na frente da atividade atual. A atividade perde o foco e o dilogo aceita a interao do usurio. Os dilogos so normalmente utilizados para notificaes e atividades curtas que se relacionem diretamente com a aplicao em curso. Voc deve usar uma caixa de dilogo quando voc precisa mostrar uma barra de progresso ou uma mensagem curta que requer a confirmao do usurio (como um alerta com "OK" e "Cancelar"). Voc pode usar tambm as janelas como parte integrante na interface do aplicativo e para outros fins alm de notificaes. Para uma discusso completa sobre todos os tipos disponveis de dilogos, incluindo seus usos para as notificaes, consulte Criando caixas de dilogo.
189
E transformar nisso:
<TextView style="@style/CodeFont" android:text="@string/hello" />
Todos os atributos relacionados com o estilo foram removidos do layout XML e colocado em uma definio de estilo chamado CodeFont, e depois aplicado com o atributo style. Voc ver a definio para esse estilo na seo seguinte. Um tema um estilo aplicado a toda uma Activity ou aplicao, ao invs de um indivduo View (como no exemplo acima). Quando um estilo aplicado como um tema, a cada view da atividade ou da aplicao sero aplicados cada propriedade de estilo que ele suporta. Por exemplo, voc pode aplicar o mesmo estilo CodeFont como um tema para uma atividade e, em seguida, todo o texto dentro dessa atividade dever ter fonte monoespaada verde.
Definio de estilos
Para criar um conjunto de estilos, salve um arquivo XML no diretrio res/values/ do seu projeto. O nome do arquivo XML arbitrrio, mas deve usar a extenso .xml e ser salvo na pasta res/values/. O n raiz do arquivo XML deve ser <resources>. Para cada estilo que voc quer criar, adicione um elemento <style> para o arquivo com um nome que identifica o estilo (este atributo obrigatrio). Em seguida, adicione um elemento <item> para cada propriedade desse estilo, com um nome que declara a ANDROID, uma viso geral Anderson Duarte de Amorim
190
propriedade de estilo e um valor para ir com ele (este atributo obrigatrio). O valor para o <item> pode ser uma seqncia de palavras-chave, uma cor hexadecimal, uma referncia a outro tipo de recurso, ou outro valor, dependendo da propriedade de estilo. Aqui est um exemplo de arquivo com um estilo nico:
<?xml version="1.0" encoding="utf-8"?> <resources> <style name="CodeFont" parent="@android:style/TextAppearance.Medium"> <item name="android:layout_width">fill_parent</item> <item name="android:layout_height">wrap_content</item> <item name="android:textColor">#00FF00</item> <item name="android:typeface">monospace</item> </style> </resources>
Cada filho do elemento <resources> convertido em um objeto de recurso do aplicativo em tempo de compilao, que pode ser referenciado pelo valor do atributo name do elemento <style>. Este estilo de exemplo pode ser referenciado a partir de um layout XML como @style/CodeFont (como demonstrado na introduo acima). O atributo parent no elemento <style> opcional e especifica o ID do recurso de um outro estilo a partir do qual este estilo deve herdar propriedades. Voc pode, ento, substituir as propriedades de estilo herdado se voc quiser. Lembre-se, um estilo que voc deseja usar como uma atividade ou tema de aplicao definido em XML exatamente do mesmo jeito que um estilo para uma view. Um estilo, como o definido acima pode ser aplicado como um estilo para uma nica view ou como um tema para uma atividade ou aplicao inteira. Como aplicar um estilo para uma viso nica ou como um tema de aplicao discutido mais tarde.
Herana
O atributo parent no elemento <style> permite que voc especifique um estilo a partir do qual o seu estilo deve herdar propriedades. Voc pode usar isso para herdar propriedades de um estilo existente e, em seguida, definir apenas as propriedades que deseja alterar ou acrescentar. Voc pode herdar de estilos que voc criou para si mesmo ou de diferentes estilos que esto construdos na plataforma (Veja Usando estilos e temas da plataforma abaixo, para obter informaes sobre herana de estilos definidos pela plataforma Android). Por exemplo, voc pode herdar a aparncia do texto padro da plataforma Android e, em seguida, modific-lo:
191
Se voc quer herdar os estilos que voc definiu para si mesmo, voc no tem que usar o atributo parent. Em vez disso, apenas preceda o nome do estilo que voc quer herdar ao nome do seu novo estilo, separados por um perodo. Por exemplo, para criar um novo estilo que herda o estilo CodeFont definido anteriormente, mas fazer a cor vermelha, voc pode criar o novo estilo como este:
<style name="CodeFont.Red"> <item name="android:textColor">#FF0000</item> </style>
Observe que no h atributo parent na tag <style>, mas porque o atributo name comea com a CodeFont nome do estilo (que um estilo que voc criou), este estilo herda todas as propriedades de estilo a partir desse estilo. Este estilo, em seguida, substitui a propriedade android:textColor para tornar o texto vermelho. Voc pode fazer referncia a este novo estilo como @style/CodeFont.Red. Voc pode continuar herdando assim tantas vezes quanto quiser, encadeando os nomes com os perodos. Por exemplo, voc pode estender CodeFont.Red ser maior, com:
<style name="CodeFont.Red.Big"> <item name="android:textSize">30sp</item> </style>
Este herda de ambos os estilos CodeFont e CodeFont.Red, em seguida, adiciona a propriedade android:textSize. Nota: Essa tcnica de herana por encadeando de nomes s funciona para estilos definidos por seus prprios recursos. Voc no pode herdar estilos internos do Android desta forma. Para fazer referncia a um estilo incorporado, como TextAppearance, voc deve usar o atributo parent.
Propriedades do estilo
Agora que voc entende como um estilo definido, preciso saber que tipo de propriedades de estilo definidas pelo <item> esto disponveis. Voc provavelmente est familiarizado com alguns j, como layout_width e textColor. Claro, h muito mais propriedades de estilo que voc pode usar.
192
O melhor lugar para encontrar propriedades que se aplicam a um determinado View a referncia de classe correspondente, que lista todos os atributos XML que so suportados. Por exemplo, todos os atributos listados na tabela de atributos XML TextView podem ser usados em uma definio de estilo para um elemento TextView (ou uma de suas subclasses). Um dos atributos listados na referncia android:inputType, ento onde voc normalmente poderia colocar o atributo android:inputType em um elemento <EditText>, assim:
<EditText android:inputType="number" ... />
Voc pode em vez disso criar um estilo para o elemento EditText que inclua esta propriedade:
<style name="Numbers"> <item name="android:inputType">number</item> ... </style>
Portanto, o seu XML para o esquema pode agora aplicar este estilo:
<EditText style="@style/Numbers" ... />
Este exemplo simples pode parecer dar mais trabalho, mas quando voc adiciona mais propriedades de estilo e fatores na possibilidade de voltar a usar o estilo em vrios lugares, o custo-beneficio pode ser enorme. Para uma referncia de todas as propriedades de estilo disponveis, consulte a referncia R.attr. Tenha em mente que todos os objetos view no aceitam todos os atributos de mesmo estilo, ento voc deve, normalmente, referenciar ao especfico View para as propriedades de estilo suportadas. Entretanto, se voc aplicar um estilo a uma exibio que no suporta todas as propriedades de estilo, o view ir aplicar apenas as propriedades que so suportadas e simplesmente ignorar os outros. Algumas propriedades de estilo, no entanto, no so suportadas por qualquer elemento View e s pode ser aplicado como um tema. Estas propriedades de estilo se aplicam a toda a janela e no a qualquer tipo de view. Por exemplo, propriedades de estilo para um tema podem ocultar o ttulo do aplicativo, ocultar a barra de status, ou mudar o fundo da
193
janela. Estes tipos de propriedades de estilo no pertencem a nenhum objeto View. Para descobrir essas propriedades de estilo theme-only, veja o R.attr de referncia para os atributos que comeam com window. Por exemplo, windowNoTitle e
windowBackground so propriedades de estilo que s so eficazes quando o estilo aplicado como um tema para uma atividade ou aplicao. Consulte a prxima seo para informaes sobre como aplicar um estilo como um tema. Nota: No se esquea de prefixo dos nomes das propriedades em cada elemento <item> com o android: namespace. Por exemplo: <item name="android:inputType">.
194
Agora este TextView ser denominado como definido pelo estilo chamado CodeFont. (Veja o exemplo acima, em Definio de estilos). Nota: O atributo style no usa o android: namespace prefix.
Se voc quer um tema aplicado a apenas uma atividade em seu aplicativo, ento, adicione o atributo android:theme ao tag <activity> um de cada vez. Assim como o Android oferece outros recursos internos, h muitos temas pr-definidos que podem ser usados, para evitar escrev-los sozinho. Por exemplo, voc pode usar o tema Dialog e fazer a sua actividade parecer como uma caixa de dilogo:
<activity android:theme="@android:style/Theme.Dialog">
Se voc gosta de um tema, mas quer ajust-lo, basta adicionar o tema como o parent do seu tema personalizado. Por exemplo, voc pode modificar o tradicional light theme para usar a sua prpria cor, como esta:
<color name="custom_theme_color">#b0b0ff</color> <style name="CustomTheme" parent="android:Theme.Light"> <item name="android:windowBackground">@color/custom_theme_color</item> <item name="android:colorBackground">@color/custom_theme_color</item> </style>
(Note que a cor precisa ser fornecida como um recurso separado aqui, porque o atributo android:windowBackground suporta apenas uma referncia a outro recurso, ao contrrio do android:colorBackground, a ele pode no ser dada uma cor literal.) Agora use CustomTheme em vez de Theme.Light dentro do Manifesto Android: ANDROID, uma viso geral Anderson Duarte de Amorim
195
<activity android:theme="@style/CustomTheme">
Para este tema usar o novo tema hologrfico quando o aplicativo est rodando o Android 3.0 (API Nvel 11) ou superior, voc pode colocar uma declarao alternativa para o tema em um arquivo XML em res/values-v11, mas fazer do tema me o tema hologrfico:
<style name="LightThemeSelector" parent="android:Theme.Holo.Light"> ... </style>
Agora, usar este tema como se fosse qualquer outro, e seu aplicativo passar automaticamente para o tema hologrfico se em execuo no Android 3.0 ou superior. Uma lista de atributos padro que voc pode usar em temas podem ser encontrados em R.styleable.Theme. Para obter mais informaes sobre o fornecimento de recursos alternativos, como os temas e layouts, com base na verso de plataforma ou configuraes de outro dispositivo, consulte o documento Fornecimento de Recursos.
196
sublinhados no nome do estilo, com um perodo. Por exemplo, voc pode aplicar o Theme_NoTitleBar tema com "@android:style/Theme.NoTitleBar". O R.style, entretanto, no bem documentado e no descreve minuciosamente os estilos, assim, ver o cdigo fonte para estes estilos e temas lhe dar uma compreenso melhor do que as propriedades de estilo de cada um oferece. Para uma melhor referncia para estilos e temas do Android, consulte os seguintes cdigos fonte: Android Styles (styles.xml) Android Temas (themes.xml) Esses arquivos vo te ajudar a aprender atravs do exemplo. Por exemplo, no cdigo fonte de temas Android, voc encontrar uma declarao de <style
name="Theme.Dialog">. Nesta definio, voc ver todas as propriedades que so usadas para estilo de dilogos que so usadas pelo framework Android. Para uma referncia de atributos de estilo disponveis que voc pode usar para definir um estilo ou tema (por exemplo, "windowBackground" ou "textAppearance"), ver R.attr ou a classe View para o qual voc est criando um estilo.
197
Recursos de aplicao
Voc deve sempre externar recursos como imagens e seqncias de seu cdigo de aplicao, para que voc possa mant-las de forma independente. Externalizar seus recursos tambm permite que voc fornea recursos alternativos que oferecem suporte a configuraes de dispositivos especficos, como lnguas ou tamanhos de tela diferentes, o que se torna cada vez mais importante quanto mais dispositivos com Android tornamse disponveis com configuraes diferentes. A fim de proporcionar compatibilidade com diferentes configuraes, voc deve organizar os recursos em seu diretrio do projeto res/, usando vrios sub-diretrios que agrupam os recursos por tipo e configurao.
Para qualquer tipo de recurso, voc pode especificar padro e vrios recursos alternativos para a sua aplicao: Os recursos padro so aqueles que devem ser utilizados independentemente da configurao do aparelho ou quando no existem recursos alternativos que correspondam configurao atual. Recursos alternativos so aqueles que voc j projetou para uso com uma configurao especfica. Para especificar que um grupo de recursos so de uma configurao especfica, acrescente um qualificador de configurao adequada ao nome do diretrio. ANDROID, uma viso geral Anderson Duarte de Amorim
198
Por exemplo, enquanto o seu layout padro de interface do usurio salvo no diretrio res/layout/, voc pode especificar um layout de interface diferente para ser usado quando a tela est na orientao paisagem, salvando-o no diretrio res/layout-land/. Android aplica automaticamente os recursos apropriados por correspondncia configurao atual do dispositivo para os nomes do diretrio de recursos. A figura 1 demonstra como um conjunto de recursos padro de um aplicativo so aplicados a dois dispositivos diferentes, quando no h recursos alternativos disponveis. A Figura 2 mostra o mesmo aplicativo com um conjunto de recursos alternativos que se qualificam para uma das configuraes do dispositivo, assim, os dois dispositivos usam recursos diferentes. A informao acima apenas uma introduo sobre como trabalhar os recursos do aplicativo no Android. Os documentos a seguir fornecem um guia completo de como voc pode organizar seus recursos de aplicao, especificar os recursos alternativos, acess-los em seu aplicativo, e mais: Fornecendo recursos Que tipos de recursos voc pode oferecer em seu aplicativo, onde guard-los, e como criar recursos alternativos para configuraes de dispositivo especfico. Acessando recursos Como utilizar os recursos que voc forneceu, seja por referenci-los a partir do seu cdigo de aplicativo ou de outros recursos XML. Tratando alteraes em runtime Como gerenciar as alteraes de configurao que ocorrem quando sua atividade est em execuo. Localizao Um guia de baixo para cima para localizar seu aplicativo usando recursos alternativos. Enquanto este apenas um uso especfico de recursos alternativos, muito importante para alcanar mais usurios.
199
Tipos de recursos Uma referncia de vrios tipos de recursos que voc pode fornecer, descrevendo seus elementos XML, atributos e sintaxe. Por exemplo, esta referncia mostra como criar um recurso para os menus do aplicativo, os desenhos, animaes e muito mais.
200
Armazenamento de dados
Android oferece vrias opes para voc guardar dados da aplicao persistente. A soluo que voc escolher depende de suas necessidades especficas, tais como se os dados devem ser privados da sua aplicao ou acessveis para outras aplicaes (e do usurio) e quanto espao seus dados requerem. Suas opes de armazenamento de dados so os seguintes: Preferncias compartilhadas Armazenar dados privados primitivos em pares chave-valor. Armazenamento interno Armazenar dados privados sobre a memria do dispositivo. Armazenamento externo Armazenar dados pblicos sobre o armazenamento compartilhado externo. Bancos de dados SQLite Armazenar dados estruturados em um banco privado. Conexo de rede Armazenar dados na web com seu servidor de rede prpria. Android fornece uma maneira para que voc exponha seus dados pessoais, mesmo para outras aplicaes - com um provedor de contedo. Um provedor de contedo um componente opcional que expe acesso de leitura/gravao sua aplicao de dados, sujeito a qualquer restrio que voc pretende impor. Para obter mais informaes sobre como usar provedores de contedo, consulte a documentao de provedores de contedo.
201
strings. Estes dados vo persistir nas sesses de usurio (mesmo se sua aplicao morta). Para obter um objeto SharedPreferences para sua aplicao, use um dos dois mtodos: getSharedPreferences() - Use esta opo se voc precisa de arquivos de mltiplas preferncias
Preferncias do usurio
Preferncias compartilhadas no so estritamente para o salvar "as preferncias do usurio", como o toque de um usurio escolheu. Se voc est interessado em criar preferncias do usurio para seu aplicativo, consulte PreferenceActivity , que estabelece um quadro de atividades para voc criar as preferncias do usurio, persistido o qual (usando ser as
identificados pelo nome, que voc especifica primeiro. getPreferences() - Use esta opo se voc s precisa de um arquivo de com o parmetro
automaticamente
preferncias compartilhadas).
preferncias para a sua actividade. Porque este ser o nico arquivo de preferncias para sua atividade, voc no fornece um nome. Para escrever os valores: 1. Chame edit() para obter uma SharedPreferences.Editor. 2. Adicione valores com mtodos como putBoolean() e putString(). 3. Empregue os novos valores com commit(). Para ler os valores, use mtodos SharedPreferences como getBoolean() e getString(). Aqui est um exemplo que salva uma preferncia para o modo silencioso keypress em uma calculadora:
public class Calc extends Activity { public static final String PREFS_NAME = "MyPrefsFile"; @Override protected void onCreate(Bundle state){ super.onCreate(state); ... // Restore preferences SharedPreferences settings = getSharedPreferences(PREFS_NAME, 0); boolean silent = settings.getBoolean("silentMode", false); setSilent(silent); }
202
@Override protected void onStop(){ super.onStop(); // We need an Editor object to make preference changes. // All objects are from android.context.Context SharedPreferences settings = getSharedPreferences(PREFS_NAME, 0); SharedPreferences.Editor editor = settings.edit(); editor.putBoolean("silentMode", mSilentMode); // Commit the edits! editor.commit(); } }
MODE_PRIVATE ir criar o arquivo (ou substituir um arquivo de mesmo nome) e torn-lo privado para sua aplicao. Outras modalidades disponveis so:
203
Para ler um arquivo de armazenamento interno: 1. Chame openFileInput() e passe o nome do arquivo a ser lido. Isso retorna um FileInputStream. 2. Leia os bytes do arquivo com a read(). 3. Em seguida, feche o fluxo com close(). Dica: Se voc quiser salvar um arquivo esttico em seu aplicativo em tempo de compilao, salve o arquivo no diretrio de res/raw/ do seu projeto. Voc pode abri-lo com openRawResource(), passando a identificao de recurso R.raw.<filename>. Esse mtodo retorna um InputStream que voc pode usar para ler o arquivo (mas voc no pode escrever no arquivo original).
204
fileList() Retorna uma matriz de arquivos atualmente salvos pela sua aplicao.
205
Este exemplo verifica se o armazenamento externo est disponvel para ler e escrever. O mtodo getExternalStorageState() retorna outros estados que voc pode querer verificar, como se a mdia est sendo compartilhada (conectada a um computador), est totalmente ausente, foi mal removida, etc. Voc pode us-los para notificar o usurio com mais informaes quando o aplicativo precisa de acesso mdia.
DIRECTORY_RINGTONES (passe null para receber a raiz do diretrio do arquivo da aplicativo). Este mtodo ir criar o diretrio apropriado, se necessrio. Ao especificar o tipo de diretrio, voc garante que a mdia scanner do Android ir categorizar corretamente seus arquivos no sistema (por exemplo, os ringtones so identificados como toques, e no msica). Se o usurio desinstala o aplicativo, este diretrio e todo seu contedo sero apagados. Se voc estiver usando a API de nvel 7 ou inferior, use getExternalStorageDirectory() para abrir um File que representa a raiz de armazenamento externo. Voc deve ento escrever os seus dados no seguinte diretrio: /Android/data/<package_name>/files/ O <package_name> o seu nome de estilo do pacote Java, tal como "com.example.android.app". Se o dispositivo do usurio est executando API nvel 8 ou superior e desinstalar o aplicativo, este diretrio e todo seu contedo sero apagados.
Como salvar arquivos que Escondendo seus arquivos a partir da devem ser compartilhados Media Scanner
Se voc deseja salvar os arquivos que no so especficos para a sua aplicao e que no devem ser excludos quando o aplicativo desinstalado, salva-os em um dos
Inclua um arquivo vazio chamado .nomedia em seu diretrio de arquivos externos (note o ponto prefixo ao nome do arquivo). Isto ir prevenir o media scanner do Android de ler arquivos de mdia e inclu-los em aplicativos como Galley ou Music.
206
diretrios pblicos de armazenamento externo. Esses diretrios esto na origem do armazenamento externo, como Music/, Pictures/, Ringtones/ e outros. Na API nvel 8 ou superior, use getExternalStoragePublicDirectory(),passando para ele o tipo de diretrio pblico que deseja, tais como DIRECTORY_MUSIC, DIRECTORY_PICTURES, DIRECTORY_RINGTONES ou outros. Este mtodo ir criar o diretrio apropriado, se necessrio. Se voc estiver usando a API de nvel 7 ou inferior, use getExternalStorageDirectory() para abrir um File que representa a raiz do armazenamento externo, em seguida, salve seus arquivos compartilhados em um dos seguintes diretrios: Music/ - o scanner media classifica todas as mdias encontradas aqui como a msica do usurio. Podcasts/ - scanner media classifica todas as mdias encontradas aqui como um podcast. Ringtones/ - scanner media classifica todas as mdias encontradas aqui como um ringtone. Alarms/ - scanner media classifica todas as mdias encontradas aqui como um som de alarme. Notifications/ - scanner media classifica todas as mdias encontradas aqui como um som de notificao. Pictures/ - todas as fotos (excluindo as tiradas com a cmera). Movies/ - todos os filmes (excluindo aqueles filmados com a cmera de vdeo). Download/ - downloads diversos.
207
Se voc estiver usando a API de nvel 7 ou inferior, use getExternalStorageDirectory() para abrir um File que representa a raiz do armazenamento externo, em seguida, escreva o seu cache de dados no seguinte diretrio: /Android/data/<package_name>/cache/ O <package_name> o seu estilo nome do pacote Java, tal qual
"com.example.android.app".
Voc pode obter uma instncia de sua implementao SQLiteOpenHelper usando o construtor que voc definiu. Para escrever e ler a partir do banco de dados, chame getWritableDatabase() e getReadableDatabase(), respectivamente. Estes devolvem um objeto SQLiteDatabase que representa o banco de dados e fornece mtodos para operaes de SQLite.
208
Voc pode executar consultas SQLite usando mtodos query() SQLiteDatabase, que aceitam parmetros de consulta diversos, tais como a tabela a ser consultada, a projeo, seleo, colunas,
Android
no
impe
qualquer
recomendamos incluir um valor de campo autoincrementado como chave que pode ser usado como
agrupamento e outros. Cada consulta SQLite ir retornar um Cursor que aponta para todos os registros encontrados pela consulta. O Cursor sempre o mecanismo com o qual voc pode navegar pelos resultados de uma consulta de banco de dados e ler linhas e colunas. Para aplicativos de exemplo que demonstram como usar banco de dados SQLite no Android, consulte as aplicaes Note Pad e Dicionrio pesquisvel.
uma
identificao
nica
para
localizar rapidamente um registro. Isso no necessria para dados privados, implementar mas um se provedor voc de
contedo, voc deve incluir uma identificao exclusiva com a constante BaseColumns._ID.
209
Artigos Acessibilidade
Linguagens e recursos
Text-to-Speech TTS: tambm conhecido como speech synthesis (sntese de fala, em portugus) um recurso disponibilizado a partir de Android 1.6 (API Level 4) que possibilita ao dispositivo ler textos em diversas linguagens. O mecanismo TTS embarcado no Android suporta ingls (britnico ou americano), francs, alemo, italiano e espanhol e precisa saber qual idioma pronunciar para adequar a voz, afinal, uma mesma palavra possui pronuncias diferentes dependendo da lngua. Uma checagem da disponibilidade do recurso se faz necessrio tendo em vista que, apesar de todos os dispositivos com Android terem a funcionalidade embarcada, alguns possuem armazenamento limitado e pode ser que faltem arquivos de recursos especficos do idioma, sendo assim, o seguinte cdigo verifica a presena dos recursos TTS.
Intent checkIntent = new Intent(); checkIntent.setAction(TextToSpeech.Engine.ACTION_CHECK_TTS_DATA); startActivityForResult(checkIntent, MY_DATA_CHECK_CODE);
Uma checagem que retorna sucesso marcada por CHECK_VOICE_DATA_PASS indicando que o dispositivo est pronto para falar, depois da criao do objeto TextToSpeech. Em caso negativo, o dispositivo ir utilizar o ACTION_INSTALL_TTS_DATA que dispara uma ao levando o usurio a fazer a instalao manualmente acessando o Android Market; A instalao feita automaticamente aps a concluso do download. Uma implementao da verificao do resultado da checagem est abaixo:
private TextToSpeech mTts; protected void onActivityResult( int requestCode, int resultCode, Intent data) { if (requestCode == MY_DATA_CHECK_CODE) { if (resultCode == TextToSpeech.Engine.CHECK_VOICE_DATA_PASS) { // success, create the TTS instance mTts = new TextToSpeech(this, this); } else { // missing data, install it Intent installIntent = new Intent(); installIntent.setAction( TextToSpeech.Engine.ACTION_INSTALL_TTS_DATA); startActivity(installIntent);
210
} }}
No construtor da instncia TextToSpeech ns passamos uma referncia ao Contexto a ser usado (neste caso a atividade atual), e um OnInitListener (aqui a nossa atividade tambm). Dessa forma habilitado para que a aplicao seja notificada quando o TextTo-Speech totalmente carregado, ento podemos comear a configurar-lo e us-lo.
Linguagens e localidade
No Google I/O 2009 foi mostrado uma utilizao do TTS para falar o resultado de uma traduo de e para uma das lnguas disponveis. Um exemplo de chamada como o abaixo:
mTts.setLanguage(Locale.US);
Ou para verificar se uma linguagem est disponvel, basta usar o trecho abaixo que retornar TextToSpeech.LANG_COUNTRY_AVAILABLE para indicar que o idioma e o pas, como descrito pelo parmetro de localidade, so suportados (e os dados esto corretamente instalados), como tambm pode retornar
Obs.: para usar o cdigo Locale.getDefault(), deve-se certificar primeiramente se o idioma padro suportado.
O mecanismo TTS gerencia uma fila global de todas as entradas para sintetizar, que tambm so conhecidos como "expresses". Cada TextToSpeech pode gerir sua prpria fila a fim de controlar o que vai interromper a emisso atual e que simplesmente uma fila de espera.
211
No Android, cada stream de udio que reproduzido est associado a um tipo de fluxo, tal como definido no android.media.AudioManager . Para um despertador falando, o texto a ser reproduzido pertence ao tipo de fluxo AudioManager.STREAM_ALARM, para que ele respeite as definies de alarme que o usurio escolheu no dispositivo. O ltimo parmetro do mtodo speak() permite que voc passe para os parmetros do TTS, especificado como pares chave / valor em um HashMap, tal qual:
HashMap<String, String> myHashAlarm = new HashMap(); myHashAlarm.put(TextToSpeech.Engine.KEY_PARAM_STREAM, String.valueOf(AudioManager.STREAM_ALARM)); mTts.speak(myText1, TextToSpeech.QUEUE_FLUSH, myHashAlarm); mTts.speak(myText2, TextToSpeech.QUEUE_ADD, myHashAlarm);
Como as chamadas so assncronas, pode ser necessrio identificar se uma sntese foi concluda, isso pode ser feito da seguinte forma:
mTts.setOnUtteranceCompletedListener(this); myHashAlarm.put(TextToSpeech.Engine.KEY_PARAM_STREAM, String.valueOf(AudioManager.STREAM_ALARM)); mTts.speak(myText1, TextToSpeech.QUEUE_FLUSH, myHashAlarm); myHashAlarm.put(TextToSpeech.Engine.KEY_PARAM_UTTERANCE_ID, "end of wakeup message ID"); // myHashAlarm now contains two optional parameters mTts.speak(myText2, TextToSpeech.QUEUE_ADD, myHashAlarm);
E a atividade notificada pelo mtodo, repare que a mensagem foi usada para ser identificada no mtodo:
public void onUtteranceCompleted(String uttId) { if (uttId == "end of wakeup message ID") { playAnnoyingMusic(); } }
Como o recurso de fala exige bastante processamento, numa situao em que um determinado texto ser lido diversas vezes mais interessante gravar o udio para ser reproduzido posteriormente.
HashMap<String, String> myHashRender = new HashMap(); String wakeUpText = "Are you up yet?"; String destFileName = "/sdcard/myAppCache/wakeUp.wav"; myHashRender.put(TextToSpeech.Engine.KEY_PARAM_UTTERANCE_ID, wakeUpText); mTts.synthesizeToFile(wakuUpText, myHashRender, destFileName);
A funcionalidade de text-to-speech depende de um servio dedicado compartilhado entre todos os aplicativos que usam esse recurso. Quando voc terminar de usar o TTS, use a instruo mTts.shutdown() dentro do mtodo onDestroy(), por exemplo. ANDROID, uma viso geral Anderson Duarte de Amorim
212
Interface
Toque
O modo de toque um estado da hierarquia de vista que depende unicamente da interao do usurio com o telefone. Por si s, o modo de tocar algo muito fcil de entender, pois ele simplesmente indica se a interao do usurio passado foi realizada com a tela sensvel ao toque. Por exemplo, se voc estiver usando um dispositivo com Android, a seleo de um widget com o trackball vai lev-lo sair do modo de tocar, no entanto, se voc toca um boto na tela com seu dedo, voc entrar no modo de tocar. Quando o usurio no estiver em modo de tocar, ns falamos sobre o modo de trackball, o modo de navegao ou a navegao por teclado, por isso no se surpreenda se voc encontrar esses termos. Existe apenas uma API diretamente relacionada com o modo de toque, View.isInTouchMode(). Curiosamente, o modo de tocar enganosamente simples e as conseqncias de entrar no modo de tocar muito maior do que voc imagina. Vejamos algumas das razes. Toque em modo de seleo e foco Criar um conjunto de ferramentas UI para dispositivos mveis difcil porque so vrios os mecanismos de interao. Alguns dispositivos oferecem apenas 12 teclas, algumas tm uma tela sensvel ao toque, alguns exigem uma caneta, alguns tm ambos um ecr tctil e um teclado. Com base nos recursos de hardware do usurio, ele pode interagir com seu aplicativo usando mecanismos diferentes, ento tivemos que pensar muito sobre todos os possveis problemas que possam surgir. Uma questo nos levou a criar o modo de toque. Imagine um aplicativo simples, ApiDemos por exemplo, que mostra uma lista de itens de texto. O usurio pode navegar livremente pela lista usando a trackball, mas tambm, em alternativa, deslocar e arremessar a lista usando a tela sensvel ao toque. O problema neste cenrio como lidar com a seleo corretamente quando o usurio manipula a lista atravs da tela sensvel ao toque. Neste caso, se o usurio selecionar um item no topo da lista e ento arremessa a lista para o fundo, o que deve acontecer com a seleo? E se ele permanecer no item e rolar
213
para fora da tela? O que deve acontecer se o usurio decidiu ento mover a seleo com o trackball? Ou pior, o que deve acontecer se o usurio pressiona o trackball para agir de acordo com o item selecionado, que no mostrado na tela mais? Aps cuidadosa considerao, decidimos remover por completo a seleo, quando o usurio manipula a interface do usurio atravs da tela sensvel ao toque. No modo de toque, no h foco e no h seleo. Qualquer item selecionado em uma lista de em uma grade fica desmarcada, logo que o usurio entra no modo de tocar. Da mesma forma, quaisquer widgets ficaram desfocados quando o usurio entra no modo de tocar. A imagem abaixo ilustra o que acontece quando o usurio toca uma lista depois de selecionar um item com o trackball.
Para tornar as coisas mais naturais para o usurio, o quadro sabe como ressuscitar a seleo / foco sempre que o usurio sai do modo de tocar. Por exemplo, se o usurio fosse usar o trackball novamente, a seleo iria reaparecer no item previamente selecionado. por isso que alguns desenvolvedores esto confusos quando se criar uma exibio personalizada e comear a receber os principais eventos s depois de mover o trackball uma vez: a sua aplicao est no modo de tocar, e eles precisam usar o trackball para sair do modo de tocar e ressuscitar o foco.
214
A relao entre o modo de toque, seleo e foco significa que voc no deve confiar na seleo e/ou foco existir em sua aplicao. Um problema muito comum com o Android para novos desenvolvedores contar com ListView.getSelectedItemPosition(). No modo de toque, este mtodo retornar INVALID_POSITION. Focando no modo Touch Em geral, o foco no existe no modo de tocar. No entanto, o foco pode existir no modo de tocar em uma maneira muito especial chamado focusable. Este modo especial foi criado para widgets que recebem a entrada de texto, como EditText ou ListView. O modo focusable o que permite ao usurio inserir texto dentro de um campo de texto na tela, sem primeiro selecion-la com a bola ou o dedo. Quando um usurio toca a tela, o aplicativo ir entrar no modo de toque se ele no estava no modo de tocar j. O que acontece durante a transio para o modo de tocar depende do que o usurio tocou, e que atualmente tem foco. Se o usurio toca um widget que focusable no modo de tocar, o widget ir receber o foco. Caso contrrio, qualquer elemento ao qual se dedica atualmente no vai manter o foco a menos que seja focusable no modo de tocar. Por exemplo, na figura abaixo, quando o usurio toca a tela, o campo de texto recebe o foco. Focusable no modo de uma propriedade que voc pode definir a si mesmo, seja de cdigo ou de XML. No entanto, voc deve us-lo com parcimnia e s em situaes muito especficas, porque quebra a coerncia com o comportamento normal da interface do Android. Um jogo um bom exemplo de uma aplicao que pode fazer bom uso do focusable na propriedade de modo sensvel ao toque. MapView, se usada em tela cheia como no Google Maps, outro bom exemplo de onde voc pode usar focusable no modo de tocar
corretamente. Abaixo est um exemplo de um widget focusable em modo de tocar. Quando o usurio bate um AutoCompleteTextView com o dedo, o foco permanece no campo de texto de entrada:
215
Novos desenvolvedores para o Android, muitas vezes pensam que focusable no modo de tocar a soluo que eles precisam para "consertar" o problema do "desaparecimento" da seleo/foco. Ns encorajamos voc a pensar muito antes de utiliz-lo. Se usada incorretamente, pode fazer seu aplicativo se comportar de maneira diferente do resto do sistema e simplesmente jogar fora os hbitos do usurio. O quadro Android contm todas as ferramentas necessrias para lidar com as interaes do usurio sem usar focusable no modo de tocar. Por exemplo, em vez de tentar fazer ListView sempre manter a sua seleo, basta usar o modo de escolha apropriada, como mostrado na setChoiceMode(int) .
Gestos
As telas de toque so uma tima maneira de interagir com aplicaes em dispositivos mveis. Com uma tela de toque, os usurios podem facilmente tocar, arrastar,
arremessar ou deslizar rapidamente e realizar aes em seus aplicativos favoritos. Para os desenvolvedores de aplicativos o Android faz com que seja fcil reconhecer aes simples, mas tem sido mais difcil de lidar com gestos complicados, s vezes exigindo que os desenvolvedores escrevam um monte de cdigo. por isso que foi introduzida uma nova API de gestos no Android 1.6. Esta API, localizada no novo pacote android.gesture , permite armazenar, carregar, desenhar e reconhecer gestos. Clique para baixar o cdigo fonte dos exemplos
216
apoiar novas classes de dispositivos Android, como os teclados sem hardware, por isso importante que o aplicativo funcione bem com o FMI e oferece uma tima experincia para os usurios. O que um mtodo de entrada? O FMI Android foi concebido para suportar uma variedade de IMEs, incluindo o teclado virtual, reconhecedores de mo-escrita, e tradutores teclado duro. Nosso foco, no entanto, ser em teclados virtuais, j que este o tipo de mtodo de entrada que atualmente faz parte da plataforma. Um usurio normalmente ir acessar o IME atual, tocando em uma exibio de texto para editar, conforme mostrado na tela inicial:
O teclado virtual posicionado na parte inferior da tela sobre a janela do aplicativo. Para organizar o espao disponvel entre a aplicao e o IME, usamos algumas abordagens, a que mostrada aqui chamado de pan e digitalizar, e simplesmente envolve a rolagem da janela do aplicativo em torno de modo que a viso focada atualmente visvel. Este o modo padro, pois mais seguro para as aplicaes existentes.
217
Na maioria das vezes o layout da tela um resize, onde a janela da aplicao redimensionada para ser totalmente visvel. Um exemplo mostrado aqui, quando escrevo uma mensagem de e-mail:
O tamanho da janela do aplicativo alterada para que nenhum deles seja escondido pelo IME, permitindo acesso total ao aplicativo e IME. Isto, obviamente, s funciona para aplicativos que tm uma rea redimensionvel que pode ser reduzida para dar espao suficiente, mas o espao vertical neste modo realmente nada menos do que o que est disponvel na orientao paisagem. O principal modo final fullscreen ou modo de extrato. Isso usado quando o IME muito grande para o espao compartilhar com a aplicao de base. Com o IME padro, voc s vai encontrar essa situao quando a tela est em uma orientao horizontal, embora IMEs sejam livres para us-lo sempre que desejarem. Neste caso, a janela da aplicao deixada como est, e simplesmente o IME exibe a tela inteira em cima dela, como mostrado aqui:
218
Porque o IME est cobrindo o aplicativo, ele tem a sua rea de edio prpria, o que mostra o texto, na verdade contida na petio inicial. Existem tambm algumas oportunidades limitadas aplicao que tem que personalizar as partes do IME para melhorar a experincia do usurio. Atributos bsicos XML para controlar IMEs H uma srie de coisas que o sistema faz para tentar ajudar de trabalho existente com as aplicaes IMEs to bem quanto possvel, tais como: Use pan e scan por padro, a menos que possa razoavelmente supor que o modo de redimensionar vai trabalhar pela existncia de listas, percorrer as exibies, etc. Analisar no TextView vrios atributos existentes para adivinhar o tipo de contedo (nmeros, texto simples, senha, etc.) para ajudar o teclado a exibir um esquema de chave apropriado. Atribuir algumas aes padro para o IME fullscreen, como "campo prximo" e "feito". H tambm algumas coisas simples que voc pode fazer na sua aplicao que, muitas vezes, melhoram significativamente sua experincia de usurio. Exceto quando mencionado explicitamente, estes iro trabalhar em qualquer verso da plataforma Android, mesmo os anteriores para o Android 1.5 (uma vez que ir simplesmente ignorar essas novas opes). Especificando cada tipo de controle de entrada EditText A coisa mais importante para um pedido a fazer usar o novo atributo android:inputType em cada EditText. O atributo fornece informao muito mais rica
219
sobre o contedo do texto. Este atributo realmente substitui muitos atributos existentes ( android: password , android: singleLine , android: numeric , android: phoneNumber , android: capitalize , android: autoText e android: editable). Se voc especificar os atributos mais velhos e os novos android:inputType, o sistema usa android:inputType e ignora as outras. O android:inputType atributo tem trs partes: A classe a interpretao geral de caracteres. As classes atualmente suportadas so text (plain text), number (nmero decimal), phone (nmero de telefone), e datetime (uma data ou hora). A variao um refinamento da classe. No atributo, normalmente voc vai especificar a classe e variante juntamente com a classe como um prefixo. Por exemplo, textEmailAddress um campo de texto onde o usurio ir inserir algo que um endereo de correio (foo@bar.com) para a disposio das teclas ter um @ "carter" de acesso fcil, e numberSigned um campo numrico com um sinal. Se somente a classe especificado, ento voc obtm o padro / variante genrica. Sinalizadores adicionais podem ser especificados de abastecimento de refinamento. Esses sinalizadores so especficos para uma classe. Por exemplo, alguns sinalizadores para o text de classe so textCapSentences, textAutoCorrect e textMultiline. Como exemplo, aqui o EditText novo para a aplicao do IM ver texto da mensagem:
<EditText android:id="@+id/edtInput" android:layout_width="0dip" android:layout_height="wrap_content" android:layout_weight="1" android:inputType="textShortMessage|textAutoCorrect|textCapSentences|textMultiLine" android:imeOptions="actionSend|flagNoEnterAction" android:maxLines="4" android:maxLength="2000" android:hint="@string/compose_hint"/>
Ativar o modo de redimensionamento e funcionalidades outra janela A segunda coisa mais importante para sua aplicao a fazer especificar o comportamento global da sua janela em relao ao mtodo de entrada. O aspecto mais
220
visvel disto o controle redimensionar VS. pan e scan mode, mas existem outras coisas que voc pode fazer bem para melhorar sua experincia de usurio. Voc normalmente ir controlar esse comportamento atravs do
android:windowSoftInputMode em cada <activity> em sua AndroidManifest.xml. Como o tipo de entrada, h um par de peas diferentes de dados que pode ser especificado aqui, combinando-as entre si: O modo de ajuste da janela especificado com adjustResize ou adjustPan . altamente recomendado que voc especifique sempre um ou outro. Voc ainda pode controlar se o IME ser exibido automaticamente quando sua atividade exibida e outras situaes onde o usurio move a ele. O sistema no mostrar automaticamente um IME, por padro, mas em alguns casos pode ser conveniente para o usurio se uma aplicao permite esse comportamento. Voc pode solicitar este com stateVisible . H tambm um nmero de opes de outro estado para o controle mais detalhado que voc pode encontrar na documentao. Um exemplo tpico desse campo pode ser visto na atividade de edio do contato, o que garante que ele redimensionado e exibe automaticamente o IME para o usurio:
<activity name="EditContactActivity" android:windowSoftInputMode="stateVisible|adjustResize"> ... </activity>
Controlando os botes de ao Para a personalizao final, vamos olhar para a "ao" de botes no IME. Existem atualmente dois tipos de aes: A tecla enter em um teclado virtual normalmente ligada a uma ao quando no estiverem operando em um multi-line de edio de texto. Quando em modo de tela cheia, um IME pode tambm colocar um boto de ao adicional direita do texto que est sendo editado, dando ao usurio o acesso rpido a uma operao de aplicativos comuns.
221
Estas opes so controladas com o atributo android:imeOptions em TextView . O valor que voc fornecer aqui pode ser qualquer combinao de: Uma das aes pr-definidas constantes ( actionGo , actionSearch , actionSend , actionNext , actionDone ). Se nenhum desses for especificado, o sistema ir inferir qualquer actionNext ou actionDone dependendo se h um campo focusable aps este, voc pode explicitamente forar a nenhuma ao com actionNone. O flagNoEnterAction informa o IME que a ao no deve estar disponvel na tecla enter, mesmo que o texto em si no multi-linha. Isso evita ter aes irrecuperveis (enviar) que pode ser tocado acidentalmente pelo usurio durante a digitao. O flagNoAccessoryAction remove o boto de ao da rea de texto, deixando mais espao para o texto. O flagNoExtractUi remove completamente a rea de texto, permitindo que o aplicativo possa ser visto por trs dele. A anterior mensagem de aplicao MI tambm fornece um exemplo de um uso interessante da imeOptions, para especificar a ao de envio, mas no que seja mostrado a tecla Enter:
android:imeOptions="actionSend|flagNoEnterAction"
APIs para controlar IMEs Para um controle mais avanado sobre o IME, h uma variedade de novas APIs que voc pode usar. A menos que tenha um cuidado especial (como por meio de reflexo), utilizando essas APIs far com que seu aplicativo seja incompatvel com as verses anteriores do Android, e voc deve se certificar de que voc especifique android:minSdkVersion="3" em seu manifesto. A API principal o novo android.view.inputmethod.InputMethodManager, que voc pode recuperar com Context.getSystemService(). Ele permite que voc interaja com o estado global do mtodo de entrada, como explicitamente esconder ou mostrar a rea atual do IME de entrada.
222
H tambm novas bandeiras controlando a interao do mtodo de entrada, que voc pode controlar atravs da A existente classe Window.addFlags() acrescentou e novos mtodos
Window.setSoftInputMode().
PopupWindow
correspondentes para controlar essas opes em sua janela. Uma coisa em particular a ter em conta o novo
WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM, que usado para controlar se uma janela est em cima ou atrs do IME atual. A maior parte da interao entre um IME ativos e a aplicao feita atravs do android.view.inputmethod.InputConnection. Esta a API implementada em uma aplicao, que um IME chama para realizar as operaes de edio apropriada sobre o pedido. Voc no vai precisar se preocupar com isso, pois TextView oferece sua prpria implementao para si mesmo. H tambm um punhado de novas View s APIs, a mais importante delas sendo onCreateInputConnection() que cria um novo InputConnection de um IME (e preenche um android.view.inputmethod.EditorInfo com o seu tipo de entrada, as opes IME, e outros dados), novamente, a maioria dos desenvolvedores no precisaro se preocupar com isso, pois TextView cuida disso para voc.
223
224
Campos de um aplicativo de texto podem ter diferentes tipos de entrada especificada sobre eles, como o texto de forma livre, numrico, URL, endereo de e-mail e busca. Quando voc implementa um novo mtodo de entrada, voc precisa estar ciente dos tipos de entrada diferentes. Os mtodos de entrada no so automaticamente comutados para diferentes tipos de entrada e por isso necessrio para suportar todos os tipos no IME. No entanto, o IME no responsvel por validar a entrada enviada para o aplicativo. Essa a responsabilidade da aplicao. Por exemplo, o LatinIME equipados com a plataforma Android oferece layouts diferentes para o texto e entrada de nmero de telefone:
Preste ateno especfica ao enviar o texto para campos de senha. Certifique-se que a senha no visvel na sua interface do usurio - nem no modo de exibio de entrada ou o ponto de vista dos candidatos. Alm disso, no salvar a senha em qualquer lugar sem explicitamente informar o utilizador. A interface do usurio deve ser capaz de escala entre as orientaes retrato e paisagem. No modo IME no fullscreen, deixar espao suficiente para a aplicao para mostrar o campo de texto e qualquer contexto associado. De preferncia, no mais que metade da tela deve ser ocupada pelo IME. Existem duas maneiras de enviar mensagens de texto para o aplicativo. Voc pode enviar individuais eventos-chave ou voc pode editar o texto ao redor do cursor no campo a aplicao do texto. Para enviar um evento-chave, voc pode simplesmente construir objetos KeyEvent e chamar InputConnection.sendKeyEvent(). Aqui esto alguns exemplos:
InputConnection ic = getCurrentInputConnection(); long eventTime = SystemClock.uptimeMillis(); ic.sendKeyEvent(new KeyEvent(eventTime, eventTime,
225
Ao editar texto em um campo de texto, alguns dos mtodos mais teis na android.view.inputmethod.InputConnection so: getTextBeforeCursor() getTextAfterCursor() deleteSurroundingText() commitText()
Aes de desenhos
Drawable Mutations uma classe para oferecer ao programador algo que pode ser desenhado (Drawable Mutations). Por exemplo, um BitmapDrawable usado para exibir imagens, um ShapeDrawable para desenhar formas e gradientes e assim por diante. Voc pode at mesmo combinlas para criar renderizaes complexas. Por exemplo, toda vez que voc criar um Button, uma nova drawable carregada a partir do quadro de recursos ( android.R.drawable.btn_default ). Isto significa que todos os botes em todos os aplicativos usam uma instncia diferente drawable como pano de fundo. No entanto, todas estas partes drawables possuem um estado comum, o
chamado "estado constante". O contedo deste estado varia de acordo com o tipo de drawable voc est usando, mas, geralmente, contm todas as propriedades que podem ser definidos por um recurso. No caso de um boto, o constante estado contm uma imagem bitmap. Desta forma, todos os botes em todos os aplicativos compartilham o mesmo bitmap, o que economiza um monte de memria. O diagrama abaixo mostra como as entidades so criadas quando voc atribuir o recurso de mesma imagem como fundo de dois pontos de vista diferentes. Como voc
226
pode ver dois drawables so criadas, mas que ambos compartilham o mesmo estado constante, portanto, a mesma bitmap:
Esse recurso de compartilhamento de estado de grande valia para evitar o desperdcio de memria, mas pode causar problemas quando voc tentar modificar as propriedades de um drawable. Imagine uma aplicao com uma lista de livros. Cada livro tem uma estrela ao lado de seu nome, totalmente opaco quando o usurio marca o livro como um dos favoritos, e translcido quando o livro no um favorito. Para conseguir esse efeito, voc provavelmente vai escrever o seguinte cdigo em seu mtodo adaptador de lista do getView():
Book = ...; TextView Item_da_lista = ...; listItem.setText (book.getTitle ()); estrela Drawable = context.getResources () getDrawable (R.drawable.star).; if (book.isFavorite ()) { star.setAlpha (255); / opaca / Else {} star.setAlpha (70); / translcido }
227
Infelizmente, este pedao de cdigo gera um resultado um pouco estranho: todas as drawables tm a mesma opacidade. Esse resultado explicado pela constante estado. Mesmo que ns estamos comeando uma nova instncia drawable para cada item da lista, o constante estado permanece o mesmo e, no caso de BitmapDrawable, a opacidade parte da constante estado. Assim, mudando a opacidade de uma instncia muda drawable a opacidade de todas as outras instncias. Android 1.5 e superior oferecem uma maneira muito fcil de resolver esse problema com a nova mutate() mtodo. Quando voc chamar esse mtodo em um drawable, a constante estado de drawable duplicada para permitir a voc alterar qualquer propriedade, sem afetar outros drawables. Note-se que os bitmaps so ainda comuns, mesmo depois de uma mutao drawable. O diagrama abaixo mostra o que acontece quando voc chama mutate() em um drawable:
228
Assim, um exemplo se uso, como o citado acerca dos livros, fica como a figura abaixo.
229
cara principalmente quando voc aninhar diversos LinearLayout que utilizam o weight do parmetro, que requer que o nodo filho seja medido duas vezes. Consideremos um exemplo muito simples e comum de um esquema: um item da lista com um cone no lado esquerdo, um ttulo em cima e uma descrio opcional abaixo do ttulo.
Uma ImageView e dois TextView so posicionados em relao uns aos outros, aqui o wireframe do layout como capturado pelos HierarchyViewer :
A implementao desta estrutura simples com LinearLayout. O item em si uma LinearLayout horizontal com um ImageView e um LinearLayout vertical, que contm as duas TextView. Aqui est o cdigo fonte deste esquema:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="?android:attr/listPreferredItemHeight" android:padding="6dip"> <ImageView android:id="@+id/icon" android:layout_width="wrap_content" android:layout_height="fill_parent" android:layout_marginRight="6dip" android:src="@drawable/icon" /> <LinearLayout android:orientation="vertical" android:layout_width="0dip" android:layout_weight="1" android:layout_height="fill_parent"> <TextView android:layout_width="fill_parent" android:layout_height="0dip"
230
android:layout_weight="1" android:gravity="center_vertical" android:text="My Application" /> <TextView android:layout_width="fill_parent" android:layout_height="0dip" android:layout_weight="1" android:singleLine="true" android:ellipsize="marquee" android:text="Simple application that shows how to use RelativeLayout" /> </LinearLayout> </LinearLayout>
Este esquema acima funciona, mas pode ser prejudicial se voc instanci-la para cada item da lista de um ListView . O mesmo esquema pode ser reescrito utilizando um nico RelativeLayout , salvando assim um ponto de vista, e melhor ainda, um nvel na hierarquia do ponto de vista, por item da lista. A implementao do layout com um RelativeLayout simples:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="?android:attr/listPreferredItemHeight" android:padding="6dip"> <ImageView android:id="@+id/icon" android:layout_width="wrap_content" android:layout_height="fill_parent" android:layout_alignParentTop="true" android:layout_alignParentBottom="true" android:layout_marginRight="6dip" android:src="@drawable/icon" /> <TextView android:id="@+id/secondLine" android:layout_width="fill_parent" android:layout_height="26dip" android:layout_toRightOf="@id/icon" android:layout_alignParentBottom="true" android:layout_alignParentRight="true"
231
android:singleLine="true" android:ellipsize="marquee" android:text="Simple application that shows how to use RelativeLayout" /> <TextView android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_toRightOf="@id/icon" android:layout_alignParentRight="true" android:layout_alignParentTop="true" android:layout_above="@id/secondLine" android:layout_alignWithParentIfMissing="true" android:gravity="center_vertical" android:text="My Application" /> </RelativeLayout>
Esta nova aplicao se comporta exatamente da mesma forma que a implementao anterior, exceto em um caso: o item da lista que se pretende apresentar tem duas linhas de texto: o ttulo e uma descrio opcional. Quando uma descrio no est disponvel para um determinado item da lista o aplicativo simplesmente define a visibilidade do segundo TextView como GONE. Isso funciona perfeitamente com o LinearLayout, mas no com o RelativeLayout:
descrio est alinhado com a parte inferior da RelativeLayout e que o ttulo colocado acima da descrio e ancorado a me da top. Com a descrio GONE, o RelativeLayout no sabe a posio da margem inferior do ttulo. Para resolver esse problema, voc pode usar um parmetro muito especial chamado
layout_alignWithParentIfMissing. Este parmetro boolean simplesmente diz ao RelativeLayout a utilizar os seus prprios limites como ncoras quando um alvo est faltando. Por exemplo, se voc posicionar uma view direita de uma GONE e definir alignWithParentIfMissing como true,
232
RelativeLayout
vez vai ancorar o fim de sua borda esquerda. No nosso caso, usando far RelativeLayout alinhar a parte inferior do ttulo
alignWithParentIfMissing
O comportamento do nosso layout est perfeito, mesmo quando a descrio GONE. Ainda melhor, a hierarquia mais simples porque no estamos usando pesos LinearLayout's tambm mais eficiente. A diferena entre as duas implementaes torna-se evidente quando se comparam as hierarquias em HierarchyViewer:
233
234
A atividade tambm usada quando o usurio adiciona ou importa novos livros. Durante essa operao, a Prateleira mostra bits adicionais de interface do usurio. A imagem abaixo mostra a barra de progresso e um boto cancelar que aparecer na parte inferior da tela durante uma importao:
Como a importao de livros no uma operao comum, pelo menos quando comparado visita a lista de livros, o painel de importao representado inicialmente por um ViewStub :
235
Quando o usurio inicia o processo de importao, o ViewStub inflado e passa a ter o contedo do arquivo de layout que faz referncia:
236
Para usar um ViewStub , tudo que voc precisa especificar um atributo android:id, para depois inflar, e um atributo android:layout para fazer referncia ao arquivo de layout para incluir e inflar. Um stub permite que voc use um terceiro atributo, android:inflatedId , que pode ser usado para substituir o id da raiz do arquivo includo. Finalmente, os parmetros de layout especificados no topo sero aplicados para a raiz do layout includo. Aqui est um exemplo:
<ViewStub android:id="@+id/stub_import" android:inflatedId="@+id/panel_import" android:layout="@layout/progress_overlay" android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_gravity="bottom" />
Quando estiver pronto para inflar o stub, basta invocar o mtodo inflate(). Voc tambm pode simplesmente alterar a visibilidade do stub para VISIBLE ou INVISIBLE e o stub ir inflar. Note, no entanto que o mtodo inflate() tem a vantagem de retornar a raiz View ao inflar o layout:
((ViewStub) findViewById(R.id.stub_import)).setVisibility(View.VISIBLE); // or View importPanel = ((ViewStub) findViewById(R.id.stub_import)).inflate();
muito importante lembrar que aps o stub ser inflado, o topo removido da hierarquia de vista. Como tal, necessrio manter uma referncia de vida longa, por exemplo, em um campo de instncia de classe, a uma ViewStub . Um ViewStub um grande compromisso entre a facilidade de programao e de eficincia. Em vez de encher vistas manualmente e adicion-los em tempo de execuo de sua hierarquia de vista, basta usar um ViewStub. barato e fcil. A nica desvantagem de ViewStub que atualmente no suporta a tag <merge />.
FrameLayout usada para empilhar um TextView em cima de um ImageView : ANDROID, uma viso geral Anderson Duarte de Amorim
237
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent"> <ImageView android:layout_width="fill_parent" android:layout_height="fill_parent" android:scaleType="center" android:src="@drawable/golden_gate" /> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginBottom="20dip" android:layout_gravity="center_horizontal|bottom" android:padding="12dip" android:background="#AA000000" android:textColor="#ffffffff" android:text="Golden Gate" /> </FrameLayout>
238
As coisas ficam mais interessantes quando voc inspecionar o resultado com HierarchyViewer. Se voc olhar atentamente para a rvore resultante, voc vai notar que o FrameLayout definida no arquivo XML (destacada em azul abaixo) o filho nico de outro FrameLayout:
S fizemos a interface mais complexa, sem qualquer razo. Mas como poderamos nos livrar do presente FrameLayout? Afinal de contas, documentos XML requerem uma marca de raiz e tags em esquemas XML sempre representam instncias. a que o <merge /> vem a calhar. Quando o LayoutInflater encontra essa marca, ele ignora-o e adiciona o <merge /> dos nodos ao <merge /> pai. Confuso? Vamos reescrever o nosso layout XML anterior, substituindo o FrameLayout com <merge />: ANDROID, uma viso geral Anderson Duarte de Amorim
239
<merge xmlns:android="http://schemas.android.com/apk/res/android"> <ImageView android:layout_width="fill_parent" android:layout_height="fill_parent" android:scaleType="center" android:src="@drawable/golden_gate" /> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginBottom="20dip" android:layout_gravity="center_horizontal|bottom" android:padding="12dip" android:background="#AA000000" android:textColor="#ffffffff" android:text="Golden Gate" /> </merge>
Com esta nova verso, tanto o TextView quanto o ImageView sero adicionados diretamente ao nvel superior. O resultado ser o mesmo, mas visualmente a hierarquia do ponto de vista simples:
240
Obviamente, o uso do <merge /> funciona neste caso porque o nodo pai sempre um FrameLayout. Voc no pode aplicar este truque se o layout estava usando um LinearLayout como sua marca raiz, por exemplo. O <merge /> pode ser til em outras situaes, no entanto. Por exemplo, ele funciona perfeitamente quando combinado com o <include />. Voc tambm pode usar <merge /> quando voc cria um composto de exibio personalizado. Vamos ver como podemos usar essa tag para criar uma nova viso chamada OkCancelBar que simplesmente mostra dois botes com rtulos personalizados.
<merge xmlns:android="http://schemas.android.com/apk/res/android" xmlns:okCancelBar="http://schemas.android.com/apk/res/com.example.android.merge"> <ImageView android:layout_width="fill_parent" android:layout_height="fill_parent" android:scaleType="center" android:src="@drawable/golden_gate" /> <com.example.android.merge.OkCancelBar android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_gravity="bottom" android:paddingTop="8dip" android:gravity="center_horizontal" android:background="#AA000000" okCancelBar:okLabel="Save" okCancelBar:cancelLabel="Don't save" /> </merge>
241
O cdigo fonte do OkCancelBar muito simples, porque os dois botes so definidos em um arquivo XML externo, carregado com um LayoutInflate. Como voc pode ver no trecho a seguir, o esquema XML R.layout.okcancelbar inflado com o OkCancelBar como o pai:
public class OkCancelBar extends LinearLayout { public OkCancelBar(Context context, AttributeSet attrs) { super(context, attrs); setOrientation(HORIZONTAL); setGravity(Gravity.CENTER); setWeightSum(1.0f); LayoutInflater.from(context).inflate(R.layout.okcancelbar, this, true); TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.OkCancelBar, 0, 0); String text = array.getString(R.styleable.OkCancelBar_okLabel); if (text == null) text = "Ok"; ((Button) findViewById(R.id.okcancelbar_ok)).setText(text); text = array.getString(R.styleable.OkCancelBar_cancelLabel); if (text == null) text = "Cancel"; ((Button) findViewById(R.id.okcancelbar_cancel)).setText(text);
242
array.recycle(); } }
Os dois botes so definidos no esquema XML a seguir. Como voc pode ver, usamos o <merge /> para adicionar os dois botes diretamente ao OkCancelBar . Cada boto est includo a partir do arquivo XML externo mesmo layout para torn-los mais fceis de manter, ns simplesmente substituimos o seu id:
<merge xmlns:android="http://schemas.android.com/apk/res/android"> <include layout="@layout/okcancelbar_button" android:id="@+id/okcancelbar_ok" /> <include layout="@layout/okcancelbar_button" android:id="@+id/okcancelbar_cancel" /> </merge>
Ns criamos uma forma flexvel e fcil de manter a exibio personalizada que gera uma hierarquia de vista eficiente:
243
O <merge /> extremamente til e pode fazer maravilhas em seu cdigo. No entanto, ele sofre de um par de limitaes: <merge /> s pode ser usado como a tag raiz de um esquema XML Ao inflar um layout comeando com uma <merge /> voc deve especificar um pai ViewGroup e voc deve definir attachToRoot como true
244
O efeito de fade implementado usando uma combinao de Canvas.saveLayerAlpha() e Porter-Duff Destination Out blending mode. Infelizmente, as coisas comeam a ficarem feias quando voc tenta usar um background personalizado no ListView ou quando voc muda a janela de fundo. A seguir duas imagens mostram o que acontece em um aplicativo quando voc mudar o fundo da janela. A imagem da esquerda mostra como a lista se parece por padro e a imagem da direita mostra o como a lista se parece durante um deslocamento iniciado com um gesto de tocar:
Este problema de processamento causada por uma otimizao do quadro Android ativada por padro em todas as instncias do ListView. Esta aplicao funciona muito bem, mas infelizmente muito caro e pode trazer para baixo o desempenho de desenho, um pouco como ele necessita para capturar uma parcela da prestao em um bitmap fora da tela e, em seguida, requer a mistura extra (o que implica readbacks da memria). ListViews so, na maioria das vezes exibidos em uma base slida, no h nenhuma razo para enveredar por esse caminho caro. por isso que ns introduzimos uma otimizao chamada de pitada de cor cache. A dica de cor cache uma cor RGB definido por padro com a cor de fundo da janela, que #191919 no tema escuro do
245
Android. Quando esta dica definida, ListView (na verdade, sua classe base View) sabe que vai recorrer a um fundo slido e substitui, portanto, a cara renderizao saveLayerAlpha()/Porter-Duff por um gradiente simples. Este gradiente vai desde totalmente transparente para o valor de cor cache e exatamente isso que voc v na imagem acima, com o gradiente escuro na parte inferior da lista. No entanto, isso ainda no explica por que a lista inteira fica em preto durante um pergaminho. Como mencionado anteriormente, ListView tem um fundo transparente/translcido por padro, assim como todos os widgets padro na caixa de ferramentas UI Android. Isto implica que, quando ListView redesenha seus filhos, tem que misturar as crianas com janela de fundo. Mais uma vez, isto requer readbacks caros de memria que so particularmente dolorosos durante um deslocamento ou uma aventura, quando acontece o desenho dezenas de vezes por segundo. Para melhorar o desempenho de desenho durante as operaes de rolagem, o quadro Android reutiliza a dica de cor cache. Para corrigir esse problema, tudo que voc tem que fazer desativar o cache de otimizao de cor, se voc usar uma cor de fundo no-contnua, ou definir a dica para o valor de cor slido adequado. Voc pode fazer isso a partir do cdigo ou, de preferncia, a partir de XML, usando o android:cacheColorHint. Para desabilitar a otimizao, basta usar a cor transparente #00000000. A figura abaixo mostra uma lista com android:cacheColorHint="#00000000" definido no arquivo de layout XML:
246
Como voc pode ver, o fade funciona perfeitamente contra o fundo personalizado em madeira. O recurso de cache de sugesto de cor interessante porque mostra como as otimizaes podem tornar sua vida mais difcil em algumas situaes. Neste caso especfico, porm, o benefcio do comportamento padro compensa a maior complexidade.
Live folders
Live Folders, introduzida no Android 1.5 API (Nvel 3), permitem a exibio de qualquer fonte de dados na tela inicial, sem forar o usurio a lanar uma aplicao. Uma live folder simplesmente uma viso em tempo real de um ContentProvider. Como tal, uma live folder pode ser usada para exibir todos os contatos do usurio ou bookmarks, e-mail, listas de reproduo, um feed RSS, e assim por diante. possibilidades so infinitas! A plataforma inclui vrias pastas padro para a exibio de contatos. Por exemplo, a imagem abaixo mostra o contedo das pastas ao vivo que mostra todos os contatos com um nmero de telefone: As
247
Se a sincronizao de contatos acontece em segundo plano enquanto o usurio est visitando esta pasta ao vivo, o usurio ver a mudana acontecer em tempo real. Live folders no so apenas teis, mas elas tambm so fceis de adicionar ao seu aplicativo. Este artigo mostra como adicionar uma live folder para uma aplicao, como por exemplo as chamadas Prateleiras. Para entender melhor como trabalham as pastas, voc pode baixar o cdigo fonte da aplicao e modific-lo seguindo as instrues abaixo. Para dar ao usurio a opo de criar uma nova pasta para um aplicativo, voc primeiro precisa criar uma nova atividade com a inteno de filtro cuja ao android.intent.action.CREATE_LIVE_FOLDER. Para isso, basta abrir
O rtulo e o cone desta atividade so o que o usurio ver na tela inicial quando se escolhe uma pasta:
248
Uma vez que voc s precisa de uma inteno de filtro, possvel e, por vezes aconselhvel, a reutilizao de uma atividade existente. No caso de Prateleiras, vamos criar uma nova O atividade, papel desta
org.curiouscreature.android.shelves.activity.BookShelfLiveFolder.
atividade enviar um resultado Intent para Pgina contendo a descrio da live folder: o seu nome, cone, modo de apresentao e contedo URI. O URI contedo muito importante, pois descreve o que ContentProvider ser usado para preencher a live folder. O cdigo da atividade muito simples, como voc pode ver aqui:
public class BookShelfLiveFolder extends Activity { public static final Uri CONTENT_URI = Uri.parse("content://shelves/live_folders/books"); @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); final Intent intent = getIntent(); final String action = intent.getAction(); if (LiveFolders.ACTION_CREATE_LIVE_FOLDER.equals(action)) { setResult(RESULT_OK, createLiveFolder(this, CONTENT_URI, "Books", R.drawable.ic_live_folder)); } else { setResult(RESULT_CANCELED); } finish(); } private static Intent createLiveFolder(Context context, Uri uri, String name, int icon) { final Intent intent = new Intent(); intent.setData(uri); intent.putExtra(LiveFolders.EXTRA_LIVE_FOLDER_NAME, name); intent.putExtra(LiveFolders.EXTRA_LIVE_FOLDER_ICON, Intent.ShortcutIconResource.fromContext(context, icon)); intent.putExtra(LiveFolders.EXTRA_LIVE_FOLDER_DISPLAY_MODE, LiveFolders.DISPLAY_MODE_LIST); return intent; } }
Esta atividade, quando invocada com a ACTION_CREATE_LIVE_FOLDER, retorna com a inteno de um URI, content://shelves/live_folders/books , e trs extras para descrever a pasta ao vivo. Existem outros extras e constantes que voc pode usar e voc deve consultar a documentao do android.provider.LiveFolders para mais detalhes.
249
Quando a Home recebe esta ao, uma nova live folder criada no desktop do usurio, com o nome e o cone que voc forneceu. Ento, quando o usurio clica na pasta para abri-la ao vivo, a Home consulta o provedor de contedo referenciado pelo URI fornecido. Prestadores de pastas Live devem obedecer a regras especficas de nomeao. O Cursor retornado pelo mtodo query() deve ter pelo menos duas colunas chamadas LiveFolders._ID e LiveFolders.NAME . O primeiro o identificador nico de cada item na live folder e o segundo o nome do item. H nomes de coluna que voc pode usar para especificar um cone, uma descrio, a inteno de associar ao item (acionado quando o usurio clicar nesse item), etc. Novamente, consulte a documentao do android.provider.LiveFolders para mais detalhes . No nosso exemplo, tudo o que precisamos fazer modificar o provedor existente nas prateleiras Primeiro, chamado precisamos org.curiouscreature.android.shelves.provider.BooksProvider. modificar o URI_MATCHER para reconhecer nosso
Um mapa de
projeo pode ser usado para "renomear" colunas. No nosso caso, vamos substituir BooksStore.Book._ID , BooksStore.Book.TITLE e BooksStore.Book.AUTHORS com LiveFolders._ID , LiveFolders.TITLE e LiveFolders.DESCRIPTION:
private static final HashMap<string, string=""> LIVE_FOLDER_PROJECTION_MAP; static { LIVE_FOLDER_PROJECTION_MAP = new HashMap<string, string="">(); LIVE_FOLDER_PROJECTION_MAP.put(LiveFolders._ID, BooksStore.Book._ID + " AS " + LiveFolders._ID); LIVE_FOLDER_PROJECTION_MAP.put(LiveFolders.NAME, BooksStore.Book.TITLE + " AS " + LiveFolders.NAME); LIVE_FOLDER_PROJECTION_MAP.put(LiveFolders.DESCRIPTION, BooksStore.Book.AUTHORS + " AS " + LiveFolders.DESCRIPTION); }
Porque estamos a dar um ttulo e uma descrio para cada linha, Home ir exibir automaticamente cada item da live folder com duas linhas de texto. Finalmente, vamos
250
implementar a query(), fornecendo o nosso mapa de projeo para o construtor de consultas SQL:
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) { SQLiteQueryBuilder qb = new SQLiteQueryBuilder(); switch (URI_MATCHER.match(uri)) { // ... case LIVE_FOLDER_BOOKS: qb.setTables("books"); qb.setProjectionMap(LIVE_FOLDER_PROJECTION_MAP); break; default: throw new IllegalArgumentException("Unknown URI " + uri); } SQLiteDatabase db = mOpenHelper.getReadableDatabase(); Cursor c = qb.query(db, projection, selection, selectionArgs, null, null, BooksStore.Book.DEFAULT_SORT_ORDER); c.setNotificationUri(getContext().getContentResolver(), uri); return c; }
Agora voc pode compilar e implantar o aplicativo, v para a tela inicial e tente adicionar uma live folder. Voc pode adicionar uma pasta para os livros na sua tela inicial e quando voc abri-lo, veja a lista de todos os seus livros, com seus ttulos e autores, e bastou algumas linhas de cdigo:
251
A API de live folders extremamente simples e depende apenas de intenes e URI. Se voc quiser ver mais exemplos de aplicao das pastas, voc pode ler o cdigo-fonte do aplicativo de contatos e do provedor de Contatos.
Live Wallpapers
Comeando com o Android 2.1 (API Nvel 7), os utilizadores podem agora desfrutar de papis de parede ao vivo - mais ricos, animados, cenrios interativos - em suas telas iniciais. Um papel de parede ao vivo muito semelhante a uma aplicao Android normal e tem acesso a todas as facilidades da plataforma: SGL (desenho 2D), OpenGL (desenho 3D), GPS, acelermetro, acesso rede, etc. Os papis de parede ao vivo, includo no Nexus One, demonstram o uso de algumas dessas APIs para criar experincias divertidas e interessantes. Por exemplo, o papel de parede da grama usa a localizao do telefone para calcular o nascer e o por do sol, a fim de exibir o cu adequado.
Criar o seu prprio papel de parede ao vivo fcil, especialmente se voc teve experincia anterior com SurfaceView ou Canvas. Para saber como criar um papel de parede ao vivo, voc deve verificar se o cdigo de exemplo CubeLiveWallpaper . Em termos de execuo, um papel de parede ao vivo muito similar a um Service. A nica diferena a adio de um novo mtodo, onCreateEngine(), cujo objetivo criar um WallpaperService.Engine. O dispositivo responsvel pela gesto do ciclo de vida e desenho de um papel de parede. O sistema fornece uma superfcie sobre a qual voc pode desenhar, assim como voc faria com um SurfaceView. Desenho de um papel de parede pode ser muito caro por isso voc deve otimizar o cdigo, tanto quanto possvel para evitar o uso excessivo de CPU, no s para a vida da bateria, mas tambm para evitar a abrandar o resto do sistema. tambm por isso que a parte mais importante do ciclo de vida de um papel de parede quando se torna visvel, como indicado por uma ANDROID, uma viso geral Anderson Duarte de Amorim
252
chamada para onVisibilityChanged(). Quando invisveis, como quando o usurio inicia um aplicativo que cobre a tela inicial, o papel de parede tem que parar todas as atividades. O dispositivo tambm pode implementar vrios mtodos para interagir com o usurio ou o aplicativo de origem. Por exemplo, para reagir ao toque, basta implementar onTouchEvent(). Finalmente, os aplicativos podem enviar comandos arbitrrios para o papel de parede ao vivo. Atualmente, apenas o pedido inicial padro envia comandos para o onCommand() do papel de parede ao vivo:
1.
android.wallpaper.tap: Quando o usurio bate um espao vazio na rea de trabalho. Este comando interpretado pelo dispositivo para fazer o papel de parede reagir interao do usurio.
2.
Se voc est desenvolvendo um papel de parede ao vivo, lembre-se que o recurso s suportado no Android 2.1 (API nvel 7) e verses superiores da plataforma. Para garantir que seu pedido s pode ser instalado em dispositivos que suportam wallpapers, lembre-se de acrescentar o seguinte trecho de cdigo antes de publicar no Android Market: <uses-sdk android:minSdkVersion="7" />, que indica Android Market e plataforma que seu aplicativo requer Android 2.1 ou superior. <uses-feature android:name="android.software.live_wallpaper" />, que informa Android Market que seu aplicativo inclui um papel de parede ao vivo. Android Market usa esse recurso como um filtro, ao apresentar listas de usurios de aplicaes disponveis. Quando voc declarar esse recurso, o Android Market exibe sua aplicao apenas aos usurios cujas dispositivos suportam wallpapers ao vivo, enquanto oculta de outros dispositivos sobre os quais no seria capaz de executar.
253
Usando webViews
Um pequeno aplicativo chamado WebViewDemo mostra como voc pode adicionar contedo da Web em seu aplicativo. Voc pode encontr-la no projeto de aplicativos para Android. Esta aplicao demonstra como voc pode incorporar um WebView em uma atividade e tambm como voc pode ter comunicao bidirecional entre o aplicativo e o contedo da web. Um WebView utiliza o mesmo processamento e motor de JavaScript, o navegador, mas ele executado sob o controle de sua aplicao. O WebView podem ser em tela cheia ou voc pode mistur-la com outras vises. O WebView pode baixar contedo da web, ou pode vir a partir de arquivos locais armazenados em seu diretrio de ativos. O contedo pode at ser gerado dinamicamente pelo cdigo do aplicativo. Este aplicativo no faz muita coisa: quando voc clica sobre o Android, ele levanta o brao.
Isso poderia, naturalmente, ser facilmente conseguido com um pouco de JavaScript. Em vez disso, porm, WebViewDemo toma um caminho um pouco mais complicado para ilustrar duas caractersticas muito poderosa de WebView. Primeiro, o JavaScript em execuo dentro do WebView pode se ligar com o cdigo em sua atividade. Voc pode usar isso para fazer suas aes disparar JavaScript como comear uma nova atividade, ou pode ser usada para buscar dados de um banco de dados ou ContentProvider . A API para isso muito simples: basta conectar com o addJavascriptInterface()em sua WebView. Voc passa um objeto cujos mtodos voc
254
deseja expor ao JavaScript e o nome a ser usado para fazer chamadas. Voc pode ver a sintaxe exata em WebViewDemo.java. Aqui ns estamos fazendo o nosso objeto DemoJavascriptInterface disponvel em JavaScript para onde ele vai ser chamado de "window.demo". Em segundo lugar, sua atividade pode invocar mtodos JavaScript. Tudo que voc tem a fazer chamar o mtodo loadUrl com a chamada de JavaScript apropriada:
mWebView.loadUrl("javascript:wave()");
Nosso WebViewDemo utiliza duas tcnicas: quando voc clica sobre o Android, que chama a atividade, que ento se vira e chama de volta para o JavaScript. WebViews so muito poderosos e podem ser uma ferramenta valiosa para ajudar a construir a sua aplicao - especialmente se voc j tem um monte de contedo HTML. Quando isso acontece, usamos exatamente essa abordagem em algumas das aplicaes que ns escrevemos.
Funcionalidades
Caixa de pesquisa
Comeando com o Android 1.6, a plataforma inclui suporte para caixa de pesquisa rpida (CPR ou QSB Quick Search Box), uma poderosa estrutura de pesquisa de todo o sistema. A caixa de pesquisa rpida permite que os usurios rapidamente e facilmente encontrem o que procuram, tanto em seus dispositivos quanto na web. Ele sugere contedo no seu dispositivo enquanto voc digita como aplicativos, contatos, histrico do navegador, e msica. Tambm oferece resultados das sugestes de pesquisa na web, anncios de empresas locais e outras informaes do Google, tais como cotaes da bolsa, previso do tempo e status de vo. Tudo isso est disponvel logo na tela inicial, tocando na caixa de pesquisa rpida. Seus aplicativos podem fornecer sugestes de pesquisa que surgiro a usurios de CPR junto com outros resultados de pesquisa e sugestes. Isso torna possvel para os usurios acessem o contedo do seu aplicativo de fora da sua aplicao, por exemplo, a partir da tela inicial.
255
Nota: Os fragmentos de cdigo deste documento esto relacionados a um aplicativo de exemplo chamado Dicionrio pesquisvel. O aplicativo est disponvel para o Android 1.6 e plataformas posteriores. Plataforma de lanamentos de verses anteriores para o Android 1.6 j previam um mecanismo que permite que voc exponha pesquisa e sugestes de busca na sua aplicao, conforme descrito na documentao para SearchManager. Esse mecanismo no mudou e exige as seguintes coisas em sua AndroidManifest.xml :
1.
Em sua <activity>, a inteno do filtro, e uma referncia a um searchable.xml arquivo (descritas abaixo):
<intent-filter> <action android:name="android.intent.action.SEARCH" /> <category android:name="android.intent.category.DEFAULT" /> </intent-filter> <meta-data android:name="android.app.searchable" android:resource="@xml/searchable" />
2.
Um provedor de contedo que pode oferecer sugestes de pesquisa de acordo com as URIs e formatos de coluna especificada pelo Sugestes de Pesquisa seo do docs SearchManager.
<!-- Provides search suggestions for words and their definitions. --> <provider android:name="DictionaryProvider" android:authorities="dictionary" android:syncable="false" />
No searchable.xml, voc especifica algumas coisas sobre como voc deseja que o sistema de busca apresente a pesquisa para a sua aplicao, incluindo a autoridade do provedor de contedo que oferece sugestes para o usurio enquanto digitam. Aqui est um exemplo do searchable.xml de um aplicativo do Android que fornece sugestes de pesquisa dentro de suas prprias atividades:
<searchable xmlns:android="http://schemas.android.com/apk/res/android" android:label="@string/search_label" android:searchSuggestAuthority="dictionary" android:searchSuggestIntentAction="android.intent.action.VIEW"> </searchable>
256
No Android 1.6, que adicionou um novo atributo para os metadados conhecido como: android:includeInGlobalSearch. Especificando-a como "true" no seu searchable.xml, voc permite que QSB a pegar sua pesquisa provedor de contedo e d sugesto de incluso (se o usurio permite que suas sugestes a partir das definies de pesquisa do sistema). Voc tambm deve especificar um valor de cadeia para
android:searchSettingsDescription, que descreve aos usurios que tipo de sugestes o seu aplicativo fornece nas configuraes do sistema para a pesquisa.
<searchable xmlns:android="http://schemas.android.com/apk/res/android" android:label="@string/search_label" android:searchSettingsDescription="@string/settings_description" android:includeInGlobalSearch="true" android:searchSuggestAuthority="dictionary" android:searchSuggestIntentAction="android.intent.action.VIEW"> </searchable>
O mais importante e primeira coisa a notar que quando um usurio instala um aplicativo com um provedor de sugesto que participam no CPR, esta nova aplicao no ser ativado por padro para o CPR. O usurio pode optar por ativar as fontes de sugesto especial, as configuraes do sistema para a pesquisa (clicando em "Pesquisar" > "itens pesquisveis" nas configuraes). Voc deve pensar em como lidar com isso em sua aplicao. Talvez mostrar um aviso de que instrui o usurio a visitar as configuraes do sistema e permitir as sugestes do seu aplicativo. Quando o usurio habilita o item pesquisado, sugestes do aplicativo tero a chance de aparecer na QSB. Como sugestes de sua aplicao so escolhidas com mais freqncia, eles podem se mover para cima na lista.
257
Um dos nossos objetivos com o CPR torn-lo mais rpido para que os usurios acessem as coisas com mais freqncia. Uma maneira que fizemos isso 'shortcutting' algumas das sugestes de pesquisa previamente escolhido, ento eles sero mostrados imediatamente quando o usurio comea a digitar, ao invs de esperar para consultar os fornecedores de contedos. Sugestes de sua aplicao podem ser escolhidas como atalhos quando o usurio clica neles. Para sugestes de dinmicas que podem querer alterar o seu contedo (ou se tornar invlido), no futuro, voc pode fornecer um 'id atalho.
Sistema
Alocao de memria
Escrever eficazes aplicaes mveis nem sempre fcil. Em particular, aplicaes Android dependem de gerenciamento automtico de memria manipulado pelo coletor de lixo Dalvik, que por vezes pode causar problemas de desempenho se voc no for cuidadoso com as alocaes de memria. Em um caminho de cdigo de desempenho sensveis, tais como o mtodo de layout ou desenho de uma vista ou o cdigo da lgica de um jogo, qualquer atribuio tem um preo. Depois de muitas atribuies, o coletor de lixo vai comear e parar o aplicativo para deix-lo liberar memria. Na maioria das vezes, as coletas de lixo acontecem rpidas o suficiente para voc no perceber. No entanto, se uma coleo acontece enquanto voc estiver percorrendo uma lista de itens ou enquanto voc est tentando
258
derrotar um inimigo em um jogo, voc pode de repente ver uma queda no desempenho/ capacidade de resposta do aplicativo. No incomum para uma coleta de lixo levar de 100 a 200 ms. Para comparao, uma animao suave precisa desenhar cada quadro em 16 a 33 ms. Se a animao subitamente interrompida por 10 quadros, voc pode estar certo que os usurios iro notar. Na maioria das vezes, a coleta de lixo ocorre por causa de toneladas de objetos pequenos, de curta durao e alguns coletores de lixo, como catadores de lixo de geraes, que podem otimizar a coleta desses objetos para que o aplicativo no se interrompa com muita freqncia. O coletor de lixo Android infelizmente no capaz de realizar tais otimizaes e na criao de objetos de curta durao em caminhos de cdigo crtico de desempenho , portanto, muito caro para sua aplicao. Para ajudar a evitar freqentes coletas de lixo, o SDK do Android embarcado com uma ferramenta muito til chamado allocation tracker. Esta ferramenta parte do DDMS, que voc j deve ter usado para fins de depurao. Para comear a usar o tracker de atribuio, primeiro voc deve lanar a verso autnoma do DDMS, que pode ser encontrado na tools/ do SDK. A verso do DDMS includo no Eclipse plugin no oferece capacidade de usar o tracker de atribuio ainda. Depois DDMS estar funcionando, basta selecionar o seu processo de candidatura e, em seguida, clique na guia Atribuio Tracker. Na nova viso, clique em Iniciar monitoramento e ento usar o aplicativo para torn-lo executvel para os caminhos de cdigo que voc deseja analisar. Quando estiver pronto, clique em Obter atribuies. Uma lista de objetos alocados ser mostrada no primeiro quadro. Ao clicar em uma linha voc pode ver, na segunda tabela, o rastreamento de pilha que levaram atribuio. No somente voc saber que tipo de objeto foi alocado, mas tambm em qual segmento, em que classe, em qual arquivo e em qual linha. A figura abaixo mostra as atribuies realizadas por prateleiras enquanto estiver rolando um ListView.
259
O tracker de atribuio ajudar voc a identificar questes importantes em seu cdigo. Por exemplo, um erro comum que tenho visto em muitas aplicaes a criao de uma novo objeto Paint em cada sorteio. Mover a pintura em um campo de instncia uma soluo simples que ajuda no desempenho de um lote. Eu altamente encorajo-vos a examinar o cdigo fonte do Android para ver como podemos reduzir dotaes em caminhos de cdigo crtico de desempenho. Voc tambm vai descobrir o Android, assim, oferecer APIs para ajudar voc a reutilizar objetos.
260
e um cone; o sistema servidor l os recursos para uma variedade de razes (por exemplo, para exibir as notificaes que aplicativo), e por ltimo mas no menos importante, os arquivos de recurso so, obviamente, utilizado pelo prprio aplicativo. Os cdigos de manipulao de recursos no Android podem acessar os recursos de forma eficiente quando esto alinhados em limites de 4 bytes de memria. Mas, para recursos que no esto alinhados (ou seja, quando zipalign no tenha sido executado em um APK), ele tem que cair de volta a expressamente e l-los - o que mais lento e consome memria adicional. Para um desenvolvedor de aplicativos, este mecanismo de retorno muito conveniente. Ele oferece uma grande flexibilidade, permitindo o desenvolvimento de vrios mtodos diferentes, incluindo aqueles que no incluem a agregao de recursos como parte de seu fluxo normal. Infelizmente, para os usurios a situao inversa - os recursos de leitura de APKs desalinhados so lentos e exigem muito da memria. No melhor dos casos, o nico resultado visvel que tanto a aplicao inicial quanto o lanamento de aplicaes desalinhadas so mais lentos do que deveria. No pior dos casos, a instalao de vrias aplicaes com recursos de memria no alinhadas aumentam a presso, causando assim problemas para o sistema por ter que constantemente iniciar e matar processos. O usurio acaba com um dispositivo lento, com uma durao de bateria fraca. Felizmente, muito fcil para o alinhar recursos em sua aplicao: Usando ADT:
o
A ADT, plugin para o Eclipse (a partir da verso 0.9.3), alinhar automaticamente os pacotes de aplicativos libertados se a assistente de exportao usado para cri-las.
Usando Ant:
o
O script de construo Ant (a partir do Android 1.6) pode alinhar os pacotes de aplicativos. Metas para verses mais antigas da plataforma Android no so alinhados pelo script de construo Ant e precisam ser manualmente alinhados.
261
A partir dos 1,6 Android SDK, Ant alinha pacotes de sinais automaticamente, quando est construindo o modo de depurao.
No modo de lanamento, Ant alinha as embalagens se tiver informao suficiente para assinar os pacotes, uma vez que o alinhamento deve acontecer aps a assinatura. A fim de poder assinar os pacotes, e, portanto, para alinh-los, Ant precisa saber a localizao do armazenamento de chaves e o nome da chave na build.properties. O nome das propriedades so key.store e key.alias. Se as propriedades estiverem ausentes, o pacote de lanamento no ser assinado e, portanto, no vai se alinhar tambm.
Manualmente:
o
A fim de alinhar manualmente um pacote, zipalign est no tools/ do Android SDK 1.6 e posteriores. Voc pode us-lo para alinhar os pacotes de aplicativos voltados para qualquer verso do Android. Voc deve execut-lo somente aps a assinatura do arquivo APK, usando o seguinte comando: zipalign -v 4 source.apk destination.apk
Verificando o alinhamento:
o
comando
seguir
verifica
se
um
pacote
est
alinhado:
zipalign -c -v 4 application.apk
262
Nota
Todo o contedo foi retirado de <http://android.com> e correlatos sendo disponibilizado atravs da licena Apache 2.0 e traduzido com auxlio de <http://translate.google.com.br> com posterior reviso.
Fontes
About the Android Open Source Project. Disponvel em: <http://source.android.com/about/index.html>. Acesso em: 06 abril 2011. Activities. Disponvel em: <http://developer.android.com/guide/topics/fundamentals/activities.html>. Acesso em: 22 maro 2011. Application Resources. Disponvel em: <http://developer.android.com/guide/topics/resources/index.html>. Acesso em: 05 abril 2011. Applying Styles and Themes. Disponvel em: <http://developer.android.com/guide/topics/ui/themes.html>. Acesso em: 04 abril 2011. Bound Services. Disponvel em: <http://developer.android.com/guide/topics/fundamentals/bound-services.html>. Acesso em: 25 maro 2011. Creating Dialogs. Disponvel em: <http://developer.android.com/guide/topics/ui/dialogs.html>. Acesso em: 01 abril 2011. Creating Menus. Disponvel em: <http://developer.android.com/guide/topics/ui/menus.html>. Acesso em: 30 maro 2011. Creating Status Bar Notifications. Disponvel em: <http://developer.android.com/guide/topics/ui/notifiers/notifications.html>. Acesso em: 04 abril 2011.
263
Creating Toast Notifications. Disponvel em: <http://developer.android.com/guide/topics/ui/notifiers/toasts.html>. Acesso em: 04 abril 2011. Data Backup. Disponvel em: <http://developer.android.com/guide/topics/data/backup.html>. Acesso em: 06 abril 2011. Data Storage. Disponvel em: <http://developer.android.com/guide/topics/data/data-storage.html>. Acesso em: 05 abril 2011. Declaring Layout. Disponvel em: <http://developer.android.com/guide/topics/ui/declaring-layout.html>. Acesso em: 29 maro 2011. Fragments. Disponvel em: <http://developer.android.com/guide/topics/fundamentals/fragments.html>. Acesso em: 22 maro 2011. Handling UI Events. Disponvel em: <http://developer.android.com/guide/topics/ui/ui-events.html>. Acesso em: 04 abril 2011. How Android Draws Views. Disponvel em: <http://developer.android.com/guide/topics/ui/how-android-draws.html>. Acesso em: 04 abril 2011. Loaders. Disponvel em: <http://developer.android.com/guide/topics/fundamentals/loaders.html>. Acesso em: 23 maro 2011. Notifying the User. Disponvel em: <http://developer.android.com/guide/topics/ui/notifiers/index.html>. Acesso em: 04 abril 2011. Processes and Threads. Disponvel em:
264
265
Services. Disponvel em: <http://developer.android.com/guide/topics/fundamentals/services.html>. Acesso em: 25 maro 2011. Tasks and Back Stack. Disponvel em: <http://developer.android.com/guide/topics/fundamentals/tasks-and-back-stack.html>. Acesso em: 24 maro 2011. User Interface. Disponvel em: <http://developer.android.com/guide/topics/ui/index.html>. Acesso em: 29 maro 2011. Using the Action Bar. Disponvel em: <http://developer.android.com/guide/topics/ui/actionbar.html>. Acesso em: 30 maro 2011.
266
Layout Tricks: Creating Efficient Layouts. Disponvel em: <http://developer.android.com/resources/articles/layout-tricks-efficiency.html>. Acesso em: 21 maro 2011. Layout Tricks: Merging Layouts. Disponvel em: <http://developer.android.com/resources/articles/layout-tricks-merge.html>. Acesso em: 21 maro 2011. Layout Tricks: Using ViewStubs. Disponvel em: <http://developer.android.com/resources/articles/layout-tricks-stubs.html>. Acesso em: 21 maro 2011. Live Folders. Disponvel em: <http http://developer.android.com/resources/articles/live-folders.html>. Acesso em: 21 maro 2011. Live Wallpapers. Disponvel em: <http://developer.android.com/resources/articles/live-wallpapers.html>. Acesso em: 21 maro 2011. ListView Backgrounds: An Optimization. Disponvel em: <http://developer.android.com/resources/articles/listview-backgrounds.html>. em: 21 maro 2011. Touch Mode. Disponvel em: <http://developer.android.com/resources/articles/touch-mode.html>. Acesso em: 21 maro 2011. Using Text-to-Speech. Disponvel em: <http://developer.android.com/resources/articles/tts.html>. Acesso em: 18 maro 2011. Zipalign: an Easy Optimization. Disponvel em: <http://developer.android.com/resources/articles/zipalign.html>. Acesso em: 21 maro 2011. Acesso
267