ANDROID, uma visão geral. Anderson Duarte de Amorim

Tamanho: px
Começar a partir da página:

Download "ANDROID, uma visão geral. Anderson Duarte de Amorim"

Transcrição

1 ANDROID, uma visão geral Anderson Duarte de Amorim 2011

2 Conteúdo Introdução Atividades Criar uma atividade Implementando uma interface de usuário Declarando a atividade no manifesto O uso de filtros intenção Iniciar uma atividade Iniciar uma atividade para um resultado Encerrar uma atividade Gerenciando o ciclo de atividade Aplicar o ciclo de vida callbacks Salvando estado de atividade Manipulação de alterações na configuração Coordenar as atividades Fragmentos Filosofia de design Criando um fragmento DialogFragment ListFragment PreferenceFragment Adicionando uma interface de usuário Criando um layout Adicionando um fragmento de uma atividade Adicionando um fragmento sem uma interface de usuário (UI) Gerenciando fragmentos Executando transações com fragmento ANDROID, uma visão geral Anderson Duarte de Amorim 2

3 Comunicando-se com a atividade Criar callbacks evento para a atividade Adicionando itens à barra de ação Manuseio do ciclo de vida do fragmento Coordenação com o ciclo de vida de atividade Loaders Resumo API Loader Usando carregadores em um aplicativo Iniciando um Loader Reiniciando o Loader Usando callbacks do LoaderManager Exemplo Tarefas e pilha de execução Salvando estado de atividade Gerenciando tarefas Definição de modos de lançamento Usando o arquivo de manifesto Usando as opções de intenções Manipulação de afinidades Limpando a pilha de volta Iniciando uma tarefa Serviços O básico Você deve utilizar um serviço ou um thread? Declarando um serviço no manifesto Criando um serviço iniciado Segmentação Android 1.6 ou inferior ANDROID, uma visão geral Anderson Duarte de Amorim 3

4 Estendendo a classe IntentService Estendendo a classe de serviço Iniciando um serviço Parando um serviço Criando um serviço vinculado Enviando notificações para o usuário Executando um serviço em primeiro plano Gerenciando ciclo de vida de um serviço Aplicando o ciclo de vida dos callbacks Serviços vinculados O básico Vinculação a um serviço iniciado Criando um serviço ligado Estendendo a classe Binder Usando um Messenger Vinculação a um serviço Notas adicionais Gerenciando o ciclo de vida de um serviço de associação Processos e threads Processos Ciclo de vida do processo Thread Threads funcionais Usando AsyncTask Métodos de Thread-safe Comunicação entre processos Interface de usuário ANDROID, uma visão geral Anderson Duarte de Amorim 4

5 Hierarquia de view Como o Android desenha views Layout Widgets Eventos UI Menus Tópicos Avançados Adaptadores Estilos e Temas Declarando Layout Escreve o XML Carregar os recursos XML Atributos ID Parâmetros de layout Posição de Layout Tamanho, padding e margin Criando Menus Menu de Opções Menu de Contexto Submenu Criando um recurso de menu Inflar um recurso de menu Criando um Menu de Opções Respondendo à ação do usuário Alterando os itens de menu em tempo de execução Criando um Menu de Contexto ANDROID, uma visão geral Anderson Duarte de Amorim 5

6 Registre uma ListView Criando Submenus Outras funções do menu Grupos de Menu Itens de menu verificados As teclas de atalho Adicionar intenções em menu dinamicamente Permitindo a sua atividade a ser adicionada para outros menus Usando a barra de ação Adicionando a barra de ação Removendo a barra de ação Adicionando itens de ação Usando o ícone do aplicativo como um item de ação Usando o ícone do aplicativo para navegar "para cima" Adicionando uma exibição de ação Adicionando abas Adicionando de navegação drop-down Exemplo de SpinnerAdapter e OnNavigationListener Estilizando a barra de ação Criando caixas de diálogo Mostrando uma caixa de diálogo Dispensar um diálogo Usando demissão de receptores Criando um AlertDialog Adicionando botões Adicionando uma lista Adicionando caixas de seleção e botões de rádio ANDROID, uma visão geral Anderson Duarte de Amorim 6

7 Criar um ProgressDialog Mostrando uma barra de progresso Criando uma caixa de diálogo personalizada Manipulando eventos de UI Os ouvintes de eventos Manipuladores de eventos Modo de toque Manipulação do foco Notificar o usuário Notificação brinde Criando notificações brinde Notificação na barra de status Criação de notificações da barra de status Notificação de diálogo Aplicando estilos e temas Definição de estilos Herança Propriedades do estilo Aplicando estilos e temas para a interface do usuário Aplicar um estilo a uma view Aplicar um tema a uma atividade ou aplicação Selecione um tema baseado na versão de plataforma Usando estilos e temas da plataforma Recursos de aplicação Armazenamento de dados Utilizando preferências compartilhadas Preferências do usuário ANDROID, uma visão geral Anderson Duarte de Amorim 7

8 Usando o armazenamento interno Salvando os arquivos de cache Usando o armazenamento externo Verificar a disponibilidade dos meios Acessando arquivos em armazenamento externo Escondendo seus arquivos a partir da Media Scanner Como salvar arquivos que devem ser compartilhados Salvando os arquivos de cache Utilizando bancos de dados Banco de dados de depuração Usando uma conexão de rede Artigos Acessibilidade Linguagens e recursos Linguagens e localidade Fazendo o dispositivo falar Interface Toque Gestos Método de entrada de dados Criando um método de entrada de dados Ações de desenhos Truques de layout: criando layouts eficientes Truques de layout: usando ViewStub Truques de layout: mesclando layouts ListView, uma otimização Live folders ANDROID, uma visão geral Anderson Duarte de Amorim 8

9 Live Wallpapers Usando webviews Funcionalidades Caixa de pesquisa Sistema Alocação de memória Zipaling oferece uma otimização fácil Nota Fontes Fontes das imagens Fontes dos artigos ANDROID, uma visão geral Anderson Duarte de Amorim 9

10 Introdução 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 manutenção e desenvolvimento do Android. Muitos fabricantes de dispositivos trouxeram ao mercado de dispositivos rodando o Android, e eles são disponíveis ao redor do mundo. O objetivo principal é construir uma plataforma de software excelente para usuários de todos os dias. Uma série de empresas empenhou muitos engenheiros para atingir esse objetivo, e o resultado é uma produção total de produtos de consumo de qualidade, cuja fonte é aberta para customização e portabilidade. Você pode encontrar mais informações sobre o Android a partir destas páginas abaixo: Filosofia de projeto e objetivos Interagindo com o projeto Compatibilidade com Android Informações sobre licenciamento ANDROID, uma visão geral Anderson Duarte de Amorim 10

11 Atividades Uma Activity é um componente do aplicativo que fornece uma tela com a qual os usuários podem interagir, a fim de fazer algo, como discar o telefone, tirar uma foto, enviar um , ou ver um mapa. Para cada atividade é dada uma janela na qual se desenha sua interface de usuário. 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 múltiplas atividades que são frouxamente ligadas uns aos outros. Normalmente uma atividade em um aplicativo é especificada como a atividade principal", que é apresentada ao usuário ao iniciar o aplicativo pela primeira vez. Cada atividade pode começar outra atividade, a fim de executar ações diferentes. Cada vez que começa uma nova atividade, a atividade anterior é interrompida, mas o sistema preserva a atividade em uma pilha (a "pilha de volta"). Quando uma nova atividade começa, é empurrada para a pilha de volta e leva o foco do usuário. A pilha de volta usa "last in, first out" como mecanismo de fila, então, quando o usuário está em uma atividade e pressione a tecla BACK, a atividade é removida da pilha (e destruída) e retoma a atividade anterior. Quando uma atividade é parada por causa de uma nova atividade, há uma notificação da alteração no estado através de métodos de retorno da atividade do ciclo de vida. Existem vários métodos de retorno que uma atividade possa receber, devido a uma mudança em seu estado. Por exemplo, quando parado, sua atividade deve liberar todos os objetos grandes, como conexões de rede ou banco de dados. Quando a atividade recomeça, você pode readquirir os recursos necessários e retomar as ações que foram interrompidas. Estas transições de estado são todos parte do ciclo de atividade. Criar uma atividade Para criar uma atividade, você deve criar uma subclasse da Activity (ou uma subclasse existente do mesmo). Em sua subclasse, você precisa implementar métodos de callback que chama o sistema quando ocorrem as transições de atividade entre diversos estados do seu ciclo de vida, como quando a atividade está sendo criada, parou, recomeçou, ou foi destruída. Os dois métodos de retorno mais importantes são: oncreate(): Você deve implementar este método. O sistema chama isso ao criar a sua atividade. Dentro de sua aplicação, você deve inicializar os componentes essenciais de ANDROID, uma visão geral Anderson Duarte de Amorim 11

12 sua atividade. Mais importante, este é o lugar onde você deve chamar setcontentview() para definir o layout para a atividade do usuário a interface. onpause(): O sistema chama este método como o primeiro indício de que o usuário está saindo de sua atividade (embora nem sempre signifique que a atividade está sendo destruída). Isso geralmente é onde você deve cometer quaisquer alterações que devem ser mantidas para além da sessão atual do usuário (porque o usuário pode não voltar). Existem vários métodos de retorno do ciclo de vida de outros que você deve usar a fim de proporcionar uma experiência de usuário mais fluida entre as atividades e manipular interrupções inesperadas que causem a sua atividade a ser interrompida e até mesmo destruída. Implementando uma interface de usuário A interface de usuário para uma determinada atividade é assegurada por uma hierarquia de pontos de vista - objetos derivam da classe View. Cada exibição controla um determinado espaço retangular dentro da janela da atividade e pode responder a interação do usuário. Por exemplo, uma visão pode ser um botão que inicia uma ação quando o usuário tocá-la. Android fornece um número de pontos de vista prontos que você pode usar para criar e organizar seu layout. "Widgets" são vistas que proporcionam um visual (interativo) de elementos para a tela, como um botão, um campo texto, checkbox, ou apenas uma imagem. "Esquemas" são pontos de vista derivados de ViewGroup que fornecem um modelo de layout exclusivo para a estrutura derivada, como um layout linear, um layout de grade, ou a disposição relativa. Você pode criar uma subclasse da View e ViewGroup (ou subclasses existentes) para criar seus próprios widgets e layouts e aplicá-las ao seu layout atividade. A maneira mais comum para definir um layout usando pontos de vista é com um arquivo XML salvo disposição em recursos do seu aplicativo. Dessa forma, você pode manter o design da sua interface de usuário separadamente do código fonte que define o comportamento da atividade. Você pode definir o layout da interface do usuário para a sua atividade com setcontentview(), passando a identificação do recurso para o layout. No entanto, você também pode criar novas Views no seu código de atividade e construir ANDROID, uma visão geral Anderson Duarte de Amorim 12

13 uma hierarquia de vista através da inserção de novos Views em um ViewGroup, em seguida, usar esse esquema, passando a raiz ViewGroup para setcontentview(). Declarando a atividade no manifesto Você deve declarar a sua atividade no arquivo de manifesto para que ele seja acessível para o sistema. Para declarar sua atividade, abra o arquivo e adicione um <activity> como um filho do <application>. Por exemplo: <manifest... > <application... > <activity android:name=".exampleactivity" />... </application... >... </manifest > Existem vários outros atributos que podem ser incluídos nesse elemento, para definir propriedades, como o rótulo para a atividade, um ícone para a atividade, ou um tema ao estilo de interface do usuário da atividade. O uso de filtros intenção Um <activity> também pode especificar filtros diferentes, usando o <intent-filter>, a fim de declarar como outros componentes de aplicação podem ativá-lo. Quando você cria um novo aplicativo usando as ferramentas do Android SDK, a atividade de topo que é criada para você automaticamente inclui a intenção de filtro que declara a atividade e responde à ação "principal" e deve ser colocado no "lançador" da categoria. A intenção parece filtro como este: <activity android:name=".exampleactivity" android:icon="@drawable/app_icon"> <intent-filter> <action android:name="android.intent.action.main" /> <category android:name="android.intent.category.launcher" /> </intent-filter> </activity> 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 lançador de aplicação. ANDROID, uma visão geral Anderson Duarte de Amorim 13

14 Se você pretende que o seu aplicativo seja auto-suficiente e não permita que outras aplicações ativem as suas atividades, então você não precisa de nenhum outro filtro de intenção. Apenas uma atividade deve ter a ação "principal" e "lançador" da categoria, como no exemplo anterior. Atividades que você não deseja disponibilizar para outros aplicativos não devem ter a intenção de filtros e você pode iniciá-los usando as intenções explícitas. No entanto, se você quiser a sua atividade para responder às intenções implícitas que são entregues a partir de outras aplicações (e suas próprias), então você deve definir filtros de intenção adicional para a sua atividade. Para cada tipo de intenção 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 intenções para que sua atividade possa responder. Iniciar uma atividade Você pode iniciar outra atividade, chamando startactivity(), passando-lhe uma Intent que descreve a atividade que deseja iniciar. A intenção especifica qualquer atividade exatamente o que deseja iniciar ou descreve o tipo de ação que deseja executar (e o sistema seleciona a atividade adequada para você, que pode mesmo ser de um aplicativo diferente). A intenção também pode transportar pequenas quantidades de dados a serem utilizados pela atividade que é iniciada. Quando se trabalha dentro de sua própria aplicação, muitas vezes você precisa simplesmente lançar uma atividade conhecida. Você pode fazer isso criando uma intenção que define explicitamente a atividade que deseja iniciar, usando o nome da classe. Por exemplo, aqui está como uma atividade inicia outra atividade denominada SignInActivity: Intent intent = new Intent(this, SignInActivity.class); startactivity(intent); No entanto, sua aplicação pode também querer executar alguma ação, como enviar um , mensagem de texto, ou atualização de status, usando dados de sua atividade. Neste caso, sua aplicação não pode ter as suas próprias atividades para realizar tais ações, para que você possa aproveitar ao invés das atividades previstas por outras aplicações no dispositivo, que pode executar as ações para você. Este é o lugar onde as ANDROID, uma visão geral Anderson Duarte de Amorim 14

15 intenções são realmente valiosas, você pode criar uma intenção que descreve uma ação que deseja executar e o sistema inicia a atividade adequada a partir de outro aplicativo. Se houver múltiplas atividades que podem manipular a intenção, então o usuário pode selecionar qual usar. Por exemplo, se você quer permitir que o usuário envie uma mensagem de , você pode criar a seguinte intenção: Intent intent = new Intent(Intent.ACTION_SEND); intent.putextra(intent.extra_ , recipientarray); startactivity(intent); O EXTRA_ extra adicionado é uma matriz de seqüência de endereços de para onde o deve ser enviado. Quando um aplicativo de responde a esta intenção, ele lê a matriz de cadeia prevista na extra e as coloca no campo "Para" do formulário de composição de . Iniciar uma atividade para um resultado Às vezes, você pode querer receber um resultado da atividade que você começar. Nesse caso, iniciar a atividade, chamando startactivityforresult() (em vez de startactivity() ). Para então receber o resultado da atividade subseqüente, aplicar o onactivityresult(), método de retorno. Quando a atividade subseqüente é feita, ele retorna um resultado de uma Intent para o seu método onactivityresult(). Por exemplo, talvez você queira que o usuário escolha um de seus contatos, para que sua atividade pode fazer algo com as informações desse contato. Veja como você pode criar uma intenção e manipular o resultado: private void pickcontact() { // Create an intent to "pick" a contact, as defined by the content provider URI Intent intent = new Intent(Intent.ACTION_PICK, Contacts.CONTENT_URI); startactivityforresult(intent, protected void onactivityresult(int requestcode, int resultcode, Intent data) { // If the request went well (OK) and the request was PICK_CONTACT_REQUEST if (resultcode == Activity.RESULT_OK && requestcode == PICK_CONTACT_REQUEST) { // Perform a query to the contact's content provider for the contact's name Cursor cursor = getcontentresolver().query(data.getdata(), new String[] {Contacts.DISPLAY_NAME, null, null, null); if (cursor.movetofirst()) { // True if the cursor is not empty int columnindex = cursor.getcolumnindex(contacts.display_name); String name = cursor.getstring(columnindex); ANDROID, uma visão geral Anderson Duarte de Amorim 15

16 // Do something with the selected contact's name... Este exemplo mostra a lógica básica que você deve usar seu método onactivityresult() para lidar com um resultado de atividade. A primeira condição verifica se a solicitação foi bem-sucedida, se for, então o resultcode será RESULT_OK e se a solicitação para que este resultado está respondendo é conhecido, neste caso, o requestcode coincide com o segundo parâmetro enviada com startactivityforresult(). De lá, o código manipula o resultado de atividade, consultando os dados retornados de uma Intent. O que acontece é, um ContentResolver executa uma consulta contra um provedor de conteúdo, que retorna um Cursor que permite que os dados consultados possam serem lidos. Encerrar uma atividade Você pode encerrar uma atividade chamando seu método finish(). Você também pode encerrar uma atividade separada que já começou chamando finishactivity(). Nota: Na maioria dos casos, você não deve terminar explicitamente uma atividade com estes métodos. Como discutido na seção seguinte sobre o ciclo de vida de atividade, o sistema Android gerencia a vida de uma atividade para você, então você não precisa terminar a sua própria atividade. Chamar esses métodos pode afetar negativamente a experiência do usuário e só deve ser usado quando você realmente não quer que o usuário retorne a esta instância da atividade. Gerenciando o ciclo de atividade Gerenciar o ciclo de vida de suas atividades através da implementação de métodos de retorno é essencial para desenvolver uma aplicação forte e flexível. O ciclo de vida de uma atividade está diretamente afetada pela sua associação com outras atividades, a sua missão e voltar à pilha. Uma atividade pode existir em três estados, essencialmente: Retomado: A atividade está em primeiro plano da tela e tem o foco do usuário. (Esse estado é também por vezes referido como "run".) ANDROID, uma visão geral Anderson Duarte de Amorim 16

17 Em pausa: Outra atividade está em primeiro plano e tem foco, mas este é ainda visível. Ou seja, outra atividade é visível na parte superior de um presente e que a atividade é parcialmente transparente ou não cobre a tela inteira. Uma atividade em pausa está completamente viva (o objeto Activity é mantido na memória, ele mantém todas as informações do estado e membro, e permanece preso ao gerenciador de janelas), mas pode ser morta pelo sistema em situações de pouca memória. Parado: A atividade é totalmente obscurecida por outra atividade (a atividade está agora em "background"). A atividade parada também está ainda viva (o objeto Activity é mantido na memória, ele mantém todas as informações do estado e membro, mas não está ligado ao gerenciador de janelas). No entanto, já não é visível para o usuário e pode ser morto pelo sistema quando a memória é necessária em outro lugar. Se uma atividade está em pausa ou parada, o sistema pode retirá-la da memória, quer por pedir para terminar (chamando seu finish()), ou simplesmente matar o processo. Quando a atividade é aberta novamente (depois de ter sido concluído ou morto), ela deve ser criada por toda parte. Aplicar o ciclo de vida callbacks Quando uma atividade transita entrando e saindo dos diferentes estados descritos acima, ele é notificado através de vários métodos de retorno. Todos os métodos de callback são ganchos que você pode substituir para fazer um trabalho adequado quando o estado da sua atividade muda. A atividade seguinte inclui cada um dos métodos de ciclo de vida fundamentais: public class ExampleActivity extends Activity public void oncreate(bundle savedinstancestate) { super.oncreate(savedinstancestate); // The activity is being protected void onstart() { super.onstart(); // The activity is about to become protected void onresume() { super.onresume(); // The activity has become visible (it is now "resumed"). ANDROID, uma visão geral Anderson Duarte de Amorim 17

18 @Override protected void onpause() { super.onpause(); // Another activity is taking focus (this activity is about to be protected void onstop() { super.onstop(); // The activity is no longer visible (it is now protected void ondestroy() { super.ondestroy(); // The activity is about to be destroyed. Nota: A implementação destes métodos do ciclo de vida deve sempre chamar a implementação da superclasse antes de fazer qualquer trabalho, conforme mostrado nos exemplos acima. Juntos, esses métodos definem o ciclo de vida de uma atividade. Ao implementar esses métodos, você pode monitorar três 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 instalação do "Estado" global (tal como a definição de layout) em oncreate(), e liberar todos os recursos remanescentes em ondestroy(). Por exemplo, se a sua atividade tem um segmento em execução em segundo plano para transferir os dados da rede, ele pode criar esse tópico em oncreate() e depois parar o segmento em ondestroy(). O tempo de vida visível de uma atividade acontece entre a chamada para onstart() e a chamada para onstop(). Durante este tempo, o usuário pode ver a atividade na tela e interagir com ele. Por exemplo, onstop() é chamado quando inicia uma nova atividade e esta não é mais visível. Entre estes dois métodos, você pode manter os recursos que são necessários para mostrar a atividade para o usuário. Por exemplo, você pode registrar um BroadcastReceiver em onstart() para monitorar as mudanças que impactam sua interface do usuário, e cancelar o registro em onstop() quando o usuário não pode mais ver o que você está sendo exibido. O sistema pode chamar onstart() e onstop() várias vezes durante toda a vida útil da atividade, como a atividade se alterna entre visível e oculta para o usuário. ANDROID, uma visão geral Anderson Duarte de Amorim 18

19 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 usuário. Uma atividade pode freqüentemente transitar para dentro e fora do plano, por exemplo, onpause() é chamado quando o dispositivo vai dormir ou quando uma caixa de diálogo aparece. O código desses dois métodos deve ser bastante leve, para evitar transições lentas que fazem o usuário esperar. A figura 1 ilustra esses laços e os caminhos de uma atividade que podem levar a esses estados. Figura 1. O ciclo de vida de atividade. ANDROID, uma visão geral Anderson Duarte de Amorim 19

20 Tabela 1. Um resumo do ciclo de vida do callback métodos atividade. Método Descrição Chamado quando a atividade Killable depois? Seguinte é criada pela primeira vez. Isto é onde você deve fazer oncreate() tudo do seu conjunto estático normal - criar pontos de vista, Não onstart() vincular dados em listas, e assim por diante. Sempre seguido por onstart(). Chamado depois que a atividade foi interrompida, onrestart() pouco antes de ele ser iniciado novamente. Sempre seguido Não onstart() por onstart() Chamado imediatamente antes da atividade tornar-se visível onstart() para o usuário. Seguido por onresume() se a atividade Não onresume() vem para o primeiro plano, ou onstop() se torna oculto. Chamado imediatamente antes da atividade passar a interagir com o usuário. Neste ponto, a onresume() atividade está no topo da pilha Não onpause() de atividade. Sempre seguido por onpause(). ANDROID, uma visão geral Anderson Duarte de Amorim 20

21 Chamado quando o sistema está prestes a começar a retomar a outra atividade. Este método é geralmente usado para confirmar as alterações não salvas, dados persistentes, animações stop e outras coisas que podem estar consumindo onpause() CPU, e assim por diante. Ele deve fazer tudo o que ele faz Sim onresume() ou onstop() muito rapidamente, porque a próxima atividade não será retomada até que ele retorne. Seguidas por onresume() se a atividade retorna para a frente, ou por onstop() se torna invisível para o usuário. Chamado quando a atividade já não é visível para o usuário. Isso pode acontecer porque ele está sendo destruído, ou porque outra atividade (seja onstop() um existente ou uma nova) foi retomado e está cobrindo-o. Seguidas por onrestart() se a Sim onrestart() ou ondestroy() atividade está voltando para interagir com o usuário, ou por ondestroy() se essa atividade está indo embora. ANDROID, uma visão geral Anderson Duarte de Amorim 21

22 Chamado antes que a atividade é destruída. Esta é a chamada final que a atividade irá receber.poderia ser chamada, quer porque a atividade está acabando ondestroy() (alguém chamado finish() nela), ou porque o sistema Sim nada está destruindo essa instância da atividade para economizar espaço. Você pode distinguir entre estes dois cenários com o isfinishing(). A coluna chamada "killable depois?" indica se o sistema pode matar o processo que acolhe a atividade a qualquer momento após o método retornar, sem executar outra linha. Três métodos são marcados como "sim": (onpause(), onstop(), e ondestroy() ). onpause() é o primeiro dos três, uma vez que a atividade é criada, onpause() é o último método que é garantido para ser chamado antes que o processo pode ser morto, se o sistema deve recuperar a memória em caso de emergência, então onstop() e ondestroy() não podem ser chamados. Portanto, você deve usar onpause() para escrever dados persistentes para armazenamento. No entanto, você deve ser seletivo sobre quais informações devem ser mantidas durante onpause(), porque os procedimentos de bloqueio neste método bloqueiam a passagem para a próxima atividade e retardam a experiência do usuário. Métodos que são marcados como "Não" na coluna killable protegem o processo da atividade de ser morto desde o momento em que são chamados. Assim, uma atividade é killable a partir do momento onpause() e retorna quando onresume() é chamado. Não será novamente killable até onpause() seja novamente chamado e retornado. Nota: uma atividade que não é tecnicamente "killable" por esta definição na tabela 1 ainda pode ser morta pelo sistema, mas isso vai acontecer apenas em circunstâncias extremas, quando não há outro recurso. ANDROID, uma visão geral Anderson Duarte de Amorim 22

23 Salvando estado de atividade A introdução à Gestão do Ciclo de Atividade menciona brevemente que, quando uma atividade está em pausa ou parada, o estado da atividade é mantido. Isto é verdade porque a Activity ainda está retida na memória quando está em pausa ou parada, todas as informações sobre seus membros e estado atuais ainda estão vivos. Assim, qualquer alteração que o usuário fez no âmbito da atividade é retida na memória, de modo que quando a atividade retorna para o primeiro plano (quando ele "retoma"), essas mudanças ainda estão lá. Figura 2. As duas formas em que para a atividade um usuário 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 é destruído, então recriada e a atividade deve restaurar o estado da atividade anterior (direita). No entanto, quando o sistema destrói uma atividade, a fim de recuperar a memória, a Activity é destruída, então o sistema não pode simplesmente continuar com o seu estado intacto. Em vez disso, o sistema deve recriar a Activity se o usuário navega de volta para ele. No entanto, o usuário não sabe que o sistema destrói e recria a atividade e, assim, provavelmente espera que a atividade seja exatamente como era. Nessa situação, ANDROID, uma visão geral Anderson Duarte de Amorim 23

24 você pode garantir que informações importantes sobre o estado de atividade são preservadas através da implementação de um método de retorno adicional que permite que você salve as informações sobre o estado de sua atividade e, em seguida, restaura quando o sistema recria a atividade. O método de callback em que você pode salvar informações sobre o estado atual da sua atividade é onsaveinstancestate(). O sistema chama este método antes de fazer a atividade vulnerável a ser destruída e passa-lhe um objeto Bundle. O Bundle é o lugar onde você pode armazenar informações de estado sobre a atividade como pares valornome, utilizando métodos como putstring(). Então, se o sistema mata a atividade e o usuário 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 não há informações do estado para restaurar, em seguida, o Bundle que passou a oncreate() se torna nulo. Nota: Não há nenhuma garantia de que onsaveinstancestate() será chamado antes de sua atividade ser destruída, porque há casos em que não será necessário salvar o estado (como quando o usuário deixa a sua atividade com a chave de volta, porque a usuário explicitamente encerra as atividades). Se o método for chamado, ele sempre é chamado antes de onstop() e, possivelmente, antes de onpause(). No entanto, mesmo se você não faz nada e não implementar onsaveinstancestate(), alguns estados de atividade são restaurados pela Activity de implementação padrão da classe de onsaveinstancestate(). Especificamente, a implementação padrão chama onsaveinstancestate() para cada View no layout, que permite fornecer informações sobre si que devem ser salvos. Quase todos os widgets no âmbito Android implementam este método, de modo que qualquer mudança visível para o interface do usuário são automaticamente salvas e restauradas quando sua atividade é recriada. Por exemplo, o EditText salva qualquer texto digitado pelo usuário e o CheckBox widget salva se é marcado ou não. O único trabalho exigido por você é fornecer uma identificação única (com o android:id) para cada elemento gráfico que deseja salvar seu estado. Se um elemento não tem um ID, então ele não pode salvar seu estado. Você também pode parar explicitamente de salvar em seu layout seu estado, definindo o android:saveenabled para "false" ou chamando o setsaveenabled(). Normalmente, você ANDROID, uma visão geral Anderson Duarte de Amorim 24

25 não deve desativar isso, mas você pode caso queira restaurar o estado da atividade de interface diferente. Embora a implementação padrão de onsaveinstancestate() salva as informações úteis sobre a atividade da sua interface, você ainda pode precisar substituí-lo para guardar informações 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 usuário, mas os membros que detêm esses valores UI não são restaurados, por padrão). Como a implementação padrão de onsaveinstancestate() ajuda a salvar o estado da interface do usuário, se você substituir o método para salvar informações de estado adicionais, você deve sempre chamar a implementação da superclasse de onsaveinstancestate() antes de fazer qualquer trabalho. Nota: Devido ao onsaveinstancestate() não ser garantido de ser chamado, você deve usá-lo apenas para registrar o estado transiente da atividade (o estado da interface do usuário), 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 usuário deixa a atividade. Uma boa maneira de testar a capacidade do seu aplicativo para restaurar seu estado é simplesmente girar o dispositivo para fazer alterações na orientação da tela. Quando da mudança de orientação da tela, o sistema destrói e recria a atividade a fim de aplicar recursos alternativos que possam estar disponíveis para a nova orientação. Por esta razão, é muito importante para sua atividade restaurar completamente o seu estado quando ele é recriado, pois os usuários regularmente giram a tela ao usar aplicações. Manipulação de alterações na configuração Algumas configurações de dispositivo podem mudar durante a execução (tais como a orientação da tela, a disponibilidade de teclado e idioma). Quando essa mudança ocorre, o Android reinicia a atividade em execução (ondestroy() é chamado, seguido imediatamente por oncreate()). O comportamento reiniciar é projetado para ajudar a sua candidatura a se adaptar às novas configurações automaticamente recarregando a sua aplicação com recursos alternativos que você forneceu. Se você projeta sua atividade ANDROID, uma visão geral Anderson Duarte de Amorim 25

26 para lidar adequadamente com este evento, vai ser mais resistentes a eventos inesperados no ciclo de atividade. A melhor maneira de lidar com uma mudança de configuração, tais como uma mudança na orientação da tela, é simplesmente preservar o estado do seu aplicativo usando onsaveinstancestate() e onrestoreinstancestate() (ou oncreate() ), como discutido na seção anterior. Coordenar as atividades Quando uma atividade começa outra, ambas experimentam as transições do ciclo de vida. A primeira atividade faz uma pausa e para (embora, não vai parar se ele ainda está visível 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 não está completamente parada antes de a segunda ser criada. Pelo contrário, o processo de iniciar o segundo se sobrepõe ao processo de parar o primeiro. A ordem dos retornos do ciclo de vida é bem definida, especialmente quando as duas atividades estão no mesmo processo e está começando um do outro. Aqui está a ordem das operações que ocorrem quando a atividade A começa atividade B: 1. O método onpause() da atividade A é executado. 2. Os métodos oncreate(), onstart(), e onresume() de B são executados em seqüência. (Atividade B agora tem o foco do usuário.) 3. Então, se uma atividade não é mais visível na tela, a sua onstop() é executada. Esta seqüência previsível de callbacks do ciclo de vida permite-lhe gerir a transição de informações de uma atividade para outra. Por exemplo, se você deve escrever em um banco de dados quando a primeira atividade pára para que esta atividade pode lê-lo, então você deve escrever para o banco de dados durante onpause() em vez de durante onstop(). ANDROID, uma visão geral Anderson Duarte de Amorim 26

27 Fragmentos Um Fragment representa um comportamento ou uma parte da interface de usuário em uma Activity. Você pode combinar vários fragmentos em uma única atividade para construir uma interface multi-painel e reutilização de um fragmento de atividades múltiplas. Você pode pensar em um fragmento como uma seção modular de uma atividade, que tem seu próprio ciclo de vida, recebe os seus próprios eventos de entrada, e que você pode adicionar ou remover, enquanto a atividade está em execução. 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 são todos os fragmentos nele, e quando a atividade é destruída, assim são todos os fragmentos. No entanto, enquanto uma atividade está em execução (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 operação deste tipo de fragmento, você também 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 transação de fragmento que ocorreu. A volta da pilha permite que o usuário possa reverter uma transação (navegar para trás), 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 próprio layout de pontos de vista. Você pode inserir um fragmento em seu layout declarando o fragmento na atividade de distribuição de arquivos, como <fragment>, ou a partir de seu código de aplicativo, adicionando-o a um já existente ViewGroup. No entanto, um fragmento não é obrigado a fazer parte do esquema de atividade, você também pode utilizar um fragmento como um trabalhador invisível para a atividade. Filosofia de design Android apresenta fragmentos no Android 3.0 (API Level "Honeycomb"), principalmente para apoiar projetos mais dinâmicos e flexíveis de interface do usuário em telas grandes, como os Tablets. Como uma tela de tablet é muito maior do que a de um telefone, há mais espaço para combinar e trocar os componentes de interface do usuário. Fragmentos permitem tais projetos sem a necessidade de gerenciar mudanças ANDROID, uma visão geral Anderson Duarte de Amorim 27

28 complexas à hierarquia vista. Ao dividir o layout de uma atividade em fragmentos, você se torna capaz de modificar a aparência da atividade em tempo de execução e preservar essas mudanças em uma pilha de volta que é gerenciada pela atividade. Por exemplo, um aplicativo de notícias pode usar um fragmento para mostrar uma lista de artigos à esquerda e outro fragmento para mostrar um artigo à direita, então os fragmentos aparecem em uma atividade, lado a lado, e cada fragmento tem seu próprio conjunto do ciclo de vida, métodos callback e lidam com seus próprios eventos de entrada do usuário. Assim, em vez de usar uma atividade para selecionar um artigo e outra atividade para ler o artigo, o usuário pode selecionar um artigo e ler tudo dentro da mesma atividade, conforme ilustrado na figura 1. Figura 1. Um exemplo de como dois módulos de interface do usuário que normalmente são separados em duas atividades podem ser combinados em uma atividade, utilizando fragmentos. Um fragmento deve ser um componente modular e reutilizável em sua aplicação. Ou seja, porque o fragmento define o seu próprio layout e seu próprio comportamento, usando seu próprio ciclo de vida callbacks, você pode incluir um fragmento em múltiplas atividades. Isto é especialmente importante porque permite adaptar a sua experiência de usuário para diferentes tamanhos de tela. Por exemplo, você pode incluir vários fragmentos de uma atividade apenas quando o tamanho da tela é suficientemente grande, e, quando não é, lançar atividades distintas que utilizam diferentes fragmentos. Por exemplo, para continuar com o aplicativo de notícia, a aplicação 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), não há lugar suficiente para os dois fragmentos, de modo a Atividade A inclui somente o fragmento para a lista de artigos, e quando o usuário seleciona um artigo, ele começa a ANDROID, uma visão geral Anderson Duarte de Amorim 28

29 Atividade B, que inclui o fragmento para ler o artigo. Assim, a aplicação suporta os padrões de projeto sugerido na figura 1. Criando um fragmento Figura 2. O ciclo de vida de um fragmento (enquanto a sua atividade está em execução). ANDROID, uma visão geral Anderson Duarte de Amorim 29

30 Para criar um fragmento, você deve criar uma subclasse de Fragment (ou uma subclasse existente do mesmo). O código da classe Fragment se parece muito com uma Activity. Ele contém métodos de retorno semelhante a uma atividade, como oncreate(), onstart(), onpause(), e onstop(). Na verdade, se você está convertendo uma aplicação Android existentes para usar fragmentos, você pode simplesmente mover o código de métodos de retorno de sua atividade sobre os métodos de retorno de seus respectivos fragmentos. Normalmente, você deve implementar pelo menos os métodos do ciclo de vida a seguir: oncreate(): O sistema chama isso ao criar o fragmento. Dentro de sua aplicação, você deve inicializar os componentes essenciais do fragmento que pretende manter quando o fragmento é pausado ou parado, então retomado. oncreateview(): O sistema chama isso quando está na hora de extrair o fragmento de sua interface de usuário pela primeira vez. Para desenhar uma interface para o seu fragmento, você deve retornar um View a partir deste método que é a raiz do fragmento do seu layout. Você pode retornar nulo se o fragmento não fornece uma interface do usuário. onpause(): O sistema chama este método como o primeiro indício de que o usuário está saindo do fragmento (embora nem sempre significa que o fragmento está sendo destruído). Isso geralmente é onde você deve cometer quaisquer alterações que devem ser mantidas para além da sessão atual do usuário (porque o usuário pode não voltar). A maioria dos aplicativos devem implementar pelo menos estes três métodos para cada fragmento, mas existem vários métodos de retorno que você também deve usar para lidar com diferentes fases do ciclo de vida do fragmento. Todos os métodos de retorno do ciclo de vida são discutidos mais adiante, na seção sobre o manuseio do Ciclo de Vida do fragmento. Existem também algumas subclasses que você pode querer estender: DialogFragment Mostra uma janela flutuante. Usar essa classe para criar uma caixa de diálogo é uma boa alternativa para usar os métodos auxiliares de diálogo na Activity, porque você pode incorporar um fragmento de diálogo para a volta da pilha de fragmentos gerido pela atividade, permitindo que o usuário retorne a um fragmento rejeitado. ANDROID, uma visão geral Anderson Duarte de Amorim 30

31 ListFragment Exibe uma lista de itens que são gerenciados por um adaptador (como um SimpleCursorAdapter), semelhante ao ListActivity. Ele fornece diversos métodos 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 aplicação. Adicionando uma interface de usuário Um fragmento é normalmente usado como parte de uma atividade de interface de usuário e contribui com a sua própria disposição para a atividade. Para fornecer um layout de um fragmento, você deve implementar o oncreateview(), que o sistema Android chama quando é hora do fragmento ser desenhado no layout. A implementação deste método deve retornar um View que é a raiz do fragmento do seu layout. Nota: Se o fragmento é uma subclasse de ListFragment, a implementação padrão retorna um ListView de oncreateview(), então você não precisa implementá-lo. Para devolver um layout de oncreateview(), você pode retirá-lo a partir de um layout de recursos definidos em XML e o desenvolve. Para ajudá-lo a fazê-lo, oncreateview() fornece um LayoutInflater objeto. Por exemplo, aqui está uma subclasse de Fragment que carrega um layout a partir da example_fragment.xml: public static class ExampleFragment extends Fragment public View oncreateview(layoutinflater inflater, ViewGroup container, Bundle savedinstancestate) { // Inflate the layout for this fragment return inflater.inflate(r.layout.example_fragment, container, false); ANDROID, uma visão geral Anderson Duarte de Amorim 31

32 Criando um layout No exemplo acima, R.layout.example_fragment é uma referência a um recurso chamado layout example_fragment.xml salvo na aplicação dos recursos. O parâmetro passado para oncreateview() é o pai ViewGroup (da atividade do layout), em que o layout do fragmento será inserido. O parâmetro savedinstancestate é um Bundle que fornece dados sobre a instância anterior do fragmento, se o fragmento está sendo retomado. O método inflate() utiliza três argumentos: A identificação de recurso do layout que você deseja inserir. O ViewGroup ser o pai do layout já em utilização. Passando o container é importante para que o sistema possa aplicar os parâmetros de layout para o modo de exibição raiz do layout inflado, especificado pela posição do pai em que ele está indo. Um booleano que indica se o layout desenvolvido deverá ser anexado ao ViewGroup (segundo parâmetro) 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.) Adicionando um fragmento de uma atividade Normalmente, um fragmento contribui com uma parcela de UI para a atividade de acolhimento, que é incorporado como parte da hierarquia da visão da atividade de conjunto. Há duas maneiras com as quais você pode adicionar um fragmento para o layout de atividade: Declare o fragmento dentro atividade de layout do arquivo. Neste caso, você pode especificar propriedades de layout para o fragmento como se fosse uma exibição. Por exemplo, aqui está o arquivo de layout para uma atividade com dois fragmentos: ANDROID, uma visão geral Anderson Duarte de Amorim 32

33 <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android=" android:orientation="horizontal" android:layout_width="match_parent" android:layout_height="match_parent"> <fragment android:name="com.example.news.articlelistfragment" android:layout_weight="1" android:layout_width="0dp" android:layout_height="match_parent" /> <fragment android:name="com.example.news.articlereaderfragment" 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 transações, como removê-lo). Existem três formas para fornecer uma identificação de um fragmento: o o o Forneça o android:id com um ID único. Forneça o android:tag com uma string única. Se você não fornecer nenhum dos dois anteriores, o sistema utiliza a identificação de exibição de recipiente. Ou então, 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. ANDROID, uma visão geral Anderson Duarte de Amorim 33

34 Para fazer transações em sua atividade (como adicionar, remover ou substituir um fragmento), você deve usar as APIs do FragmentTransaction. Você pode obter uma instância de FragmentTransaction de sua Activity como esta: FragmentManager fragmentmanager = getfragmentmanager() FragmentTransaction fragmenttransaction = fragmentmanager.begintransaction(); Você pode então adicionar um fragmento ao usar o método add(), especificando o fragmento a adicionar e a visão 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 identificação do recurso, e o segundo parâmetro é o fragmento a acrescentar. Depois que você fizer as alterações com FragmentTransaction, você deve chamar commit() para que as alterações tenham efeito. Adicionando um fragmento sem uma interface de usuário (UI) Os exemplos acima mostram como adicionar um fragmento de sua atividade, a fim de fornecer uma interface do usuário. No entanto, você também pode usar um fragmento para fornecer um comportamento de fundo para a atividade sem a apresentação da interface do usuário. Para adicionar um fragmento sem uma interface de usuário, adicione o fragmento da atividade usando add(fragment, String) (fornecimento de uma única seqüência de "tag" para o fragmento, ao invés de um ID). Isso adiciona o fragmento, mas, porque não está associada a um ponto de vista do layout atividade, ele não recebe uma chamada para oncreateview(). Assim você não precisa implementar esse método. Fornecendo uma tag string para o fragmento não é estritamente para os fragmentos não- UI. Você também pode fornecer etiquetas de seqüência de fragmentos que possuem uma interface de usuário, mas se o fragmento não possui uma interface de usuário, a tag string é o único caminho para identificá-lo. Se você deseja obter o fragmento da atividade posterior, você precisa usar findfragmentbytag(). ANDROID, uma visão geral Anderson Duarte de Amorim 34

35 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 usuário no layout de atividade) ou findfragmentbytag() (para os fragmentos que fazem ou não uma interface do usuário). Retirar fragmentos da pilha, com popbackstack() (simulando um comando BACK pelo usuário). Registre-se um ouvinte de alteração de parte de trás da pilha, com addonbackstackchangedlistener(). Conforme demonstrado na seção anterior, você também pode usar FragmentManager para abrir uma FragmentTransaction, que lhe permite realizar transações, tais como adicionar e remover fragmentos. Executando transações com fragmento Uma das grandes novidades sobre o uso de fragmentos em sua atividade é a capacidade de adicionar, remover, substituir e realizar outras ações com eles, em resposta à interação do usuário. Cada conjunto de alterações que comprometem a atividade é chamado de transação e você pode executar um usando APIs em FragmentTransaction. Você também pode salvar cada transação na pilha gerenciada pela atividade, permitindo ao usuário navegar para trás através das mudanças no fragmento (semelhante ao navegar para trás por meio de atividades). Você pode adquirir uma instância de FragmentTransaction do FragmentManager como este: FragmentManager fragmentmanager = getfragmentmanager(); FragmentTransaction fragmenttransaction = fragmentmanager.begintransaction(); Cada transação é um conjunto de mudanças que se deseja realizar, ao mesmo tempo. Você pode configurar todas as alterações que pretendem efetuar uma operação ANDROID, uma visão geral Anderson Duarte de Amorim 35

36 determinada utilizando métodos como add(), remove(), e replace(). Em seguida, para aplicar a operação para a atividade, você deve chamar commit(). Antes de chamar commit(), no entanto, você pode querer chamar addtobackstack(), a fim de acrescentar a operação a uma volta da pilha de transações. Esta volta na pilha é gerida pela atividade e permite que ao usuário 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 contêiner de layout identificado pelo R.id.fragment_container ID. Ao chamar addtobackstack(), é salvado na pilha de volta a operação para que o usuário possa anular a operação e trazer de volta o fragmento anterior pressionando a tecla BACK. Se você adicionar várias alterações à operação (como um outro add() ou remove()) e chamar addtobackstack(), então todas as mudanças aplicadas antes de chamar commit() são adicionados à volta da pilha como uma única operação e a tecla BACK irá inverter-los todos juntos. A ordem na qual você adiciona as alterações em um FragmentTransaction não importa, exceto: Você deve chamar commit() por último. Se você está adicionando vários fragmentos para o mesmo recipiente, então a ordem em que você adicioná-los determina a ordem em que aparecem na hierarquia. ANDROID, uma visão geral Anderson Duarte de Amorim 36

37 Se você não chamar addtobackstack() quando você executar uma operação que remove um fragmento, em seguida, esse fragmento é destruído quando a transação for confirmada e o usuário não pode navegar de volta para ela. Considerando que, se você chamar addtobackstack() quando da remoção de um fragmento, o fragmento é interrompido e será retomado se o usuário navega de volta. Dica: Para cada transação, você pode aplicar uma animação de transição, chamando settransition() antes do commit(). Chamar commit() não executa a operação imediatamente. Em vez disso, ele agenda a execução no segmento da atividade de interface do usuário (a thread "main"), logo que o segmento for capaz de fazê-lo. Se necessário, no entanto, você pode chamar executependingtransactions() no seu segmento de interface do usuário para executar imediatamente as operações apresentadas por commit(). Fazer isso geralmente não é necessário a menos que a transação é uma dependência para o emprego em outros segmentos. Cuidado: você pode cometer uma transação usando commit() apenas antes da atividade salvar seu estado (quando o usuário deixa a atividade). Se a tentativa for cometer depois desse ponto, uma exceção será lançada. Isso ocorre porque o estado, após a confirmação, pode ser perdido se a atividade precisa ser restaurada. Para as situações em que não tem problema você perder o commit, use commitallowingstateloss(). Comunicando-se com a atividade Ainda que um Fragment seja implementado como um objeto que é independente de uma Activity e pode ser usado dentro de múltiplas atividades, uma determinada instância de um fragmento está diretamente ligada à atividade que o contém. Especificamente, o fragmento pode acessar a instância Activity com getactivity() e facilmente realizar tarefas como encontrar um ponto de vista do esquema de atuação: View listview = getactivity().findviewbyid(r.id.list); Da mesma forma, sua atividade pode chamar métodos no fragmento através da aquisição de uma referência para o Fragment de FragmentManager, usando findfragmentbyid() ou findfragmentbytag(). Por exemplo: ANDROID, uma visão geral Anderson Duarte de Amorim 37

38 ExampleFragment fragment = (ExampleFragment) getfragmentmanager().findfragmentbyid(r.id.example_fragment); Criar callbacks evento para a atividade Em alguns casos, você pode precisar de um fragmento de compartilhar eventos com a atividade. Uma boa maneira de fazer isso é definir uma interface de retorno no interior do fragmento e exigem que a atividade de acolhimento implemente-a. Quando a atividade recebe uma chamada através da interface, ela pode compartilhar a informação com outros fragmentos no layout conforme necessário. Por exemplo, se um aplicativo de notícias tem dois fragmentos de uma atividade e um mostra uma lista de artigos (fragmento A) e outro mostra um artigo (fragmento B), então um fragmento deve informar a atividade quando um item da lista é escolhido de modo que pode dizer ao fragmento B para exibir o artigo. Neste caso, a interface OnArticleSelectedListener é declarada dentro de um fragmento: public static class FragmentA extends ListFragment {... // Container Activity must implement this interface public interface OnArticleSelectedListener { public void onarticleselected(uri articleuri);... Em seguida, a atividade que hospeda o fragmento implementa a 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 método onattach() de retorno (que chama o sistema quando adicionando o fragmento para a atividade) instancia uma instância de OnArticleSelectedListener pelo casting da Activity que é passado para onattach(): public static class FragmentA extends ListFragment { OnArticleSelectedListener public void onattach(activity activity) { super.onattach(activity); try { mlistener = (OnArticleSelectedListener) activity; catch (ClassCastException e) { throw new ClassCastException(activity.toString() + " must implement OnArticleSelectedListener"); ANDROID, uma visão geral Anderson Duarte de Amorim 38

39 ... Se a atividade não tenha aplicado a interface, então o fragmento lança um ClassCastException. Em caso de sucesso, o membro mlistener mantém uma referência para a implementação da atividade de OnArticleSelectedListener, de modo que um fragmento pode compartilhar eventos com a atividade, chamando os métodos definidos pela interface OnArticleSelectedListener. Por exemplo, se um fragmento é uma extensão do ListFragment, cada vez que o usuário 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 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 parâmetro 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. Adicionando itens à barra de ação Seus fragmentos podem contribuir itens de menu para a atividade do menu de opções (e, conseqüentemente, a Barra de ação) pela execução oncreateoptionsmenu(). Para que esse método receba chamadas, no entanto, você deve chamar sethasoptionsmenu() durante oncreate(), para indicar que o fragmento gostaria de adicionar itens ao menu de opções (caso contrário, o fragmento não irá receber uma chamada para oncreateoptionsmenu()). Os itens que você adicionar ao menu de opções do fragmento são acrescentados aos itens de menu existente. O fragmento também recebe callbacks para onoptionsitemselected() quando um item de menu é selecionado. ANDROID, uma visão geral Anderson Duarte de Amorim 39

40 Você também pode registrar uma exibição em seu layout para fornecer um menu de contexto, chamando registerforcontextmenu(). Quando o usuário abre o menu de contexto, o fragmento recebe uma chamada para oncreatecontextmenu(). Quando o usuário 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 usuário seleciona um item de menu. Se a execução da atividade da chamada de retorno no item selecionado não lidar com o item selecionado, o evento é transmitido para retorno do fragmento. Isso é verdadeiro para o menu de opções e menus de contexto. Manuseio do ciclo de vida do fragmento Figura 3. O ciclo de vida afeta a atividade do ciclo de vida do fragmento. ANDROID, uma visão geral Anderson Duarte de Amorim 40

41 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 três estados: Retomado: O fragmento é visível na atividade de execução. Em pausa: Outra atividade está em primeiro plano e tem o foco, mas a atividade em que vive esse fragmento é ainda visível (a atividade do primeiro plano é parcialmente transparente ou não cobre a tela inteira). Parado: O fragmento não é visível. 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 informações do estado e membro são mantidas pelo sistema). No entanto, já não é visível para o usuário e serão mortos se a atividade é morta. Também 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 diferença mais significativa no ciclo de vida entre uma atividade e um fragmento é como são armazenados em suas respectivas pilhas. Uma atividade é colocada em uma pilha de volta das atividades que é gerido pelo sistema quando ela está parada, por padrão (para que o usuário 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 instância deve ser salva chamando addtobackstack() durante uma operação que remove o fragmento. Gerenciar o ciclo de vida do fragmento é muito semelhante à gestão do ciclo de vida da atividade. Assim, as mesmas práticas de gestão do ciclo de vida de atividade também se aplicam aos fragmentos. O que você também precisa entender, porém, é como a vida da atividade afeta a vida do fragmento. Coordenação com o ciclo de vida de atividade O ciclo de vida da atividade em que o fragmento de vida afeta diretamente o ciclo de vida do fragmento, da mesma forma que cada ciclo de retorno para a atividade resulta ANDROID, uma visão geral Anderson Duarte de Amorim 41

42 em um retorno semelhante para cada fragmento. Por exemplo, quando a atividade recebe onpause(), cada fragmento na atividade recebe onpause(). Fragmentos têm alguns retornos do ciclo de vida extra, no entanto, para lidar com uma interação única com a atividade, a fim de realizar ações como construir e destruir UI do fragmento. Estes métodos de callback adicionais são: onattach(): Chamado quando o fragmento foi associado com a atividade. oncreateview(): Chamado para criar a hierarquia de visão associada com o fragmento. onactivitycreated(): Chamado quando oncreate() da atividade foi retornado. ondestroyview(): Chamado quando a hierarquia de visão 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 métodos de retorno de um fragmento pode receber. Por exemplo, quando a atividade tenha recebido uma oncreate() de callback, um fragmento da atividade não 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 através do ciclo de vida da atividade. ANDROID, uma visão geral Anderson Duarte de Amorim 42

43 Loaders Loaders tornam fácil carregar os dados de forma assíncrona, em uma atividade ou um fragmento. Loaders têm estas características: Eles estão disponíveis para cada Activity e Fragment. Eles fornecem carga assíncrona de dados. Eles monitoram a fonte de seus dados e entregam novos resultados quando muda o conteúdo. Eles reconectam automaticamente o cursor do gestor passado, quando está sendo recriado após uma mudança de configuração. Assim, eles não precisam de voltar a consultar os seus dados. Resumo API Loader Existem várias classes e interfaces que podem ser envolvidos na utilização de carregadores em um aplicativo. Os resultados estão resumidos nesta tabela: LoaderManager Classe/Interface LoaderManager.LoaderCallbacks Descrição Uma classe abstrata associada a uma Activity ou Fragment para gerenciar uma ou mais instâncias Loader. Isso ajuda a gerenciar um pedido de execução de operações já em conjunto com o ciclo de vida de Activity ou Fragment, o uso mais comum deste é com um CursorLoader, no entanto as aplicações são livres para escrever seus próprios loaders para carregar outros tipos de dados. Há apenas um LoaderManager por atividade ou fragmento. Mas um LoaderManager pode ter vários carregadores. Uma interface de retorno de um cliente para interagir com o LoaderManager. Por exemplo, você usar o oncreateloader() para criar um carregador novo. ANDROID, uma visão geral Anderson Duarte de Amorim 43

44 Loader AsyncTaskLoader CursorLoader Uma classe abstrata que executa o carregamento assíncrono de dados. Esta é a classe base para um gestor. Você usaria normalmente CursorLoader, mas você pode implementar sua própria subclasse. Enquanto os carregadores estão ativos, eles devem acompanhar a fonte de seus dados e apresentar resultados novos quando alterar o conteúdo. Carregador abstrato que provê AsyncTansk para o trabalho. Uma subclasse de AsyncTaskLoader que consulta o ContentResolver e retorna um Cursor. Essa classe implementa o protocolo Loader de uma forma padrão para consultar cursores, com base em AsyncTaskLoader para realizar a consulta de cursor em uma discussão de fundo para que ele não bloqueie os aplicativo de interface do usuário. Utilizar este carregador é a melhor maneira de carregar os dados de forma assíncrona a partir de um ContentProvider, ao invés de realizar uma consulta gerida através do fragmento ou de APIs. As classes e interfaces na tabela acima são os componentes essenciais que você vai usar para implementar um carregador em sua aplicação. Você não vai precisar de todos eles para cada gestor, mas você sempre precisa de uma referência ao LoaderManager para inicializar um carregador e uma implementação de um Loader, como CursorLoader. As seções a seguir mostram como usar essas classes e interfaces em uma aplicação. Usando carregadores em um aplicativo Um aplicativo que usa carregadores normalmente inclui o seguinte: Uma Activity ou Fragment. Uma instância da LoaderManager. ANDROID, uma visão geral Anderson Duarte de Amorim 44

45 Um CursorLoader para carregar dados apoiado por uma ContentProvider. Alternativamente, você pode implementar sua própria subclasse de Loader ou AsyncTaskLoader para carregar dados de alguma outra fonte. Uma implementação para LoaderManager.LoaderCallbacks. Isto é onde você cria novos loaders e gerencia suas referências aos carregadores existentes. Uma maneira de mostrar o carregador de dados, como um SimpleCursorAdapter. Uma fonte de dados, como um ContentProvider, ao usar um CursorLoader. Iniciando um Loader O LoaderManager gerencia um ou mais instâncias Loader dentro de uma Activity ou Fragment. Há apenas um LoaderManager por atividade ou fragmento. Normalmente, você inicializa um Loader com o método oncreate() dentro da atividade ou método 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 método initloader() utiliza os seguintes parâmetros: Um ID exclusivo que identifica o carregador. Neste exemplo, a identificação é 0. Os argumentos opcionais para fornecer ao loader a construção (null neste exemplo). A execução 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 referência para si, this. ANDROID, uma visão geral Anderson Duarte de Amorim 45

46 A chamada ao initloader() assegura que um carregador é inicializado e ativo. Ele tem dois resultados possíveis: Se o carregador especificado pelo ID já existe, o último carregador criado é reutilizado. Se o carregador especificado pela ID não existir, initloader() aciona o método LoaderManager.LoaderCallbacks em oncreateloader(). Isto é onde você implementa o código para instanciar e retornar um carregador novo. Em ambos os casos, a aplicação 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()), então você deve estar preparado para isso acontecer. Observe que o método initloader() retorna o Loader que é criado, mas você não precisa capturar uma referência a ele. O LoaderManager gerencia a vida do carregador automaticamente. O LoaderManager inicia e pára de carregar quando necessário, e mantém o estado do carregador e do seu conteúdo 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 específicos. Reiniciando o Loader Quando você usa initloader(), como mostrado acima, ele usa um carregador existente com a identificação especificada, se houver. Se não houver, ele cria um. Mas às vezes você deseja descartar os dados antigos e começar de novo. Para descartar os dados antigos, use restartloader(). Por exemplo, essa implementação de SearchView.OnQueryTextListener reinicia o carregador quando o usuário muda de consulta. O loader precisa ser reiniciado para que ele possa usar a pesquisa de revisão de filtro para fazer uma nova consulta: ANDROID, uma visão geral Anderson Duarte de Amorim 46

47 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; Usando callbacks do LoaderManager LoaderManager.LoaderCallbacks é uma interface de callback que permite que um cliente interaja com o LoaderManager. Loaders, em especial o CursorLoader, são esperados para reter seus dados depois de ser interrompido. Isso permite aos aplicativos que mantenham seus dados através dos métodos onstop() e onstart() da atividade ou fragmento, de modo que quando os usuários retornam a um pedido, eles não tem que aguardar os dados para recarregarem. Você usa o método LoaderManager.LoaderCallbacks quando quer saber quando criar um carregador novo, e para dizer a aplicação quando é hora de parar de usar um gerenciador de dados. LoaderManager.LoaderCallbacks inclui os seguintes métodos: oncreateloader() - instancia e retorna um novo Loader para o ID dado. onloadfinished() - Chamado quando um loader criado anteriormente terminou sua carga. onloaderreset() - Chamado quando um loader criado anteriormente está sendo redefinido, tornando os dados disponíveis. Esses métodos são descritos em detalhes nas seções seguintes. oncreateloader Quando você tenta acessar um loader (por exemplo, através initloader()), ele verifica se o carregador especificado pelo ID existe. Se isso não ocorrer, ele aciona o método oncreateloader() do LoaderManager.LoaderCallbacks. Isto é onde você irá criar um carregador novo. Normalmente, esse será um CursorLoader, mas você pode implementar sua própria subclasse Loader. ANDROID, uma visão geral Anderson Duarte de Amorim 47

48 Neste exemplo, o oncreateloader() cria um método de retorno CursorLoader. Você deve construir o CursorLoader usando o método construtor, que exige um conjunto completo de informações necessárias para realizar uma consulta para o ContentProvider. Especificamente, é necessário: URI - A URI para o conteúdo para recuperar. projeção - uma lista de quais colunas retornar. Passando null irá retornar todas as colunas, que é ineficiente. seleção - Um filtro que declara que as linhas de retorno, formatado como uma cláusula WHERE SQL (excluindo o próprio WHERE). Passando null retornará todas as linhas para o URI especificado. selectionargs - Você pode incluir?s na seleção, que serão substituídas pelos valores da selectionargs, na ordem em que aparecem na seleção. Os valores serão vinculados como Strings. SortOrder - Como adquirir as linhas, formatado como uma cláusula ORDER BY de SQL (excluindo-se o ORDER BY). Passando null usará a ordem de classificação padrão, 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"); ANDROID, uma visão geral Anderson Duarte de Amorim 48

49 onloadfinished Este método é chamado quando um loader criado anteriormente terminou sua carga. Este método é garantido para ser chamado antes do lançamento do último dado que foi fornecido para este carregador. Neste ponto, você deve remover todo uso dos dados antigos (desde que será lançado em breve), mas não deve fazer a seu próprio lançamento dos dados desde o seu carregador é o dono e vai cuidar disso. O carregador vai lançar os dados, uma vez que conhece que o aplicativo não está mais usando. Por exemplo, se os dados são um cursor de um CursorLoader, você não deve chamar close() sobre ele mesmo. Se o cursor está sendo colocado em um CursorAdapter, você deve usar o método swapcursor() para que o antigo Cursor não 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 método é chamado quando um loader criado anteriormente está sendo redefinido, tornando os seus dados indisponíveis. Este retorno permite saber quando o dado está prestes a ser liberado assim você pode remover a referência a ele. Esta aplicação 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); ANDROID, uma visão geral Anderson Duarte de Amorim 49

50 Exemplo Como exemplo, aqui é a implementação completa de um Fragment que apresenta um ListView com os resultados de uma consulta contra o provedor de conteúdo contatos. Ele usa um CursorLoader para gerenciar a consulta do fornecedor. Para uma aplicação para acessar os contatos de um usuário, como mostrado neste exemplo, o manifesto deve incluir a permissão 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 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, 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) { ANDROID, uma visão geral Anderson Duarte de Amorim 50

51 // 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 public boolean onquerytextsubmit(string query) { // Don't care about this. return 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); ANDROID, uma visão geral Anderson Duarte de Amorim 51

52 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); ANDROID, uma visão geral Anderson Duarte de Amorim 52

53 Tarefas e pilha de execução Um aplicativo normalmente contém várias atividades. Cada atividade deve ser concebida em torno de um tipo específico de ação que o usuário pode realizar e pode iniciar outras atividades. Por exemplo, um aplicativo de pode ter uma atividade para mostrar uma lista de . Quando o usuário seleciona um , uma nova atividade é aberta para ver o . Uma atividade pode até iniciar atividades que existem em outras aplicações no dispositivo. Por exemplo, se sua aplicação quer enviar um , você pode definir a intenção de realizar um "send" e incluir alguns dados, tais como um endereço de e uma mensagem. Uma atividade de outra aplicação que se declara para lidar com este tipo de intenção, em seguida, é aberta. Neste caso, a intenção é enviar um , assim a atividade de "compor" começa (se múltiplas atividades apóiam a mesma intenção, então o sistema permite ao usuário selecionar qual usar). Quando o é enviado, sua atividade é retomada e parece como se a atividade de é parte do seu aplicativo. Mesmo que as atividades podem ser de diferentes aplicações, o Android mantém essa experiência do usuário uniforme, mantendo as duas atividades na mesma tarefa. Uma tarefa é um conjunto de atividades que os usuários interagem ao realizar um determinado trabalho. As atividades são organizadas em uma pilha (a "pilha de volta"), na ordem em que cada atividade é aberta. A tela inicial é o ponto de partida para a maioria das tarefas. Quando o usuário toca num ícone na tela do aplicativo (ou um atalho na tela inicial), essa tarefa vem para o primeiro plano. Se existe uma tarefa para a aplicação (o pedido não tenha sido usado recentemente), então uma nova tarefa é criada e a atividade "principal" abre como a atividade da raiz na pilha. Quando a atividade atual começa outra, a nova atividade é empurrada na parte superior da pilha e ganha foco. A atividade anterior permanece na pilha, mas está parada. Quando uma atividade termina, o sistema mantém o estado atual de sua interface de usuário. Quando o usuário pressiona a tecla BACK, a atividade atual é retirada da parte superior da pilha (a atividade é destruída) e a atividade anterior recomeça (o estado anterior de sua interface é restaurado). Atividades na pilha nunca são reorganizadas, só ANDROID, uma visão geral Anderson Duarte de Amorim 53

54 incluídas e excluídas da pilha - inseridas na pilha quando iniciado pela atividade atual e retiradas quando o usuário deixa-as usando a tecla BACK. Como tal, a parte de trás 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 representação de como cada nova atividade em uma tarefa adiciona um item na parte de trás da pilha. Quando o usuário pressiona a tecla BACK, a atividade atual é destruída e volta à atividade anterior. Se o usuário continuar a pressionar BACK, então cada atividade da pilha é retirada para revelar a anterior, até que o usuário retorna à tela inicial (ou de qualquer atividade que estava sendo executada quando a tarefa começou). Quando todas as atividades são removidas da pilha, a tarefa não existe mais. Figura 2. Duas tarefas tarefa estão no fundo, esperando para ser retomado, enquanto a Tarefa B recebe interação do usuário em primeiro plano. ANDROID, uma visão geral Anderson Duarte de Amorim 54

55 Figura 3. A única atividade é instanciada várias vezes. Uma tarefa é uma unidade coesa, que pode passar para o "background" quando os usuários começam uma nova tarefa ou vão para a tela inicial, através da tecla HOME. Enquanto no fundo, todas as atividades na tarefa estão 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 usuários possam continuar de onde pararam. Suponha, por exemplo, que a tarefa atual (Tarefa A) tenha três atividades em sua pilha e dois no âmbito da atividade corrente. O usuário pressiona a tecla HOME, e em seguida, inicia uma nova aplicação a partir do lançador de aplicação. Quando a tela inicial aparece, uma tarefa vai para o fundo. Quando inicia o novo aplicativo, o sistema inicia uma tarefa para a aplicação (Tarefa B) com sua própria pilha de atividades. Após a interação com esse aplicativo, o usuário volta para HOME novamente e seleciona o aplicativo que originalmente começou Tarefa A. Agora, a tarefa A vem para o primeiro plano - todas as três atividades em sua pilha estão intactas e as atividades no topo da pilha são retomadas. Neste ponto, o usuário também 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: Várias tarefas podem ser realizadas no fundo de uma vez. No entanto, se o usuário estiver executando muitas tarefas em segundo plano ao mesmo tempo, o sistema pode começar a destruir as atividades do fundo, a fim de recuperar a memória, fazendo com que os estados de atividade possam ser perdidos. Como as atividades na parte de trás da pilha nunca são reorganizadas, se seu aplicativo permite que usuários iniciem uma atividade específica de mais de uma atividade, uma ANDROID, uma visão geral Anderson Duarte de Amorim 55

56 nova instância daquela atividade é criada e colocada na pilha (ao invés de trazer qualquer instância anterior da atividade para o topo). Como tal, uma atividade em seu aplicativo pode ser instanciada várias vezes (mesmo de diferentes tarefas), como mostrado na figura 3. Como tal, se o usuário navega para trás usando a tecla BACK, cada instância da atividade é revelada na ordem em que foi aberta (cada um com seu estado próprio de UI). No entanto, você pode modificar esse comportamento se você não quer uma atividade a ser instanciada mais de uma vez. Para resumir o comportamento padrão de atividades e tarefas: Quando a atividade A começa atividade B, uma atividade é interrompida, mas o sistema mantém o seu estado (como a posição de rolagem e texto inseridos em formulários). Se o usuário pressiona a tecla de volta, enquanto na Atividade B, a atividade A continua com o seu estado restaurado. Quando o usuário deixa uma tarefa, pressionando a tecla HOME, a atividade em curso é interrompida e sua tarefa vai para o fundo. O sistema mantém o estado de cada atividade na tarefa. Se o usuário depois recomeça a tarefa de selecionar o ícone do lançador, que começou a tarefa, ela vem para o primeiro plano e retoma a atividade no topo da pilha. Se o usuário pressionar a tecla BACK, a atividade atual é removida da pilha e destruída. A atividade anterior na pilha é retomada. Quando uma atividade é destruída, o sistema não mantém atividade do Estado. As atividades podem ser instanciadas várias vezes, até mesmo de outras tarefas. Salvando estado de atividade Como discutido acima, o comportamento padrão do sistema preserva o estado de uma atividade quando está parada. Desta forma, quando os usuários navegam de volta para uma atividade anterior, sua interface parece do jeito que deixou. No entanto, você pode, e deve, de forma proativa manter o estado de suas atividades através de métodos de retorno, caso a atividade seja destruída e deve ser recriada. Quando o sistema pára uma de suas atividades (como quando inicia uma nova atividade ou movimenta as tarefas para o fundo), o sistema poderia destruir completamente essa atividade se ele precisa recuperar a memória do sistema. Quando isso acontece, as ANDROID, uma visão geral Anderson Duarte de Amorim 56

57 informações sobre o estado da atividade são perdidas. Se isso acontecer, o sistema ainda sabe que a atividade tem um lugar na parte de trás 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 usuário, você deve mantê-la de forma proativa através da aplicação do método 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 começaram sucessivamente na mesma tarefa e em uma pilha "last in, first out" - funciona muito bem para a maioria das aplicações e você não deve se preocupar em como suas atividades estão associadas a tarefas ou como eles existem na parte de trás 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ê começa uma atividade, que pretende apresentar uma instância existente da mesma (em vez de criar uma nova instância no topo da pilha de volta), ou, você quer a sua pilha para ser limpas de todas as activitiesstart, com exceção para a atividade de raiz quando o usuário deixa a tarefa. Você pode fazer essas coisas e mais, com atributos no manifesto da <activity> e com bandeiras de intenção que você passa para startactivity(). Neste sentido, os principais atributos de <activity> que você pode usar são: taskaffinity launchmode allowtaskreparenting cleartaskonlaunch alwaysretaintaskstate finishontasklaunch E as principais bandeiras de intenção você pode usar são: FLAG_ACTIVITY_NEW_TASK FLAG_ACTIVITY_CLEAR_TOP FLAG_ACTIVITY_SINGLE_TOP ANDROID, uma visão geral Anderson Duarte de Amorim 57

58 Atenção: A maioria dos aplicativos não deve interromper o comportamento padrão de atividades e tarefas. Se você determinar que seja necessário para a sua atividade modificar o comportamento padrão, tenha cuidado e não se esqueça de testar a usabilidade da atividade durante o lançamento 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 navegação que possam ser incompatíveis com o comportamento esperado do usuário. Definição de modos de lançamento Modos de Lançamento permitem que a definir como uma nova instância de uma atividade está associada à tarefa atual. Você pode definir diferentes modos de lançamento de duas maneiras: Usando o arquivo de manifesto o Quando você declarar uma atividade em seu arquivo de manifesto, você pode especificar como a atividade deve se associar com as tarefas quando é iniciada. Usando as opções de Intenções o Quando você chamar startactivity(), você pode incluir uma bandeira na Intent que declara como (ou se) a nova atividade deve associar com a tarefa atual. Como tal, se a atividade A inicia a atividade B, a atividade B pode definir no seu manifesto de como ele deve se associar com a tarefa atual (caso exista) e uma atividade também pode pedir o quanto a atividade B deve associar com a tarefa atual. Se ambas as atividades definem como a atividade B deve associar com uma tarefa, então a solicitação da atividade A (como definido na intenção) é honrada sobre o pedido da atividade B (como definido no seu manifesto). Nota: Alguns dos modos disponíveis no lançamento do manifesto não estão disponíveis como sinalizadores para uma intenção e, também, alguns modos de lançamento disponível como sinalizadores para a intenção pode não ser definida no manifesto. ANDROID, uma visão geral Anderson Duarte de Amorim 58

59 Usando o arquivo de manifesto Quando declarar uma atividade em seu arquivo de manifesto, você pode especificar como a atividade deve associar com uma tarefa usando o atributo launchmode do elemento <activity>. O atributo launchmode especifica uma instrução sobre como a atividade deve ser lançada em uma tarefa. Há quatro modos diferentes de lançamento você pode atribuir ao atributo launchmode: "standard" (o modo padrão) Padrão. O sistema cria uma nova instância da atividade na tarefa de que foi iniciado e mapeia a intenção a ele. A atividade pode ser instanciada várias vezes, cada instância pode pertencer a diferentes tarefas e uma tarefa pode ter múltiplas instâncias. "singletop" Se uma instância da atividade já existe no topo da tarefa atual, o sistema mapeia da estância através de uma chamada para o seu método onnewintent(), ao invés de criar uma nova instância da atividade. A atividade pode ser instanciada várias vezes, cada instância pode pertencer a diferentes tarefas e uma tarefa pode ter múltiplas instâncias (mas só se a atividade na parte superior da pilha de retorno não é uma instância existente da atividade). Por exemplo, suponha que uma tarefa que está na pilha consiste de uma atividade de raiz A com as atividades B, C e D no topo (a pilha é ABCD, D está no topo). A intenção chega para uma atividade do tipo D. Se D tem o modo de lançamento padrão "standard", uma nova instância da classe é lançada e se torna a pilha ABCDD. No entanto, se D está no modo de lançamento "singletop", a instância existente do D é entregue à intenção por meio onnewintent(), porque está no topo da pilha, a pilha continua ABCD. No entanto, se a intenção chega para uma atividade do tipo B, então, uma nova instância de B é adicionada à pilha, mesmo se o seu modo de lançamento é "singletop". Nota: Quando uma nova instância de uma atividade é criada, o usuário pode pressionar a tecla Back para retornar à atividade anterior. Mas quando uma ANDROID, uma visão geral Anderson Duarte de Amorim 59

60 instância existente de uma atividade lida com uma nova intenção, o usuário não poderá pressionar a tecla Voltar para retornar ao estado da atividade antes da nova intenção chegaram a onnewintent(). "singletask" O sistema cria uma nova tarefa e instancia a atividade na raiz da nova tarefa. No entanto, se uma instância da atividade já existe em uma tarefa separada, o sistema mapeia a intenção da instância existente através de um convite à sua onnewintent(), ao invés de criar uma nova instância. Apenas uma instância da atividade pode existir ao mesmo tempo. Nota: Embora a atividade começe em uma nova tarefa, a tecla BACK ainda retorna o usuário para a atividade anterior. "singleinstance". O mesmo que "singletask", exceto que o sistema não inicia qualquer outra atividade para a tarefa, segurando a instância. 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 própria tarefa, especificando o modo de lançamento singletask no elemento <activity>. Isto significa que, se o aplicativo emite a intenção de abrir o navegador do Android, a sua atividade não é colocada na mesma tarefa que a sua aplicação. Em vez disso, ou uma nova tarefa para o navegador é iniciada ou, se o navegador já tem uma tarefa em execução em segundo plano, essa tarefa é antecipada para lidar com a nova intenção. Independentemente de uma atividade ser iniciada em uma nova tarefa ou na mesma tarefa como a atividade que começou, a tecla BACK sempre leva o usuário para a atividade anterior. Entretanto, se você iniciar uma atividade de sua tarefa (Tarefa A), que especifica o modo de lançamento sendo singletask, então a atividade pode ter uma instancia em background que pertence a uma tarefa com a sua própria pilha de volta (Tarefa B). Neste caso, quando a tarefa B é antecipada para lidar com uma nova ANDROID, uma visão geral Anderson Duarte de Amorim 60

61 intenção, a tecla BACK navega de volta através das atividades na tarefa B antes de retornar à atividade do topo da tarefa A. Figura 4 visualiza este tipo de cenário. Figura 4. A representação de como uma atividade com o modo de lançar "singletask" é adicionada à pilha de volta. Se a atividade já faz parte de uma tarefa em segundo plano com a sua própria pilha de volta (Tarefa B), então toda a volta da pilha também 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 incluídas com a intenção de iniciar a sua atividade, como discutido na próxima seção. Usando as opções de intenções Ao iniciar uma atividade, você pode modificar o padrão de associação de uma atividade, incluindo na intenção que você entrega a startactivity(). As bandeiras que podem ser usadas para modificar o comportamento padrão são: FLAG_ACTIVITY_NEW_TASK Iniciar a atividade em uma nova tarefa. Se a tarefa já está em execução para a atividade que você está começando agora, essa tarefa é levada para o primeiro plano com o seu último estado restaurado e a atividade recebe a nova intenção em onnewintent(). ANDROID, uma visão geral Anderson Duarte de Amorim 61

62 Isso produz o mesmo comportamento que a "singletask", discutido na seção anterior. FLAG_ACTIVITY_SINGLE_TOP Se a atividade que está sendo iniciado é a atividade atual (no topo da pilha de volta), então a instância existente recebe uma chamada para onnewintent(), em vez de criar uma nova instância da atividade. Isso produz o mesmo comportamento que a "singletop", discutido na seção anterior. FLAG_ACTIVITY_CLEAR_TOP Se a atividade a ser iniciada já está em execução na tarefa atual, então ao invés de lançar uma nova instância da atividade, todas as outras atividades em cima dela são destruídas e essa intenção é entregue à instância retomada da atividade (agora no topo, através onnewintent()). Não há nenhum valor para o launchmode que produz esse comportamento. FLAG_ACTIVITY_CLEAR_TOP é mais freqüentemente utilizado em conjunto com FLAG_ACTIVITY_NEW_TASK. Quando usados em conjunto, essas bandeiras são uma maneira de localizar uma atividade existente em outra tarefa e colocá-la em uma posição onde ela pode responder à intenção. Nota: Se o modo de lançamento da atividade designada é "standard", ela também é removida da pilha e uma nova instância é lançada em seu lugar para lidar com o intuito de entrada. Isso porque uma nova instância é sempre criada para uma nova intenção, quando a modalidade de lançamento é "standard. Manipulação de afinidades A afinidade indica a qual tarefa uma atividade prefere pertencer. Por padrão, todas as atividades da mesma aplicação têm afinidade entre si. Então, por padrão, todas as atividades no mesmo aplicativo preferem estar na mesma tarefa. No entanto, você pode modificar o padrão de afinidade para uma atividade. Atividades definidas em diferentes aplicações podem compartilhar uma afinidade, ou atividades definidas no mesmo aplicativo podem ter diferentes afinidades de tarefas. ANDROID, uma visão geral Anderson Duarte de Amorim 62

63 Você pode modificar a afinidade de uma atividade específica com o atributo taskaffinity do <activity> elemento. O atributo taskaffinity tem um valor de seqüência, que deve ser exclusivo do nome do pacote padrão declarada no elemento <manifest>, porque o sistema usa esse nome para identificar a afinidade de tarefas padrão para o aplicativo. A afinidade entra em jogo em duas circunstâncias: Quando a intenção que inicia uma atividade contém FLAG_ACTIVITY_NEW_TASK. o Uma nova atividade é, por padrão, lançada na tarefa da atividade que chamou startactivity(). É empurrada para o topo da pilha do chamador. No entanto, se a intenção passada para startactivity() contém 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 não tem que ser. Se já existe uma tarefa, com a mesma afinidade que a nova atividade, a atividade é lançada nessa tarefa. Se não, ele começa uma nova tarefa. o Se este sinalizador faz uma atividade para iniciar uma nova tarefa e que o usuário pressiona a tecla HOME para deixá-lo, deve haver alguma maneira para o usuário navegar de volta para a tarefa. Algumas entidades (como o gerente de comunicação) sempre iniciam as atividades em uma tarefa externa, nunca como parte de si própria, assim eles sempre colocam FLAG_ACTIVITY_NEW_TASK nas intenções 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 usuário tenha uma maneira independente para voltar para a tarefa que começou como um ícone do lançador (a atividade radicular da tarefa tem uma intenção de filtro CATEGORY_LAUNCHER). Quando uma atividade tem seu atributo allowtaskreparenting definido como "true". Neste caso, a atividade pode se mover da tarefa que começou para a tarefa que tem afinidade, quando essa tarefa vem em primeiro plano. ANDROID, uma visão geral Anderson Duarte de Amorim 63

64 Por exemplo, suponha que uma atividade que relata as condições meteorológicas em cidades selecionadas é definida como parte de um aplicativo de viagens. Ele tem a mesma afinidade como outras atividades na mesma aplicação (a afinidade aplicativo padrão) 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 aplicação 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 "aplicação" do usuário, você provavelmente vai querer usar o atributo taskaffinity para atribuir diferentes afinidades para as atividades associadas a cada "pedido". Limpando a pilha de volta Se o usuário deixar uma tarefa por um longo tempo, o sistema cancela a tarefa de todas as atividades exceto a atividade de raiz. Quando o usuário retorna para a tarefa novamente, somente a atividade da raiz é restaurada. O sistema se comporta desta maneira, porque, depois de um longo período de tempo, os usuários provavelmente abandonaram o que faziam antes e estão retornando para a tarefa para começar algo novo. Há alguns atributos de atividade que você pode usar para modificar esse comportamento: alwaysretaintaskstate Se este atributo é definido como "true" na atividade de raiz de uma tarefa, o comportamento padrão que acabamos de descrever não acontece. A tarefa retém todas as atividades na sua pilha, mesmo após um longo período. cleartaskonlaunch Se este atributo é definido como "true" na atividade de raiz de uma tarefa, a pilha é limpa até a atividade de raiz sempre que o usuário deixa a tarefa e retorna a ela. Em outras palavras, é o oposto do alwaysretaintaskstate. O usuário sempre retorna para a tarefa em seu estado inicial, mesmo após estar deixando a tarefa por apenas um momento. ANDROID, uma visão geral Anderson Duarte de Amorim 64

65 finishontasklaunch Esse atributo é como cleartaskonlaunch, mas opera em uma única atividade, não em uma tarefa inteira. Ela também 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 sessão atual. Se o usuário sai e depois volta para a tarefa, ela não está mais presente. Iniciando uma tarefa Você pode configurar uma atividade como o ponto de entrada para uma tarefa, dandolhe um filtro com a intenção "android.intent.action.main" como a ação especificada e "android.intent.category.launcher" como a categoria especificada. Por exemplo: <activity... > <intent-filter... > <action android:name="android.intent.action.main" /> <category android:name="android.intent.category.launcher" /> </intent-filter>... </activity> A intenção do filtro deste tipo faz um ícone e uma legenda para a atividade a ser exibida na tela do menu, dando aos usuários uma maneira de iniciar a atividade e para retornar para a tarefa que ele cria em qualquer momento depois de ter sido lançado. Esta segunda habilidade é importante: o usuário deve ser capaz de deixar uma tarefa e, em seguida, voltar a ela mais tarde com o lançador de atividade. Por esta razão, os dois modos de iniciar as atividades que marcam o início, 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 intenção lança uma atividade "singletask", iniciando uma nova tarefa, e o usuário passa algum tempo a trabalhar nessa tarefa. O usuário pressiona o HOME. A tarefa agora é enviada para o fundo e fica invisível. Porque ele não é representado na tela do aplicativo, o usuário não tem como voltar para a tarefa. Para os casos onde você não deseja que o usuário seja capaz de retornar a uma atividade, defina o elemento de <activity>, finishontasklaunch, para "true". ANDROID, uma visão geral Anderson Duarte de Amorim 65

66 Serviços Um Service é um componente da aplicação que pode executar operações de longa duração em segundo plano e não oferece uma interface de usuário. Outro componente do aplicativo pode iniciar um serviço e vai continuar a rodar em segundo plano, mesmo se o usuário muda para outro aplicativo. Além disso, um componente pode se ligar a um serviço para interagir com ele e até mesmo realizar a comunicação entre processos (IPC). Por exemplo, um serviço pode lidar com as transações de rede, tocar música, executar I/O, ou interagir com um provedor de conteúdo, todos no fundo. Um serviço pode essencialmente de duas formas: Iniciado Um serviço é "iniciado" quando um componente da aplicação (como uma atividade) inicia-o chamando startservice(). Uma vez iniciado, o serviço pode ser executado em segundo plano por tempo indeterminado, mesmo se o componente que o começou é destruído. Normalmente, um serviço iniciado executa uma única operação e não retorna um resultado para o chamador. Por exemplo, pode fazer o download ou upload de um arquivo pela rede. Quando a operação é feita, o serviço deve parar. Ligado Um serviço é "ligado" quando um componente da aplicação liga-se a ele chamando bindservice(). Um serviço vinculado oferece uma interface clienteservidor que permite que os componentes interajam com o serviço, enviar pedidos, obter resultados, e até mesmo fazê-lo através de processos de comunicação entre processos (IPC). Um serviço vinculado só é executado enquanto outro componente de aplicação está vinculado a ele. Vários componentes podem ligar para o serviço de uma só vez, mas quando todos eles se desvinculam, o serviço é destruído. Embora essa documentação geralmente aborda esses dois tipos de serviços separadamente, o serviço pode funcionar nos dois sentidos, ele pode ser iniciado (para rodar indefinidamente) e também permitir a ligação. É simplesmente uma questão de ANDROID, uma visão geral Anderson Duarte de Amorim 66

67 saber se você implementa a dupla de métodos: onstartcommand() para permitir ao os componentes iniciá-lo e onbind() para permitir a ligação. Independentemente de sua aplicação ser iniciada, ligada, ou ambos, qualquer componente de aplicativo pode usar o serviço (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 serviço como privado, no arquivo de manifesto, e bloquear o acesso de outros aplicativos. Atenção: O serviço é executado no segmento principal de sua hospedagem, o serviço de processo não cria seu próprio segmento e não é executado em um processo separado (a menos que você especifique o contrário). Isso significa que, se o serviço vai fazer todo o trabalho intensivo da CPU ou o bloqueio de operações (como a reprodução de MP3 ou de rede), você deve criar um novo segmento dentro do serviço para fazer esse trabalho. Ao utilizar uma thread separada, você vai reduzir o risco de erros como aplicação não responde (ANR) e o thread principal do aplicativo pode permanecer dedicado à interação do usuário com suas atividades. O básico Você deve utilizar um serviço ou um thread? O serviço é simplesmente um componente que pode ser executado em segundo plano, mesmo quando o usuário não está interagindo com o aplicativo. Assim, você deve criar um serviço só para o que você precisa. Se você precisa realizar o trabalho fora de sua linha principal, mas apenas enquanto o usuário está interagindo com o aplicativo, então você deve, provavelmente, criar uma nova thread e não um serviço. Por exemplo, se você quiser tocar algumas músicas, mas apenas quando sua atividade está em execução, você pode criar uma lista de discussão em oncreate(), começar a utilizar em onstart(), e depois parar em onstop(). Também considere usar AsyncTask ou HandlerThread, em vez da tradicional classe Thread. Lembre-se que se você usar um serviço, ele ainda é executado no ANDROID, uma visão geral Anderson Duarte de Amorim 67

68 Para criar um serviço, thread principal do aplicativo por padrão, então você deve ainda você deve criar uma criar um novo segmento dentro do serviço se executa operações subclasse de Service (ou intensivas ou bloqueio. uma de suas subclasses existentes). Em sua execução, é necessário substituir alguns métodos de callback para lidar com aspectos essenciais do ciclo de vida do serviço e fornecer um mecanismo de componentes para ligar para o serviço, se for o caso. Os métodos mais importantes de retorno são: onstartcommand() O sistema chama este método quando outro componente, como uma atividade, solicita que o serviço seja iniciado, chamando startservice(). Uma vez que este método é executado, o serviço é iniciado e pode rodar em segundo plano por tempo indeterminado. Se você implementar essa, é sua a responsabilidade parar o serviço quando seu trabalho é feito, chamando stopself() ou stopservice(). (Se você apenas quiser fornecer ligação, você não precisa aplicar esse método.) onbind() O sistema chama este método quando um outro componente quer se vincular com o serviço (por exemplo, executar RPC), chamando bindservice(). Na implementação deste método, você deve fornecer uma interface que os clientes usam para se comunicar com o serviço, retornando um IBinder. Você sempre deve implementar este método, mas se você não quer permitir a ligação, então você deve retornar null. oncreate() O sistema chama este método quando o serviço é criado, para executar os procedimentos de configuração (antes de chamar qualquer onstartcommand() ou onbind()). Se o serviço já está em execução, este método não é chamado. ondestroy() O sistema chama este método quando o serviço não é mais usado e está sendo destruído. Seu serviço deve implementar isso para limpar quaisquer recursos, tais como threads, ouvintes registrados, receptores, etc. Esta é a última chamada que o serviço recebe. ANDROID, uma visão geral Anderson Duarte de Amorim 68

69 Se um componente inicia o serviço chamando startservice() (o que resulta em uma chamada para onstartcommand()), o serviço continua funcionando até que ele pare com stopself() ou outro componente deixa-o chamando stopservice(). Se um componente chama bindservice() para criar o serviço (e onstartcommand() não é chamado), o serviço funciona somente enquanto o componente está ligado a ele. Depois que o serviço é desvinculado de todos os clientes, o sistema se destrói. O sistema Android força a parada de um serviço somente quando estiver com pouca memória e deve recuperar os recursos do sistema para a atividade que tem o foco do usuário. Se o serviço está vinculado a uma atividade que tem o foco do usuário, então é menos provável de ser morto, e se o serviço é declarado a ser executado no primeiro plano (discutido mais tarde), então ele quase nunca vai ser morto. Caso contrário, se o serviço foi iniciado e está rodando há muito tempo, então o sistema irá baixar a sua posição na lista de tarefas em segundo plano ao longo do tempo e o serviço se tornará altamente suscetível a matar-se - se o serviço é iniciado, então você deve projetá-lo elegantemente para lançar reinício pelo sistema. Se o sistema mata o seu serviço, ele reinicia logo que os recursos se tornam novamente disponíveis (embora isso também dependa do valor que você retornar do onstartcommand(), como será discutido mais tarde). Declarando um serviço no manifesto Como atividades (e outros componentes), você deve declarar todos os serviços do arquivo de manifesto do aplicativo. Para declarar seu serviço, adicione um elemento <service> como um filho do elemento <application>. Por exemplo: <manifest... >... <application... > <service android:name=".exampleservice" />... </application> </manifest> Existem outros atributos que você pode incluir no <service> para definir propriedades, como as permissões necessárias para iniciar o serviço e o processo em que o serviço deve ser executado. ANDROID, uma visão geral Anderson Duarte de Amorim 69

70 Assim como uma atividade, um serviço pode definir filtros que permitem a intenção de outros componentes para invocar o serviço utilizando as intenções implícitas. Ao declarar a intenção de filtros, componentes de qualquer aplicativo instalados no aparelho do usuário podem, potencialmente, iniciar o seu serviço se o serviço de declarar a intenção de filtro que corresponde à intenção outro aplicativo passa a startservice(). Se você planeja usar o seu serviço apenas localmente (as outras aplicações não o usam), então você não precisa (e não deve) prestar quaisquer filtros de intenção. Sem qualquer intenção de filtros, você deve iniciar o serviço usando uma intenção explícita dos nomes de classe do serviço. Além disso, você pode garantir que seu serviço seja privado, basta somente você incluir o atributo android:exported e defini-lo como "false". É eficaz mesmo se o serviço fornece filtros de intenção. Criando um serviço iniciado Um serviço iniciado é um de outro componente que se inicia chamando startservice(), resultando em uma chamada para o método onstartcommand() do serviço. Quando um serviço é iniciado, ele tem um ciclo de vida que é independente do componente que começou e o serviço pode funcionar em segundo plano por tempo indeterminado, mesmo se o componente que o começou é destruído. Como tal, o serviço deve parar quando seu trabalho é feito chamando stopself(), ou outro componente pode pará-lo, chamando stopservice(). Segmentação Android 1.6 ou inferior Se você estiver construindo uma aplicação para o Android 1.6 ou inferior, você precisa implementar onstart(), em vez de onstartcommand() (no Android 2.0, onstart() foi depreciado em favor do onstartcommand()). Para obter mais informações sobre a prestação de compatibilidade com versões do Android superiores a 2.0, consulte a documentação de onstartcommand(). Um componente de aplicação, como uma atividade, pode iniciar o serviço chamando startservice() e passando uma Intent que especifica o serviço e inclui todos os dados para o serviço deve usar. O serviço recebe essa Intent no método onstartcommand(). ANDROID, uma visão geral Anderson Duarte de Amorim 70

71 Por exemplo, suponha que uma atividade precisa salvar alguns dados para um banco de dados on-line. A atividade pode iniciar um serviço e entregá-lo para guardar os dados, passando a intenção de startservice(). O serviço recebe a intenção em onstartcommand(), se conecta à Internet e executa a operação de banco de dados. Quando a transação estiver concluída, o serviço o pára e ele é destruído. Atenção: Um serviço executa no mesmo processo do aplicativo no qual ele é declarado e na thread principal da aplicação, por padrão. Assim, se o serviço realiza intensivo ou o bloqueio de operações, enquanto o usuário interage com uma atividade a partir do mesmo aplicativo, o serviço vai abrandar o desempenho da atividade. Para evitar afetar o desempenho do aplicativo, você deve iniciar uma nova thread dentro do serviço. Tradicionalmente, há duas classes que você pode estender para criar um serviço iniciado: Service Esta é a classe base para todos os serviços. Quando você estender essa classe, é importante que você crie um novo segmento para fazer todo o trabalho, pois o serviço usa a linha principal do aplicativo, por padrão, o que poderia diminuir o desempenho de qualquer atividade de sua aplicação que está rodando. IntentService Esta é uma subclasse de Service que utiliza um thread de trabalho para lidar com todos os pedidos de início, um de cada vez. Esta é a melhor opção se você não exigir que o serviço de lidar com várias solicitações em simultâneo. Tudo que você precisa fazer é implementar onhandleintent(), que recebe a intenção de cada solicitação de início para que você possa fazer o trabalho de fundo. Estendendo a classe IntentService Porque a maioria dos serviços iniciados não precisam lidar com múltiplas solicitações ao mesmo tempo (que pode realmente ser um cenário perigoso de multi-threading), é melhor se você implementar o seu serviço usando o IntentService. O IntentService faz o seguinte: ANDROID, uma visão geral Anderson Duarte de Amorim 71

72 Cria um thread de trabalho padrão que executa todas as intenções entregues ao onstartcommand() em separado do thread principal de sua aplicação. Cria uma fila de trabalho que passa uma intenção de cada vez para seu onhandleintent() de execução, para que não tenha que se preocupar com multithreading. Interrompe o serviço, após todos os pedidos de início ter sido manipulados, então você nunca tem que chamar stopself(). Fornece implementação padrão de onbind() que retorna nulo. Fornece uma implementação padrão de onstartcommand() que envia a intenção da fila de trabalho e, em seguida, à onhandleintent() de execução. Tudo isto se acrescenta ao fato de que tudo que você precisa fazer é implementar onhandleintent() para fazer o trabalho fornecido pelo cliente. (Embora, você também precisa fornecer um construtor pequeno para o serviço). Aqui está um exemplo de implementação 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. 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) { ANDROID, uma visão geral Anderson Duarte de Amorim 72

73 Isso é tudo que você precisa: um construtor e uma implementação de onhandleintent(). Se você decidir também substituir os métodos de retorno de chamada, tais como oncreate(), onstartcommand(), ou ondestroy(), não se esqueça de chamar a implementação de super, de modo que o IntentService possa lidar corretamente com a vida do thread. Por exemplo, onstartcommand() deve retornar a implementação padrão (que é como a intenção é entregue a public int onstartcommand(intent intent, int flags, int startid) { Toast.makeText(this, "service starting", Toast.LENGTH_SHORT).show(); return super.onstartcommand(intent,flags,startid); Além do onhandleintent(), o único método a partir do qual você não precisa chamar o super classe é onbind() (mas você só precisa implementar caso o serviço permita a ligação). Estendendo a classe de serviço Como você viu na seção anterior, utilizar IntentService faz sua implementação de um serviço iniciado muito simples. Se, no entanto, é necessário o seu serviço executar multi-threading (em vez de processar pedidos através da fila de trabalho), então você pode estender a classe Service para lidar com cada intenção. Para efeito de comparação, o código de exemplo a seguir é uma implementação do Service que executa o mesmo trabalho exatamente como o exemplo acima usando IntentService. Ou seja, para cada solicitação, ele usa um thread para executar o trabalho e os processos de um único pedido por vez. public class HelloService extends Service { private Looper mservicelooper; private ServiceHandler mservicehandler; // Handler that receives messages from the thread private final class ServiceHandler extends Handler { public ServiceHandler(Looper looper) { ANDROID, uma visão geral Anderson Duarte de Amorim 73

74 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 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 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 public IBinder onbind(intent intent) { // We don't provide binding, so return null return null; ANDROID, uma visão geral Anderson Duarte de Amorim 74

75 @Override public void ondestroy() { Toast.makeText(this, "service done", Toast.LENGTH_SHORT).show(); ANDROID, uma visão geral Anderson Duarte de Amorim 75

76 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 várias solicitações em simultâneo. Isso não é o que este exemplo faz, mas se é isso que você quer então você pode criar um novo tópico para cada pedido e executá-los imediatamente (em vez de aguardar a solicitação anterior para terminar). Observe que o método onstartcommand() deve retornar um inteiro. O inteiro é um valor que descreve como o sistema deve continuar o serviço a partir do evento em que o sistema o mata (como discutido acima, a implementação padrão 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 serviço após onstartcommand() retornar, não recria o serviço, salvo se houver pendência de intenções para entregar. Esta é a opção mais segura para evitar a execução de seu serviço quando não for necessário e quando a sua aplicação pode simplesmente reiniciar os trabalhos inacabados. START_STICKY Se o sistema mata o serviço após onstartcommand() retornar, recria o serviço e chamar onstartcommand(), mas não entrega novamente a última intenção. Em vez disso, o sistema chama onstartcommand() com uma intenção nula, a menos que houver pendência de intenções para iniciar o serviço, nesse caso, os propósitos são entregues. Isso é adequado para media players (ou afins) que não estão executando comandos, mas rodam indefinidamente à espera de uma interação. START_REDELIVER_INTENT Se o sistema mata o serviço após onstartcommand() retornar, recria o serviço e chama onstartcommand() com a última intenção que foi entregue para o serviço. Quaisquer intenções pendentes são entregues em troca. Isso é adequado para os serviços que estão ativamente realizando um trabalho que deve ser imediatamente reiniciado, como baixar um arquivo. ANDROID, uma visão geral Anderson Duarte de Amorim 76

77 Iniciando um serviço Você pode iniciar um serviço de uma atividade ou componente de outro aplicativo por meio de um Intent (especificando o serviço para iniciar) para startservice(). O sistema Android chama o método onstartcommand() do serviço do e passa a Intent. (Você nunca deve chamar onstartcommand() diretamente.) Por exemplo, uma atividade pode iniciar o serviço de exemplo na seção anterior (HelloSevice) com a intenção explícita com startservice(): Intent intent = new Intent(this, HelloService.class); startservice(intent); O startservice() retorna imediatamente e o sistema Android chama o método onstartcommand() do serviço. Se o serviço não estiver sendo executado, o sistema chama primeiro oncreate(), em seguida, chama onstartcommand(). Se o serviço não é provê ligação, a intenção entregue com startservice() é o único modo de comunicação entre o componente de aplicação e o serviço. No entanto, se você quiser o serviço para enviar um resultado de volta, o cliente que inicia o serviço pode criar uma PendingIntent para uma transmissão (com getbroadcast()) e entregá-lo ao serviço da Intent que inicia o serviço. O serviço pode então usar a transmissão para fornecer um resultado. Vários pedidos para iniciar o resultado do serviço em várias correspondências chamam o onstartcommand() do serviço. No entanto, apenas um pedido para parar o serviço (com stopself() ou stopservice()) é necessário. Parando um serviço O serviço iniciado deve gerenciar seu próprio ciclo de vida. Ou seja, o sistema não para ou destrói o serviço a menos que ele deva recuperar a memória do sistema e o serviço continua a funcionar após onstartcommand() retornar. Assim, o serviço deve parar, chamando stopself() ou outro componente pode pará-lo, chamando stopservice(). Uma vez solicitado a parar com stopself() ou stopservice(), o sistema destrói o serviço o mais rapidamente possível. No entanto, se o serviço trabalha com pedidos múltiplos para onstartcommand() ao mesmo tempo, então você não deve interromper o serviço quando tiver terminado o ANDROID, uma visão geral Anderson Duarte de Amorim 77

78 processamento de um pedido inicial, porque você pode ter uma vez recebido um pedido novo começo (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 serviço é sempre baseado no início 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. Então, se o serviço recebeu um pedido antes de você fosse capaz de chamar stopself(int), o ID não corresponderá e o serviço não vai parar. Atenção: É importante que o aplicativo pare seus serviços quando o trabalho está pronto, para evitar o desperdício de recursos do sistema e consumo de bateria. Se necessário, outros componentes podem interromper o serviço pela chamada de stopservice(). Mesmo se você permitir chamada ao serviço, você deve sempre parar o serviço a si mesmo se ele já recebeu uma chamada para onstartcommand(). Criando um serviço vinculado Um serviço vinculado é aquele que permite que os componentes do aplicativo se vinculem a ele chamando bindservice() para criar uma ligação de longa data (e geralmente não permitem aos componentes iniciá-lo, chamando startservice()). Você deve criar um serviço ligado quando você quiser interagir com o serviço de atividades e outros componentes em seu aplicativo ou para expor algumas das funcionalidades do aplicativo para outros aplicativos, através da comunicação entre processos (IPC). Para criar um serviço vinculado, você deve implementar o método onbind()para retornar um IBinder que define a interface de comunicação com o serviço. Outros componentes do aplicativo pode então chamar bindservice() para recuperar a interface e começar a chamar os métodos do serviço. O serviço só vive para servir o componente de aplicação que é ligado a ele, então quando não há componentes vinculados ao serviço, o sistema o destrói (você não precisa parar um serviço ligado no jeito que você tem quando o serviço é iniciado através onstartcommand()). Para criar um serviço vinculado, a primeira coisa que você deve fazer é definir a interface que especifica como um cliente pode se comunicar com o serviço. Essa interface entre o serviço e o cliente deve ser uma implementação de IBinder e é o que o ANDROID, uma visão geral Anderson Duarte de Amorim 78

79 seu serviço deve retornar a partir do método de retorno onbind(). Uma vez que o cliente recebe a IBinder, pode começar a interagir com o serviço por meio dessa interface. Vários clientes podem se ligar ao serviço de uma só vez. Quando um cliente concluiu a interação com o serviço, ele chama unbindservice() para se desvincular. Uma vez que não há clientes vinculados ao serviço, o sistema destrói o serviço. Enviando notificações para o usuário Uma vez em execução, um serviço pode notificar o usuário de eventos usando notificações toast ou notificações da barra de status. Uma notificação toast é uma mensagem que aparece na superfície da janela atual por um momento e depois desaparece, enquanto uma notificação de barra de status fornece um ícone na barra de status com uma mensagem, que o usuário pode selecionar a fim de tomar uma ação (como iniciar uma atividade). Normalmente, uma notificação de barra de status é a melhor técnica quando algum trabalho de fundo tenha sido concluído (como um download do arquivo completo) e agora o usuário pode agir sobre ela. Quando o usuário seleciona a notificação a partir da visão expandida, a notificação pode iniciar uma atividade (tal como para visualizar o arquivo baixado). Executando um serviço em primeiro plano Um serviço de primeiro plano é um serviço que é considerado como sendo algo que o usuário esteja atento e, portanto, não é um candidato para o sistema matar quando com pouca memória. Um serviço de primeiro plano deve prever uma notificação na barra de status, que é colocado abaixo da posição "em curso", o que significa que a notificação não pode ser dispensada a menos que o serviço ou está parado ou foi removido do primeiro plano. Por exemplo, um leitor de música que toca a partir de um serviço, deve ser definido para ser executado em primeiro plano, porque o usuário está explicitamente consciente do seu funcionamento. A notificação na barra de status pode indicar a música atual e permitir que o usuário inicie uma atividade para interagir com o leitor de música. ANDROID, uma visão geral Anderson Duarte de Amorim 79

80 Para solicitar que o serviço seja executado em primeiro plano, chame startforeground(). Este método tem dois parâmetros: um número inteiro que identifica a notificação e a notificação 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 serviço do primeiro plano, chama-se stopforeground(). Este método tem um valor booleano, indicando se deseja remover a notificação de barra de status também. Este método não para o serviço. No entanto, se você parar o serviço enquanto ele ainda está executando em primeiro plano a notificação também é removida. Nota: Os métodos startforeground() e stopforeground() foram introduzidos no Android 2.0 (API Nível 5). Gerenciando ciclo de vida de um serviço O ciclo de vida de um serviço é muito mais simples do que o de uma atividade. No entanto, é ainda mais importante que você preste atenção à forma como o serviço é criado e destruído, porque um serviço pode ser executado em segundo plano, sem que o utilizador perceba. O ciclo de vida do serviço desde quando ele é criado até quando ele é destruído - pode seguir dois caminhos diferentes: O serviço começou O serviço é criado quando um outro componente chama startservice(). O serviço é executado indefinidamente e, em seguida, deve ser parado chamando stopself(). Outro componente também pode interromper o serviço pela chamada de stopservice(). Quando o serviço for interrompido, o sistema o destrói. Um serviço vinculado O serviço é criado quando um outro componente (um cliente) chama bindservice(). O cliente se comunica com o serviço através de uma interface IBinder. O cliente ANDROID, uma visão geral Anderson Duarte de Amorim 80

81 pode fechar a conexão chamando unbindservice(). Vários clientes podem chamar o mesmo serviço e quando todos eles desvincularem-se, o sistema destrói o serviço. (O serviço não precisa parar si mesmo). Estes dois caminhos não são totalmente distintos. Ou seja, você pode chamar um serviço que já foi iniciado com startservice(). Por exemplo, um serviço de música de fundo pode ser iniciado chamando startservice() com uma Intent que identifica a música a tocar. Mais tarde, possivelmente quando o usuário deseja exercer algum controle sobre o player ou obter informações sobre a música atual, uma atividade pode se ligar ao serviço chamando bindservice(). Em casos como este, stopservice() ou stopself() não chegam a parar o serviço até que todos os clientes se desacoplem. Aplicando o ciclo de vida dos callbacks Como uma atividade, um ciclo de vida do serviço tem métodos de retorno que você pode implementar para monitorar as mudanças no estado do serviço e realizar o trabalho no momento oportuno. O seguinte esqueleto de serviço demonstra todos os métodos de ciclo de vida: Figura 2. O ciclo de vida do serviço. O diagrama à esquerda mostra o ciclo de vida quando o serviço é criado com startservice() e o diagrama da direita mostra o ciclo de vida quando o serviço é criado com bindservice(). ANDROID, uma visão geral Anderson Duarte de Amorim 81

82 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 public void oncreate() { // The service is being public int onstartcommand(intent intent, int flags, int startid) { // The service is starting, due to a call to startservice() return public IBinder onbind(intent intent) { // A client is binding to the service with bindservice() return public boolean onunbind(intent intent) { // All clients have unbound with unbindservice() return public void onrebind(intent intent) { // A client is binding to the service with bindservice(), // after onunbind() has already been public void ondestroy() { // The service is no longer used and is being destroyed Nota: Ao contrário métodos de retorno do ciclo de vida da atividade, você não é obrigado a chamar a implementação da superclasse dos métodos de callback. Ao implementar esses métodos, você pode controlar dois loops aninhados do ciclo de vida do serviço: A vida inteira de um serviço acontece entre o momento oncreate() ser chamado e o tempo ondestroy() retornado. Como uma atividade, um serviço tem a sua configuração inicial em oncreate() e libera todos os recursos remanescentes em ondestroy(). Por exemplo, um serviço de reprodução de música pode criar o segmento onde a música será tocada em oncreate(), então para a thread em ondestroy(). ANDROID, uma visão geral Anderson Duarte de Amorim 82

83 Os métodos oncreate() e ondestroy() são chamados para todos os serviços, sejam eles criados por startservice() ou bindservice(). A vida ativa de um serviço começa com uma chamada de um onstartcommand() ou onbind(). Cada método entrega a Intent que foi passado tanto startservice() quanto bindservice(), respectivamente. Se o serviço for iniciado, o tempo de vida ativa termina ao mesmo tempo em que toda a vida termina (o serviço continua ativo mesmo após onstartcommand() retornar). Se o serviço está vinculado, a vida ativa termina quando onunbind() retorna. Nota: Apesar de um serviço iniciado ser interrompido por uma chamada para uma stopself() ou stopservice(), não há um retorno para o respectivo serviço (não há onstop() de callback). Então, a menos que o serviço esteja vinculado a um cliente, o sistema destrói quando o serviço for interrompido, ondestroy() é o retorno recebido apenas. A figura 2 ilustra os métodos típicos de retorno de um serviço. Embora a figura separa os serviços que são criados por startservice() daquelas criadas pelos bindservice(), tenha em mente que qualquer serviço, não importa como ele é iniciado, pode potencialmente permitir que os clientes chamem-no. Assim, um serviço que foi inicialmente iniciado com onstartcommand() (por um cliente chamando startservice() ) pode ainda receber uma chamada para onbind() (quando um cliente solicita bindservice()). ANDROID, uma visão geral Anderson Duarte de Amorim 83

84 Serviços vinculados Um serviço vinculado é o servidor em uma interface cliente-servidor. O serviço permite que os componentes ligados (como em atividades) vinculem-se ao serviço, enviem pedidos, recebam respostas, e até mesmo realizem a comunicação entre processos (IPC). Um serviço ligado normalmente vive apenas enquanto ela serve a outro componente da aplicação e não é executado em segundo plano por tempo indeterminado. O básico Um serviço ligado é uma implementação da classe Service que permite que outros aplicativos se liguem e interajam com ele. Para fornecer ligação para um serviço, você deve implementar o onbind() método de retorno. Esse método retorna um objeto IBinder que define a interface de programação que os clientes podem usar para interagir com o serviço. Um cliente pode se ligar ao serviço chamando bindservice(). Quando isso acontecer, ele deve fornecer uma implementação de ServiceConnection, que monitora a conexão com o serviço. O método bindservice() retorna imediatamente sem um valor, Vinculação a um serviço iniciado Conforme discutido no capítulo sobre Serviço, você pode criar um serviço que seja iniciado e vinculado. Ou seja, o serviço pode ser iniciado chamando startservice(), que permite que o serviço seja executado indefinidamente, e também permite que um cliente se amarre ao serviço chamando bindservice(). Se você permitir que seu serviço seja iniciado e ligado, em seguida, quando o serviço for iniciado, o sistema não destruirá o serviço quando todos os clientes desacoplarem. Em vez disso, você deve explicitamente parar o serviço, chamando stopself() ou stopservice(). Embora você geralmente deva implementar onbind() ou onstartcommand(), às vezes é necessário aplicar a ambos. Por exemplo, um tocador de música pode ser útil para permitir o serviço a ser executado indefinidamente e também fornecer vínculo. Desta forma, uma atividade pode iniciar o serviço para jogar alguma música e a música continua a tocar mesmo se o usuário sai do aplicativo. Então, quando o usuário retorna para a aplicação, a atividade pode ligar para o serviço para recuperar o controle da reprodução. Certifique-se de ler a seção sobre Gerenciamento do ciclo de vida de um serviço vinculado, para obter mais informações sobre o ciclo de vida do serviço, quando for feita adição de ligação para um serviço iniciado. ANDROID, uma visão geral Anderson Duarte de Amorim 84

85 mas quando o sistema Android cria a conexão entre o cliente e o serviço, ele chama onserviceconnected() na ServiceConnection para entregar o IBinder que o cliente pode usar para se comunicar com o serviço. Vários clientes podem se conectar ao serviço de uma só vez. No entanto, o sistema chama o método onbind() do serviço 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 serviço, o sistema destrói o serviço (a menos que o serviço também foi iniciado por startservice() ). Quando você implementar o seu serviço vinculado, a parte mais importante é definir a interface que o seu método callback onbind() retorna. Existem algumas maneiras diferentes que você pode definir o seu serviço da interface IBinder e a seção a seguir discute cada técnica. Criando um serviço ligado Ao criar um serviço que oferece ligação, você deve fornecer um IBinder que fornece a interface de programação que os clientes podem utilizar para interagir com o serviço. Existem três maneiras com as quais você pode definir a interface: Estendendo a classe Binder Se o serviço é privado para sua própria aplicação e é executado no mesmo processo do cliente (o que é comum), você deve criar a sua interface extendendo o Binder e retornando uma instância a partir onbind(). O cliente recebe o Binder e pode usá-lo para acessar diretamente os métodos públicos disponíveis em qualquer um dos Binder implementados ou até mesmo o Service. Esta é a técnica preferida quando o serviço é apenas um trabalhador de fundo para o seu próprio aplicativo. A única razão em que você não deve criar a interface desta maneira é porque o serviço é utilizado por outras aplicações ou através de processos separados. ANDROID, uma visão geral Anderson Duarte de Amorim 85

86 Usando um Messenger Se você precisa de sua interface para trabalhar em processos diferentes, você pode criar uma interface para o serviço com um Messenger. Desta forma, o serviço 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 serviço usando mensagem de objetos. Além disso, o cliente pode definir um Messenger próprio para que o serviço possa enviar mensagens de volta. Esta é a maneira mais simples para realizar a comunicação entre processos (IPC), porque o Messenger enfilera todas as solicitações em um único segmento para que você não tenha que projetar seu serviço 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 através de processos para executar IPC. A técnica anterior, usando um Messenger, é realmente baseado em AIDL como a sua estrutura subjacente. Como mencionado acima, o Messenger cria uma fila de todas as solicitações do cliente em um único segmento, para que o serviço receba solicitações de um de cada vez. Se, no entanto, você quiser que o seu serviço lide com múltiplas solicitações ao mesmo tempo, então você pode usar AIDL diretamente. Neste caso, o serviço deve ser capaz de multi-threading e ser construído thread-safe. Para usar AIDL diretamente, você deve criar uma arquivo.aidl que define a interface de programação. 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 serviço. Nota: A maioria dos aplicativos não devem usar AIDL para criar um serviço ligado, porque ele pode exigir recursos de multithreading e pode resultar em uma implementação mais complicada. Como tal, AIDL não é adequado para a maioria das aplicações e este documento não explica como usá-lo para seu serviço. ANDROID, uma visão geral Anderson Duarte de Amorim 86

87 Estendendo a classe Binder Se o serviço é usado somente pela aplicação local e não precisa trabalhar em todos os processos, então você pode implementar seu próprio Binder que fornece o acesso direto do cliente com os métodos públicos no serviço. Nota: Isto só funciona se o cliente e o serviço estão no mesmo aplicativo e processo, o que é mais comum. Por exemplo, isso iria funcionar bem para um aplicativo de música que tem o efeito de vincular uma atividade a seu próprio serviço de música que está tocando no fundo. Veja como configurá-lo: 1. Em seu serviço, criar uma instância do Binder que: o o o contém métodos públicos que o cliente pode chamar retorna o atual Service, que tem métodos públicos que o cliente pode chamar ou, retorna uma instância de outra classe hospedada pelo serviço com métodos públicos que o cliente pode chamar 2. Retornar essa instância do Binder do método de retorno onbind(). 3. No cliente, receber a Binder do método de retorno onserviceconnected() e fazer chamadas para o serviço vinculado usando os métodos fornecidos. Nota: A razão pela qual o serviço e o cliente devem estar no mesmo pedido é porque o cliente pode converter o objeto retornado e chamar propriamente de sua API. O serviço e o cliente também devem estar no mesmo processo, porque essa técnica não exerce qualquer triagem em todos os processos. Por exemplo, aqui está um serviço que oferece aos clientes o acesso a métodos no serviço por meio de um Binder de execução: public class LocalService extends Service { // Binder given to clients private final IBinder mbinder = new LocalBinder(); // Random number generator private final Random mgenerator = new Random(); ANDROID, uma visão geral Anderson Duarte de Amorim 87

88 /** * 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 public IBinder onbind(intent intent) { return mbinder; /** method for clients */ public int getrandomnumber() { return mgenerator.nextint(100); O LocalBinder fornece o método getservice() de clientes para recuperar a instância atual do LocalService. Isso permite aos clientes chamarem métodos públicos no serviço. Por exemplo, os clientes podem chamar getrandomnumber() do serviço. Aqui está uma atividade que se liga a LocalService e solicita getrandomnumber() quando um botão é clicado: public class BindingActivity extends Activity { LocalService mservice; boolean mbound = protected void oncreate(bundle savedinstancestate) { super.oncreate(savedinstancestate); protected void onstart() { super.onstart(); // Bind to LocalService Intent intent = new Intent(this, LocalService.class); bindservice(intent, mconnection, protected void onstop() { super.onstop(); // Unbind from the service if (mbound) { ANDROID, uma visão geral Anderson Duarte de Amorim 88

89 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() 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 = public void onservicedisconnected(componentname arg0) { mbound = false; ; O exemplo acima mostra como o cliente liga para o serviço usando uma implementação do ServiceConnection e o callback de onserviceconnected(). Nota: O exemplo acima não é explicitamente desvinculado do serviço, mas todos os clientes devem desvincular em um tempo adequado (por exemplo, quando a atividade pausa). ANDROID, uma visão geral Anderson Duarte de Amorim 89

90 Usando um Messenger Se você precisar de seu serviço para se comunicar com processos remotos, então você pode usar um Messenger para fornecer a interface para o serviço. Esta técnica permite realizar a comunicação entre processos (IPC), sem a necessidade de utilizar AIDL. Aqui está um resumo de como usar um Messenger: O serviço implementa um Handler que recebe um callback para cada chamada de um cliente. 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 serviço, que, uma interface AIDL pura envia pedidos simultâneos para o serviço, que deve, então, lidar com multi-threading. Para a maioria das aplicações, o serviço não precisa executar multi-threading, portanto, usar um Messenger permite ao serviço lidar com uma chamada ao mesmo tempo. Se é importante que o seu serviço seja multi-threaded, então você deve usar AIDL para definir sua interface. O Handler é usado para criar uma Messenger (que é uma referência para o Handler). O Messenger cria um IBinder que o serviço retorna para clientes de onbind(). Os clientes usam o IBinder para instanciar o Messenger (que faz referência ao serviço Handler), que o cliente usa para enviar mensagens para o serviço. O serviço recebe cada mensagem em seu Handler, especificamente, no método handlemessage(). Desta forma, não existem "métodos" para o cliente para chamar o serviço. Em vez disso, o cliente fornece as "mensagens" (objetos Message) que o serviço recebe em seu Handler. Aqui está um exemplo de serviço 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. ANDROID, uma visão geral Anderson Duarte de Amorim 90

91 */ class IncomingHandler extends Handler 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. public IBinder onbind(intent intent) { Toast.makeText(getApplicationContext(), "binding", Toast.LENGTH_SHORT).show(); return mmessenger.getbinder(); Observe que o método handlemessage() no Handler é onde o serviço 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 serviço e enviar uma mensagem usando o send(). Por exemplo, aqui é uma atividade simples, que liga para o serviço e oferece a mensagem MSG_SAY_HELLO para o serviço: 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) { ANDROID, uma visão geral Anderson Duarte de Amorim 91

92 // 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) { protected void oncreate(bundle savedinstancestate) { super.oncreate(savedinstancestate); protected void onstart() { super.onstart(); // Bind to the service bindservice(new Intent(this, MessengerService.class), mconnection, protected void onstop() { super.onstop(); // Unbind from the service if (mbound) { unbindservice(mconnection); mbound = false; ANDROID, uma visão geral Anderson Duarte de Amorim 92

93 Observe que este exemplo não mostra como o serviço pode responder ao cliente. Se você deseja que o serviço responda, então você também precisa criar um Messenger no cliente. Então, quando o cliente recebe a chamada onserviceconnected(), ele envia uma mensagem para o serviço, que inclui o Messenger do cliente no parâmetro replyto d método send(). Você pode ver um exemplo de como fornecer mensagens bidirecionais no MessengerService.java (serviço) e MessengerServiceActivities.java (cliente). Vinculação a um serviço Componentes da aplicação (clientes) podem se ligar a um serviço chamando bindservice(). O sistema Android, em seguida, chama o serviço de onbind(), método que retorna um IBinder para interagir com o serviço. A ligação é assíncrona, bindservice() retorna imediatamente e não retorna a IBinder para o cliente. Para receber o IBinder, o cliente deve criar uma instância de ServiceConnection e o passa para bindservice(). O ServiceConnection inclui um método de resposta que o sistema chama para entregar o IBinder. Nota: Só as atividades, serviços e provedores de conteúdo podem se ligar a um serviço - você não pode se ligar a um serviço a partir de um receptor de broadcast. Assim, para ligar a um serviço de seu cliente, você deve: 1. Implementar ServiceConnection. A implementação deve substituir dois métodos: onserviceconnected(): O sistema chama isso para entregar o IBinder retornado pelo método onbind() do serviço. onservicedisconnected(): O sistema Android chama isso quando a conexão com o serviço é perdida inesperadamente, como quando o serviço foi paralisada ou tenha sido morta. Isto não é chamado quando o cliente libera. 2. Call bindservice(), passando a implementação ServiceConnection. ANDROID, uma visão geral Anderson Duarte de Amorim 93

94 3. Quando o sistema chama o método de retorno onserviceconnected(), você pode começar a fazer chamadas para o serviço, utilizando os métodos definidos pela interface. 4. Para desligar do serviço, chame unbindservice(). Quando o cliente for destruído, ele irá desvincular-se do serviço, mas você deve sempre desvincular quando terminar a interação com o serviço ou quando a atividade pausar, então o serviço pode parar enquanto não está sendo utilizado. Por exemplo, o seguinte trecho liga o cliente ao serviço criado anteriormente por estender a classe Binder, então tudo o que deve fazer é o lançar 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 serviço, passando este para bindservice(). Por exemplo: Intent intent = new Intent(this, LocalService.class); bindservice(intent, mconnection, Context.BIND_AUTO_CREATE); O primeiro parâmetro de bindservice() é uma Intent que, explicitamente, nomeia o serviço a ser vinculado (pensando que a intenção pode ser implícita). O segundo parâmetro é o objeto ServiceConnection. O terceiro parâmetro é um sinalizador que indica as opções para a ligação. Deve ser geralmente BIND_AUTO_CREATE, a fim de criar o serviço se ainda não ANDROID, uma visão geral Anderson Duarte de Amorim 94

95 estiver vivo. Outros valores possíveis são BIND_DEBUG_UNBIND e BIND_NOT_FOREGROUND, ou 0 para nenhum. Notas adicionais Aqui estão algumas anotações importantes sobre a ligação a um serviço: Você deve sempre lançar exceções DeadObjectException, que são lançados quando a conexão foi quebrada. Esta é a única exceção acionada por métodos remotos. Os objetos são referência contada através de processos. Você normalmente deverá emparelhar a ligação e desligamento durante a correspondente destruição e desmontagem de momentos do ciclo de vida do cliente. Por exemplo: o o Se você só precisa interagir com o serviço, enquanto sua atividade é visível, 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, então você pode se ligar durante oncreate() e desvincular durante ondestroy(). Cuidado com o que isso implica que a sua atividade necessita para usar o serviço durante todo o tempo ele está rodando (mesmo no fundo), por isso, se o serviço está em outro processo, então você aumentar o peso do processo e torna-se mais provável do sistema matá-lo. Nota: Você normalmente não deveria vincular e desvincular a sua atividade durante o onresume() e onpause(), porque esses retornos ocorrem em todas as transições do ciclo de vida e você deve manter o processamento que ocorre nessas transições para um nível mínimo. Além disso, se há várias atividades em sua aplicação para vincular o mesmo serviço e não há uma transição entre duas dessas atividades, o serviço pode ser destruído e recriado como desassocia a atividade atual (durante a pausa) antes da próxima ligação (durante a retomada). ANDROID, uma visão geral Anderson Duarte de Amorim 95

96 Gerenciando o ciclo de vida de um serviço de associação Figura 1. O ciclo de vida de um serviço que é iniciado e também permite a ligação. Quando um serviço é desvinculado de todos os clientes, o sistema Android o destrói (a menos foi iniciado com onstartcommand()). Como tal, você não tem que gerenciar o ciclo de vida do seu serviço se ele é meramente um limite de serviço - o sistema Android gerencia isso para você saber se ele está ligado a algum cliente. No entanto, se você optar por implementar o método de retorno onstartcommand(), então você deve explicitamente parar o serviço, porque o serviço é considerado agora a ANDROID, uma visão geral Anderson Duarte de Amorim 96

97 ser iniciado. Neste caso, o serviço é executado até que o serviço para com stopself() ou outro componente chama stopservice(), independentemente se está ligado a outros clientes. Além disso, se o serviço é iniciado e aceita a ligação, então quando o sistema solicita sua onunbind(), você pode opcionalmente retornar true se você gostaria de receber uma chamada para onrebind() na próxima vez que um cliente chama o serviço (ao invés de receber uma chamada para onbind()). onrebind() retorna void, mas o cliente ainda recebe o IBinder na sua onserviceconnected(). A figura 1 ilustra a lógica para este tipo de ciclo de vida. ANDROID, uma visão geral Anderson Duarte de Amorim 97

98 Processos e threads Quando um componente de aplicativo se inicia e a aplicação não possui nenhum outro componente rodando, o sistema Android inicia um novo processo Linux para a aplicação com um único thread. Por padrão, 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 aplicação (porque um outro componente do aplicativo existe), então o componente é iniciado dentro desse processo e usa o mesmo thread de execução. 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 padrão, todos os componentes do mesmo aplicativo executam no mesmo processo e a maioria das aplicações não 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 próprio processo, ou que algumas componentes compartilham um processo, enquanto outros não. Você também pode definir android:process de modo que os componentes de diferentes aplicações sejam executados no mesmo processo - desde que as aplicações compartilhem o mesmo ID de usuário do Linux e assinem com os mesmos certificados. O elemento <application> também suporta um atributos android:process, para definir um valor padrão que se aplica a todos os componentes. Android pode decidir encerrar um processo em algum momento, quando houver pouca memória e exigido por outros processos que estão mais imediatamente servindo ao usuário. Componentes de aplicativos em execução no processo que está morto são conseqüentemente destruídos. Um processo é iniciado novamente para esses componentes, quando há trabalho novamente para que eles façam. ANDROID, uma visão geral Anderson Duarte de Amorim 98

99 Ao decidir quais os processos matar, o sistema Android pesa a sua importância relativa para o usuário. Por exemplo, é mais facilmente desligado um processo hospedando atividades que não são mais visíveis na tela, em comparação com um processo hospedando atividades visíveis. A decisão de encerrar um processo, portanto, depende do estado dos componentes em execução no processo. Ciclo de vida do processo O sistema Android tenta manter um processo de candidatura pelo maior tempo possível, mas, eventualmente, precisa remover os processos antigos para recuperar a memória para novos processos ou mais importantes. Para determinar quais os processos manter e quais matar, o sistema coloca cada processo em uma "hierarquia de importância" com base nos componentes em execução no processo e o estado desses componentes. Processos com menor importância são eliminadas em primeiro lugar, em seguida, aqueles com a menor importância seguinte, e assim por diante, sempre que necessário para recuperar os recursos do sistema. Há cinco níveis na hierarquia de importância. A lista a seguir apresenta os diferentes tipos de processos em ordem de importância (o primeiro processo é o mais importante e é morto por último): 1. Processo em primeiro plano: Um processo que é necessário para que o usuário esteja fazendo atualmente. Um processo é considerado em primeiro plano, se qualquer uma das seguintes condições forem verdadeiras: Abriga uma Activity com a qual o usuário está interagindo com (o método onresume() da Activity foi chamado). Abriga um Service que está vinculado à atividade que o usuário está interagindo. Abriga um Service que está sendo executado "em primeiro plano", o serviço chamado é startforeground(). Abriga um Service que está executando um ciclo de vida de seus retornos (oncreate(), onstart(), ou ondestroy()). Abriga um BroadcastReceiver que está executando a sua onreceive(). Geralmente, apenas um processo de background existe em um determinado momento. Eles são mortos apenas como um último recurso - se a memória é tão ANDROID, uma visão geral Anderson Duarte de Amorim 99

100 pouca que ele não pode continuar rodando. Geralmente, nesse ponto, o dispositivo atingiu um estado de paginação de memória, então, matar alguns processos de primeiro plano é necessário para manter a interface de usuário sensível. 2. Processo Visível Um processo que não tem nenhum componente de primeiro plano, mas ainda pode afetar o que o usuário vê na tela. Um processo é considerado visível se qualquer uma das seguintes condições forem verdadeiras: Abriga uma Activity que não está em primeiro plano, mas ainda é visível para o usuário (seu método onpause() foi chamado). Isso pode ocorrer, por exemplo, se a atividade iniciou um plano de diálogo, que permite que a atividade anterior possa ser vista por trás dele. Abriga um Service que está vinculado a uma atividade (ou plano) visível. Um processo visível é considerado extremamente importante e não vai ser morto a menos que isso é necessário para manter todos os processos de primeiro plano em execução. 3. Processo de serviço Um processo que está executando um serviço que foi iniciado com o método startservice() e não se enquadra em nenhuma das duas categorias acima. Embora os processos de serviço não estejam diretamente ligados a qualquer coisa que o usuário vê, eles estão geralmente fazendo coisas que o usuário se preocupa (como a reprodução de música no fundo ou baixando arquivo na rede), então o sistema os mantém rodando, a menos que não haja memória suficiente para retêlos, juntamente com o primeiro plano e processos visíveis. 4. Processo em segundo plano Um processo que mantém uma atividade que não é visível para o usuário no momento (o método onstop() da atividade foi chamado). Esses processos não têm impacto direto sobre a experiência do usuário, e o sistema pode matá-los a qualquer momento para recuperar a memória para primeiro plano, visibilidade, ou processo de serviço. Normalmente, há muitos processos em execução no ANDROID, uma visão geral Anderson Duarte de Amorim 100

101 fundo, então eles são mantidos em uma LRU (menos recentemente usada), lista para garantir que o processo com a atividade que mais recentemente foi visto pelo usuário é o último a ser morto. Se uma atividade implementa métodos de seu ciclo de vida corretamente, e salva o seu estado atual, matar o seu processo não terá um efeito visível sobre a experiência do usuário, pois quando o usuário navega de volta para a atividade, a atividade restaura todo o seu estado visível. 5. Processo vazio Um processo que não possui todos os componentes do aplicativo ativos. A única razão para manter esse tipo de processo vivo é para fins de armazenamento em cache, para melhorar o tempo de inicialização da próxima 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 cachês do kernel subjacente. Android enfileira um processo ao mais alto nível que pode, com base na importância do componente ativo no processo. Por exemplo, se um processo hospeda um serviço e uma atividade visível, o processo é classificado como um processo visível, e não um processo de serviço. Além disso, o ranking de um processo pode ser acrescido, pois outros processos são 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 conteúdo em um processo A está a servir um cliente no processo de B, ou se um serviço em um processo A está ligado a um componente no processo de B, processo A é sempre considerado pelo menos tão importante como o processo B. Porque um processo executando um serviço é melhor classificado do que um processo com atividades em segundo plano, uma atividade que inicia uma operação de longa duração pode muito bem começar um serviço para essa operação, ao invés de simplesmente criar uma thread de trabalhador - particularmente se a operação provavelmente durará mais que a atividade. Por exemplo, uma atividade que carrega uma foto em um site deve iniciar um serviço para realizar o upload, então o upload pode continuar em segundo plano, mesmo se o usuário deixar a atividade. Usar um serviço garante que a operação terá, pelo menos, prioridade "no processo do serviço", ANDROID, uma visão geral Anderson Duarte de Amorim 101

102 independentemente do que acontece com a atividade. Este é o mesmo motivo que os receptores de broadcast devem contratar serviços ao invés de simplesmente colocar operações demoradas em um thread. Thread Quando uma aplicação é lançada, o sistema cria um thread de execução para o aplicativo, chamado de "main". Esta thread é muito importante, pois é responsável por despachar os eventos para os apropriados widgets de interface de usuário, incluindo eventos de desenho. É também o segmento em que sua aplicação interage com os componentes da UI Toolkit Android (componentes da android.widget e pacotes android.view). Como tal, o thread principal é chamado também às vezes de UI thread. O sistema não cria um thread separado para cada instância de um componente. Todos os componentes que são executados no mesmo processo são instanciados no thread de interface do usuário e as chamadas do sistema para cada componente são despachadas a partir desse thread. Conseqüentemente, os métodos que respondem às callbacks do sistema (como onkeydown() para relatar as ações do usuário ou um método de retorno do ciclo de vida) sempre executam no thread da interface do usuário do processo. Por exemplo, quando o usuário toca um botão na tela, seu thread UI do aplicativo despacha o evento de toque para o widget, que por sua vez, define seu estado pressionado e lança uma requisição inválida para a fila de eventos. O thread UI desenfilera a requisição e notifica o widget que deve se redesenhar. Quando o aplicativo executa um trabalho intensivo em resposta à interação do usuário, este único thread pode produzir mal desempenho a menos que você implemente a sua aplicação de forma adequada. Especificamente, se tudo está acontecendo no thread de interface do usuário, realizando longas operações, 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 usuário, o aplicativo parece travar. Pior ainda, se o segmento de interface do usuário estiver bloqueado por mais de alguns segundos (cerca de 5 segundos atualmente) ao usuário é apresentado o abominável "aplicativo não responde" (ANR). O usuário pode, então, decidir abandonar a aplicação e desinstalá-la se está infeliz. ANDROID, uma visão geral Anderson Duarte de Amorim 102

103 Além disso, o Andoid UI Toolkit não é thread-safe. Então, você não deve manipular a sua interface a partir de um thread de trabalho - você deve fazer toda a manipulação de sua interface a partir de um thread UI. Assim, existem apenas duas regras para o modelo de thread única no Android: 1. Não bloquear o thread de UI 2. Não 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 usuário do seu aplicativo que você não bloqueie o thread. Se você tiver de realizar operações que não são instantâneas, você deve certificar-se de fazê-las em threads separados ("background" ou threads "worker"). Por exemplo, abaixo está um código para um usuário 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(" mimageview.setimagebitmap(b); ).start(); Em princípio, isso parece funcionar bem, porque cria uma nova thread para lidar com a operação da rede. No entanto, ele viola a segunda regra do modelo de única thread: não 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 difícil e demorado para rastrear. Para corrigir esse problema, o Android oferece várias maneiras para acessar a thread de interface do usuário a partir de outros threads. Aqui está uma lista de métodos que podem ajudar: Activity.runOnUiThread(Runnable) View.post(Runnable) View.postDelayed(Runnable, long) ANDROID, uma visão geral Anderson Duarte de Amorim 103

104 Por exemplo, você pode corrigir o código acima usando o método View.post(Runnable): public void onclick(view v) { new Thread(new Runnable() { public void run() { final Bitmap bitmap = loadimagefromnetwork(" mimageview.post(new Runnable() { public void run() { mimageview.setimagebitmap(bitmap); ); ).start(); Agora, essa implementação é thread-safe: o funcionamento da rede é feito a partir de um segmento separado, enquanto o ImageView é manipulado a partir do thread de interface de usuário. No entanto, como a complexidade da operação cresce, este tipo de código pode ser complicado e difícil de manter. Para lidar com interações 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 solução, porém, é estender a classe AsyncTask, o que simplifica a execução de tarefas do thread de trabalho que precisam interagir com a interface do usuário. Usando AsyncTask AsyncTask permite executar trabalho assíncrono em sua interface com o usuário. Ela executa as operações de bloqueio em um segmento de trabalho e, em seguida, publica os resultados no segmento de interface do usuário, sem que você precise lidar com tópicos e/ou manipuladores de si mesmo. Para usá-lo, você deve incorporar AsyncTask e implementar o método 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 usuário, assim você pode escolher atualizar o UI. Você pode então executar a tarefa, chamando execute() do thread UI. ANDROID, uma visão geral Anderson Duarte de Amorim 104

105 Por exemplo, você pode implementar o exemplo anterior usando AsyncTask desta forma: public void onclick(view v) { new DownloadImageTask().execute(" 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 usuário é segura e o código é 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 usuário. Você deve ler o AsyncTask de referência para um entendimento completo de como usar essa classe, mas aqui está uma visão geral de como funciona: Você pode especificar o tipo dos parâmetros, os valores de progresso e o valor final da tarefa, usando genéricos O método doinbackground() é executado automaticamente em um segmento de trabalho onpreexecute(), onpostexecute(), e onprogressupdate() são invocados no thread de interface do usuário 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 Atenção: Outro problema que se pode encontrar ao usar um segmento de trabalho é reinícios inesperados na sua atividade devido a uma alteração de configuração em tempo de execução (como quando o usuário muda a orientação da tela), que podem ANDROID, uma visão geral Anderson Duarte de Amorim 105

106 destruir seu segmento de trabalho. Para ver como você pode manter a sua tarefa durante um desses reinícios e como fazer corretamente um cancelamento da tarefa quando a atividade for destruída, veja o código fonte para o aplicativo de amostra da Prateleira. Métodos de Thread-safe Em algumas situações, os métodos a implementar poderiam ser chamados de mais de um thread e, portanto, deve ser escrito para ser thread-safe. Isto é principalmente verdadeiro para métodos que podem ser chamados remotamente, como métodos de um serviço vinculado. Quando uma chamada de um método implementado em um IBinder se origina no mesmo processo em que o IBinder está executando, o método é executado na thread de quem chamou. No entanto, quando a chamada é originada em outro processo, o método é executado em um thread escolhido de um pool de threads que o sistema mantém no mesmo processo que o IBinder (não é executado no thread da interface do usuário do processo). Por exemplo, considerando que um método onbind() do serviço seria chamado do de interface do usuário do processo de serviço, métodos implementados no objeto que onbind() retorna (por exemplo, uma subclasse que implementa métodos RPC) seriam chamados threads no pool. Como um serviço pode ter mais de um cliente, mais de uma pool de threads pode envolver o mesmo método IBinder, ao mesmo tempo. Métodos IBinder devem, portanto, ser implementadas para ser thread-safe. Da mesma forma, um provedor de conteúdo pode receber dados de pedidos que se originam em outros processos. Embora o ContentResolver e ContentProvider ocultam os detalhes de como a comunicação entre processos é gerenciada, métodos ContentProvider que respondem a esses pedidos - os métodos query(), insert(), delete(), update(), e gettype() são chamados a partir de um pool de threads no processo de provedor de conteúdo, e não o thread UI para o processo. Como esses métodos podem ser chamados a partir de qualquer número de threads ao mesmo tempo, eles também devem ser implementados para ser thread-safe. Comunicação entre processos Android oferece um mecanismo para comunicação entre processos (IPC) através de chamadas de procedimento remoto (RPCs), em que um método é chamado por uma ANDROID, uma visão geral Anderson Duarte de Amorim 106

107 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 decomposição de uma chamada de método e de seus dados a um nível que o sistema operacional possa entender, transmiti-lo a partir do processo do processo local e espaço de endereçamento para o processo remoto e espaço de endereço, em seguida, remontar e reencenar a chamada. Os valores de retorno são transmitidos na direção oposta. Android fornece todo o código para executar essas operações IPC, para que você possa se concentrar na definição e implementação da interface de programação do RPC. Para executar o IPC, o aplicativo deve ligar para um serviço, utilizando bindservice(). ANDROID, uma visão geral Anderson Duarte de Amorim 107

108 Interface de usuário Em um aplicativo do Android, a interface do usuário é construída usando objetos View e ViewGroup. Existem muitos tipos de views e view groups, cada um dos quais é um descendente da classe View. Objetos view são as unidades básicas de expressão da interface do usuário na plataforma Android. A classe View serve como base para as subclasses chamadas de "widgets", que oferecem completa implementação de objetos de interface do usuário, como campos de texto e botões. 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 parâmetros de layout e de conteúdo para uma determinada área retangular da tela. Um objeto View lida com sua própria medida, layout, desenho, mudança de foco, scrolling e interações telcla/gesto para a área retangular da tela na qual ele reside. Como um objeto na interface do usuário, uma View é também um ponto de interação para o usuário e o receptor de eventos de interação. Hierarquia de view Sobre a plataforma Android, você define uma interface de atividades, usando uma hierarquia de view e nós ViewGroup, como mostrado no diagrama abaixo. Esta árvore de hierarquia pode ser tão 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. ANDROID, uma visão geral Anderson Duarte de Amorim 108

109 A fim de fixar a árvore de hierarquia de views à tela para renderização, sua atividade deve chamar o método setcontentview() e passar uma referência ao objeto nó raiz. O sistema Android recebe esta referência e usa-o para invalidar, medir e desenhar a árvore. O nó raiz da hierarquia requisita que seus nós filhos desenhem a si próprios - por sua vez, cada nó do ViewGroup é responsável por chamar cada um de seus views filhos para desenhar a si mesmos. Os filhos podem solicitar um tamanho e localização com os pais, mas o objeto-mãe tem a decisão final sobre onde e qual o tamanho que cada criança 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 são desenhados em ordem, se há elementos que se sobrepõem posições, o último a ser elaborado vai ficar em cima dos outros previamente elaborados para aquele espaço. Como o Android desenha views Quando uma atividade recebe o foco, ela será convidada a desenhar o layout. O framework Android vai lidar com o processo de elaboração, mas a atividade deve apresentar o nó raiz da sua hierarquia de layout. Desenho começa com o nó raiz do layout. É solicitado para medir e desenhar a árvore de layout. Desenho é tratado pelo pé da árvore e renderização de cada vista que cruza a região inválida. Por sua vez, cada grupo View é responsável por solicitar a cada um dos seus filhos a ser desenhado (com o método draw()) e cada View é responsável pelo desenho de si. Como a árvore é percorrida em ordem, isso significa que os pais serão desenhados antes do que seus filhos, com irmãos elaborados na ordem em que aparecem na árvore. ANDROID, uma visão geral Anderson Duarte de Amorim 109

110 Desenhar o layout é um processo de duas passagens: a passagem de medidas e uma passagem de layout. A passagem de medição é implementada com measure(int, int) e é uma passagem top-down da árvore. Cada view empurra as especificações de dimensão 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 também é top-down. Durante o passar, cada pai é responsável pelo posicionamento de todos os seus filhos usando os tamanhos computados na passagem de medidas. Durante um método 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 medição de largura e altura da view devem respeitar as restrições impostas pelos pais da view. Isso garante que, no final da passagem de medidas, todos os pais aceitam todas as medições 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 dimensões não especificadas para descobrir o quão grande eles querem ser, então chama measure() neles novamente com números reais, se a soma dos tamanhos dos filhos irrestrita é muito grande ou muito pequena (Ou seja, se os filhos não concordam entre si a respeito de quanto espaço cada um ganha, o pai vai intervir e estabelecer as regras na segunda passagem). A passagem de medidas utiliza duas classes para Para dar início a um esquema, chamase requestlayout(). Este método comunicar dimensões. A classe View.MeasureSpec é usada por views para normalmente é chamado por uma view contar aos pais como eles querem ser medidos e sobre si mesma quando se acredita que é possível não caber mais dentro de posicionados. A classe base LayoutParams seus limites atuais. apenas descreve quão grandes as views querem ser para a largura e altura. Para cada dimensão, pode especificar um dos seguintes: um número exato FILL_PARENT, o que significa que o view quer ser tão grande quanto seu pai (menos padding) WRAP_CONTENT, o que significa que o view quer ser grande o suficiente para colocar o seu conteúdo (mais padding). ANDROID, uma visão geral Anderson Duarte de Amorim 110

111 Há subclasses de LayoutParams para diferentes subclasses de ViewGroup. Por exemplo, RelativeLayout tem a sua própria subclasse de LayoutParams, que inclui a capacidade de centralizar os filhos horizontalmente e verticalmente. MeasureSpecs são usados para empurrar os requisitos para baixo da árvore de pai para filho. Um MeasureSpec pode estar em um dos três modos: Layout NÃO ESPECIFICADO: Isto é usado por um dos pais para determinar a dimensão 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 criança. A criança deve usar esse tamanho, e garante que todos os seus descendentes se encaixem dentro desse tamanho. NO MÁXIMO: Este é usado pelos pais para impor um tamanho máximo para a criança. A criança deve garantir que ele e todos os seus descendentes vão caber dentro deste tamanho. 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 legível para o layout, muito parecido com HTML. Cada elemento em XML é ou um View ou ViewGroup (ou descendentes dos mesmos). Objetos view são folhas da árvore, objetos ViewGroup são 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 usuário, e um elemento <LinearLayout> cria um ViewGroup. Quando você carregar um recurso de layout, o sistema Android inicializa esses objetos em tempo de execução, correspondentes aos elementos em seu layout. Por exemplo, um layout simples vertical, com um text view e um botão parece com este: <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android=" android:layout_width="fill_parent" ANDROID, uma visão geral Anderson Duarte de Amorim 111

112 android:layout_height="fill_parent" android:orientation="vertical" > <TextView 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 contém o TextView e o Botão. Você pode aninhar outro LinearLayout (ou outro tipo de grupo de exibição) aqui dentro, para alongar a hierarquia de view e criar um layout mais complexo. Dica: Você também pode desenhar View e ViewGroups em código Java, utilizando métodos 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 exibição, você pode estruturar views herdados e view groups em um número 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 parâmetros de layout que são usados para definir as posições 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 interação com o usuário. Android fornece um conjunto de widgets plenamente implementadas, como botões, caixas de seleção, e os campos de entrada de texto, assim você pode construir rapidamente sua interface do usuário. Alguns widgets fornecidos pelo Android são mais complexos, como um selecionador de data, um relógio, e controles de zoom. Mas você não está limitado aos tipos de elementos fornecidos pela plataforma Android. Se você quiser fazer algo mais personalizado e criar seus próprios elementos, pode, através da ANDROID, uma visão geral Anderson Duarte de Amorim 112

113 definição de seu objeto View próprio ou através da extensão e combinação de elementos existentes. ANDROID, uma visão geral Anderson Duarte de Amorim 113

114 Eventos UI Uma vez que você adicionou alguns views/widgets para a interface do usuário, você provavelmente quer saber sobre a interação do usuário com eles, para que você possa executar ações. 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 contém uma coleção de interfaces aninhadas nomeadas <something> Listener, cada um com um método 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 exibição), e View.OnKeyListener (para lidar com teclas pressionadas no dispositivo dentro de uma View). Então se você quer sua View para ser notificado quando ela é "clicada" (como quando um botão é selecionado), implemente OnClickListener e defina o seu método de retorno onclick() (onde você executar a ação após o clique), e registra-o para a View com setonclicklistener(). Substituir um método de retorno existente para a View. Isto é o que você deve fazer quando você implementou sua própria classe View e quer receber eventos específicos que ocorrem dentro dele. Exemplificando eventos você pode manipular inclusão 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 padrão para cada evento dentro da sua View personalizada e determinar se o evento deve ser transmitido para alguma outra View filho. Novamente, essas são 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 são outra parte importante da interface do usuário de um aplicativo. Menus oferecem uma interface confiável, que revela funções de aplicativos e configurações. O menu de aplicativos mais comuns é revelado, pressionando a tecla MENU no dispositivo. No entanto, você também pode adicionar menus de contexto, ANDROID, uma visão geral Anderson Duarte de Amorim 114

115 que podem ser revelados quando o usuário pressiona e mantém pressionado em um item. Os menus também são estruturados usando uma hierarquia View, mas você não define essa estrutura por si mesmo. Em vez disso, você define métodos 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 necessária hierarquia View para o menu e desenhar cada um dos seus itens de menu na mesma. Menus também lidam com seus próprios eventos, por isso não há necessidade de registrar eventos listeners sobre os itens do seu menu. Quando um item no seu menu é selecionado, o método onoptionsitemselected() ou oncontextitemselected() será chamado pelo framework. E, assim como o layout do aplicativo, você tem a opção de declarar os itens para seu menu em um arquivo XML. Tópicos Avançados Uma vez que você aprendeu os fundamentos da criação de uma interface, você pode explorar algumas características avançadas para a criação de uma interface de aplicação mais complexa. Adaptadores Às vezes você deseja preencher um view group com algumas informações que não 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 visão e cada filho view é inicializado e preenchido com os dados do adaptador. O objeto AdapterView é uma implementação 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 várias implementações da classe Adapter, para tarefas específicas, como a CursorAdapter para leitura de dados banco de dados de um cursor ou um ArrayAdapter para a leitura de uma matriz arbitrária. ANDROID, uma visão geral Anderson Duarte de Amorim 115

116 Estilos e Temas Talvez você não esteja satisfeito com a aparência dos widgets padrão. Para revê-los, você pode criar alguns dos seus próprios estilos e temas. Um estilo é um conjunto de um ou mais atributos de formatação 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 específicos. Um tema é um conjunto de um ou mais atributos de formatação que você pode aplicar como uma unidade para todas as atividades em uma aplicação, ou apenas uma atividade única. Por exemplo, você pode definir um tema que define as cores específicas 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 específicas ou todo o aplicativo. Estilos e temas são recursos. Android oferece alguns recursos de estilo padrão e tema que você pode usar, ou você pode declarar o seu próprio estilo customizado e recursos de tema. ANDROID, uma visão geral Anderson Duarte de Amorim 116

117 Declarando Layout Seu layout é a arquitetura para interface de usuário em uma atividade. Ela define a estrutura de layout e possui todos os elementos que aparecem para o usuário. Você pode declarar o seu layout de duas maneiras: Declare elementos UI em XML - Android fornece um vocabulário XML simples que corresponde às classes View e subclasses, tais como widgets e layouts. Instanciar elementos de layout em tempo de execução - 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 métodos para declarar e gerenciar a interface do usuário do seu aplicativo. Por exemplo, você poderia declarar layouts padrão de seu aplicativo em XML, incluindo os elementos da tela que aparecerão nela e suas propriedades. Você pode então adicionar o código em seu aplicativo que iria alterar o estado dos objetos da tela, incluindo aqueles declarados em XML, em tempo de execução. A vantagem de declarar a sua O plugin ADT para Eclipse oferece um interface em XML é que ela permite preview do seu layout XML - com o melhor separar a apresentação da sua arquivo XML aberto, selecione a guia aplicação do código que controla o Layout. seu comportamento. Suas descrições Você também deve tentar a ferramenta de de interface do usuário são externas à Hierarquia Viewer para depuração de sua aplicação, o que significa que layouts ela revela propriedade de layout, você pode modificá-lo ou adaptá-lo desenha wireframes com indicadores sem ter que modificar seu códigofonte e recompilar. Por exemplo, você renderizadas enquanto você depurar no padding/margin e view completas emulador ou dispositivo. pode criar layouts XML para A ferramenta layoutopt permite analisar orientações de tela diferentes, rapidamente os seus layouts e hierarquias diferentes tamanhos de tela do de ineficiências ou outros problemas. dispositivo, e línguas diferentes. Além disso, declarar o layout em XML torna mais fácil visualizar a estrutura de sua ANDROID, uma visão geral Anderson Duarte de Amorim 117

118 interface do usuário, por isso é mais fácil 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 execução, consulte as classes ViewGroup e View. Em geral, o vocabulário XML para a declaração de elementos da interface segue de perto a estrutura e nomenclatura das classes e métodos, onde os nomes dos elementos correspondem aos nomes de classes e nomes de atributos correspondem aos métodos. De fato, a correspondência é muitas vezes tão direta que você pode adivinhar o atributo XML corresponde a um método de classe, ou adivinhar o que a classe corresponde a um determinado elemento XML. No entanto, note que nem todo vocabulário é idêntico. Em alguns casos, existem ligeiras diferenças 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 vocabulário do Android XML, você pode rapidamente criar layouts de interface do usuário e os elementos de tela que eles contêm, da mesma forma que você cria páginas web em HTML - com uma série 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 exibição que define o layout. Por exemplo, aqui está um esquema XML que usa um LinearLayout vertical que contém um TextView e um Button : <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns: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> ANDROID, uma visão geral Anderson Duarte de Amorim 118

119 Depois de ter declarado o seu layout em XML, salve o arquivo com a extensão.xml em seu projeto Android no diretório res/layout/, assim ele vai compilar corretamente. Carregar os recursos XML Quando você compilar sua aplicação, cada arquivo de layout XML é compilado em um View de recurso. Você deve carregar o recurso de layout de sua aplicação, em sua implementação de retorno Activity.onCreate(). Faça isso chamando setcontentview(), passando a referência ao seu recurso de layout na forma de: R.layout. layout_file_name. Por exemplo, se o seu layout XML é salvo como main_layout.xml, você deve carregá-lo para a sua atividade da seguinte forma: public void oncreate(bundle savedinstancestate) { super.oncreate(savedinstancestate); setcontentview(r.layout.main_layout); O método de retorno oncreate() em sua atividade é chamado pelo framework Android quando sua atividade é lançada. Atributos Cada objeto View e ViewGroup apóia a sua própria variedade de atributos XML. Alguns atributos são específicos para um objeto View (por exemplo, TextView apóia o atributo textsize), mas esses atributos também são herdadas por qualquer objetos View que podem estender esta classe. Alguns são comuns a todos objetos View, porque eles são herdados da classe View raiz (como o atributo id). E, outros atributos são considerados "parâmetros de layout", que são atributos que descrevem determinadas orientações 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 identificação é referenciada como um inteiro, mas a identificação é normalmente atribuída 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 identificação, dentro de uma tag XML é: ANDROID, uma visão geral Anderson Duarte de Amorim 119

120 O símbolo de arroba (@) no início da string indica que o analisador XML deve analisar e ampliar o resto da seqüência de identificação e identificá-lo como um recurso de identificação. 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 série de recursos de outro tipo de identificação que são oferecidos pela estrutura do Android. Ao fazer referência a uma identificação de recurso Android, você não 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 referência a uma ID da classe de recursos android.r, ao invés da classe de recursos locais. A fim de criar views e referenciá-los a partir da aplicação, um padrão 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 instância do objeto view e capture-o a partir do layout (geralmente no método oncreate()): Button mybutton = (Button) findviewbyid(r.id.my_button); Definir os IDs dos objetos view é importante ao criar um RelativeLayout. Em um RelativeLayout, views irmãos podem definir a sua disposição em relação a outro view irmão, que é referenciada pela ID exclusiva. Uma identificação não 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 possível). Parâmetros de layout Atributos de layout XML chamados layout_something definem os parâmetros de layout para a view que sejam adequadas para a ViewGroup em que ele reside. ANDROID, uma visão geral Anderson Duarte de Amorim 120

121 Cada classe ViewGroup implementa uma classe aninhada que estende ViewGroup.LayoutParams. Esta subclasse contém os tipos de propriedades que definem o tamanho e a posição de cada view filha, conforme apropriado para o view group. Como você pode ver na figura 1, o grupo de exibição pai define os parâmetros de layout para cada view filho (incluindo o view group dos filhos). Figura 1. Visualização de uma hierarquia de views com os parâmetros de layout associado a cada exibição. Note que cada subclasse LayoutParams tem sua própria sintaxe para definir valores. Cada elemento filho deve definir LayoutParams que são apropriadas para seu pai, embora possa também definir LayoutParams diferentes para seus filhos. Todos os view groups incluem uma largura e altura (layout_width e layout_height), e cada view é necessária para defini-los. Muitos LayoutParams também incluem margens opcional e fronteiras. Você pode especificar a largura e altura com medidas exatas, embora você provavelmente não irá querer fazer isso com freqüência. Mais freqüentemente, você vai usar uma dessas constantes para definir a largura ou altura: wrap_content diz a seu view a arranjar a si próprio para as dimensões exigidas pelo seu conteúdo. ANDROID, uma visão geral Anderson Duarte de Amorim 121

122 fill_parent (rebatizada match_parent na API Nível 8) diz à sua view para se tornar tão grande quanto o view group dos pais irá permitir. Em geral, especificar uma largura de layout e altura, utilizando unidades absolutas, tais como pixels não é 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 através de uma variedade de tamanhos de tela do dispositivo. Os tipos de medição aceitos são definidos no documento Recursos Disponíveis. Posição de Layout A geometria de uma view é a de um retângulo. Uma view tem uma localização, expresso como um par de coordenadas esquerda e superior, e duas dimensões, expressa em uma largura e uma altura. A unidade para a localização e as dimensões é o pixel. É possível recuperar o local de uma visão chamando os métodos getleft() e gettop(). O primeiro retorna a esquerda, ou X, de coordenadas do retângulo que representa o view. O segundo retorna o topo, ou Y, coordenadas do retângulo que representa o view. Estes dois métodos devolvem o local da view em relação 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. Além disso, vários métodos de conveniência são oferecidos para evitar cálculos desnecessários, ou seja, getright() e getbottom(). Esses métodos retornam as coordenadas das bordas direita e inferior do retângulo que representa o view. Por exemplo, chamando getright() é semelhante ao seguinte cálculo: getleft() + getwidth(). Tamanho, padding e margin O tamanho de uma view é expressa com uma largura e uma altura. Uma visão realmente possue dois pares de valores de largura e altura. O primeiro par é conhecido como largura medida e altura medida. Essas dimensões definem quão grande quer ser em vista de seu pai. As dimensões medidas podem ser obtidas chamando getmeasuredwidth() e getmeasuredheight(). ANDROID, uma visão geral Anderson Duarte de Amorim 122

123 O segundo par é conhecido simplesmente como largura e altura, ou às vezes a largura de desenho e altura de desenho. Essas dimensões definem o tamanho real do view sobre tela, em tempo de desenho e depois de layout. Esses valores podem ser, mas não tem que ser diferentes da largura e altura medidos. A largura e altura podem ser obtidas chamando getwidth() e getheight(). Para medir as suas dimensões, 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 conteúdo da visão de uma determinada quantidade de pixels. Por exemplo, um padding-left de 2 vai empurrar o conteúdo do view por 2 pixels à direita da margem esquerda. Padding pode ser definido usando o método setpadding(int, int, int, int) e consultado chamando getpaddingleft(), getpaddingtop(), getpaddingright() e getpaddingbottom(). Apesar de uma exibição poder definir um padding, isso não prevê qualquer apoio para as margens. No entanto, view groups prestam esse apoio. ANDROID, uma visão geral Anderson Duarte de Amorim 123

124 Criando Menus Os menus são uma parte importante da interface de uma atividade do usuário, que fornecem aos usuários uma forma familiar para executar ações. Android oferece um quadro simples para você adicionar menus padrão para seu aplicativo. Existem três tipos de menus de aplicação: Menu de Opções A coleção de itens do menu principal para uma atividade, que aparece quando o usuário toca no botão MENU. Quando o aplicativo está rodando o Android 3.0 ou posterior, você pode fornecer acesso rápido para selecionar itens de menu, colocando-os diretamente na barra de ação, como "itens de ação." Menu de Contexto Uma lista de itens de menu flutuante que aparece quando o usuário toca e tem uma visão que está registrada para fornecer um menu de contexto. Submenu Uma lista de itens de menu flutuante que aparece quando o usuário toca um item de menu que contém um menu aninhado. Criando um recurso de menu Em vez de instanciar um Menu no seu código do aplicativo, você deve definir um menu e todos os seus itens em um XML menu resource, em seguida, inflar o recurso de menu (carregá-lo como um objeto programável) no seu código do aplicativo. Utilizando um recurso de menu para definir o seu menu é uma boa prática, pois separa o conteúdo do menu de seu código do aplicativo. É também mais fácil de visualizar a estrutura e o conteúdo de um menu em XML. Para criar um recurso de menu, crie um arquivo XML dentro de seu projeto do diretório res/menu/ e crie o menu com os seguintes elementos: ANDROID, uma visão geral Anderson Duarte de Amorim 124

125 <menu> <item> <group> Define um Menu, que é um recipiente para itens de menu. Um elemento <menu> deve ser o nó raiz para o arquivo e pode conter um ou mais <item> e elementos <group>. 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. Um opcional, recipiente invisível 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=" <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 android:icon android:title A identificação do recurso que é único para o item, que permite que o aplicativo possa reconhecer o item quando o usuário seleciona-o. Uma referência para um desenho para usar como ícone do item. Uma referência a uma string para usar como título do item. ANDROID, uma visão geral Anderson Duarte de Amorim 125

126 Há muito mais atributos que você pode incluir em um <item>, incluindo alguns que especificam como o item pode aparecer na barra de ação. Inflar um recurso de menu A partir de seu código de aplicativo, você pode inflar um recurso de menu (converter o recurso de XML em um objeto programável) utilizando MenuInflater.inflate(). Por exemplo, o seguinte código infla o arquivo game_menu.xml definido acima, durante o método de retorno oncreateoptionsmenu(), para usar o menu como a atividade do Menu de public boolean oncreateoptionsmenu(menu menu) { MenuInflater inflater = getmenuinflater(); inflater.inflate(r.menu.game_menu, menu); return true; O método 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(). Criando um Menu de Opções Quando executado em um dispositivo com Android 2.3 e inferior, o Menu de Opções aparece na parte inferior da tela, como mostrado na figura 1. Quando aberto, a primeira porção visível do Menu de Opções é o menu do ícone. Ele mantém os seis primeiros itens do menu. Se você adicionar mais de seis itens do Menu de Opções, o Android coloca o sexto item e aqueles após no menu de estouro, que o usuário pode abrir tocando no item "More" do menu. Figura 1. Screenshot do menu de opções no browser. ANDROID, uma visão geral Anderson Duarte de Amorim 126

127 No Android 3.0 e superior, os itens do Menu de Opções são colocados na barra de ação, que aparece no topo da atividade no lugar da barra de título tradicional. Por padrão todos os itens do Menu de Opções são colocados no menu de estouro, que o usuário pode abrir ao tocar no ícone do menu no lado direito da barra de ação. No entanto, você pode colocar itens de menu diretamente na Barra de ação como "itens de ação", para acesso instantâneo, como mostrado na figura 2. Figura 2. Imagem da barra de ação na aplicação de , com dois itens de ação do Menu de Opções, além do menu de estouro. Quando o sistema Android cria o Menu de Opções, pela primeira vez, ele chama o método oncreateoptionsmenu() da sua atividade. Substituir este método em sua atividade e preencher o Menu que é passado para o método, Menu inflando um recurso de menu como descrito acima em Inflating a Menu Resource. Por public boolean oncreateoptionsmenu(menu menu) { MenuInflater inflater = getmenuinflater(); inflater.inflate(r.menu.game_menu, menu); return true; Você também pode preencher o menu em código, usando add() para adicionar itens ao Menu. Nota: No Android 2.3 e inferiores, o sistema chama oncreateoptionsmenu() para criar o menu de opções quando o usuário 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 ação. Respondendo à ação do usuário Quando o usuário seleciona um item de menu do Menu de Opções (incluindo itens de ação na barra de ação), o sistema chama o método onoptionsitemselected() da sua atividade. Este método passa o MenuItem que o usuário 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 número inteiro ANDROID, uma visão geral Anderson Duarte de Amorim 127

128 dado ao método add()). Você pode combinar esta identificação contra itens do menu conhecidos e executar a ação apropriada. Por 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 atribuídos aos itens do menu no recurso XML. Quando um switch case manipula o item de menu, ela retorna true para indicar que a seleção de item foi tratada. Caso contrário, a declaração padrão 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, então, a super classe retorna false, mas é uma boa prática passar itens de menu não tratados para a classe super em vez de diretamente retornar false). Além 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. Então você não precisa implementar onoptionsitemselected(). Usando o atributo android:onclick, você pode especificar um método a ser chamado quando o usuário seleciona o item de menu. Sua atividade deve, então, aplicar o método especificado no android:onclick para que ele aceite um único MenuItem de parâmetro, quando o sistema chama este método, ele passa o item de menu selecionado. Dica: Se seu aplicativo contém atividades múltiplas e algumas delas oferecem o mesmo Menu de Opções, considere a criação de uma atividade que não executa nada, exceto os métodos oncreateoptionsmenu() e onoptionsitemselected(). Em seguida, estenda esta classe para cada atividade que deve compartilhar o mesmo menu de opções. Dessa forma, você tem que gerenciar apenas um conjunto de código para manipular ações de menu e cada classe descendente herda o comportamento do menu. ANDROID, uma visão geral Anderson Duarte de Amorim 128

129 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ê também pode substituir o comportamento da super classe para os itens de menu individuais. Alterando os itens de menu em tempo de execução Uma vez que a atividade é criada, o método oncreateoptionsmenu() é chamado apenas uma vez, como descrito acima. O sistema mantém e re-utiliza o Menu que você define neste método até que sua atividade seja destruída. Se você quiser mudar o menu de opções a qualquer momento após ter sido criado pela primeira vez, você deve substituir o método onprepareoptionsmenu(). Isto lhe passa o objeto Menu como ele existe atualmente. Isso é útil se você quiser remover, adicionar, desativar ou ativar itens de menu, dependendo do estado atual de sua aplicação. No Android 2.3 e inferiores, o sistema chama onprepareoptionsmenu() cada vez que o usuário abre o Menu de Opções. No Android 3.0 e superior, você deve chamar invalidateoptionsmenu() quando você desejar atualizar o menu, porque o menu está sempre aberto. O sistema irá então chamar onprepareoptionsmenu(), assim você pode atualizar os itens de menu. Nota: Você nunca deve alterar itens no menu de opções com base no View atualmente em foco. Quando estiver no modo de toque (quando o usuário não estiver usando um trackball ou d-pad), views podem não ter foco, então você nunca deve usar o foco como base para a modificação de itens do Menu de Opções. Se você quiser fornecer itens de menu que são sensíveis ao contexto para uma View, use um menu de contexto. Se você está desenvolvendo para o Android 3.0 ou superior, não se esqueça de ler também Usando a Barra de Ação. Criando um Menu de Contexto Um menu de contexto é conceitualmente semelhante ao menu exibido quando o usuário executa um "clique-direito" em um PC. Você deve usar um menu de contexto para proporcionar ao usuário o acesso às ações que pertencem a um item específico na ANDROID, uma visão geral Anderson Duarte de Amorim 129

130 interface do usuário. No Android, um menu de contexto é exibido quando o usuário 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 freqüentemente utilizados para os itens em um ListView. Quando o usuário 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 usuário que um menu de contexto está disponível animando sua cor de fundo, que faz a transição do laranja ao branco antes de abrir o menu de contexto. (O aplicativo Contatos demonstra esta característica.) 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 duração, ela exibe um menu de contexto. Para definir a aparência e comportamento do menu de contexto, substitua seus métodos de retorno do menu de contexto da atividade, oncreatecontextmenu() e oncontextitemselected(). Por exemplo, aqui está um oncreatecontextmenu() que usa o recurso de menu context_menu.xml: Registre uma public void oncreatecontextmenu(contextmenu menu, View v, ContextMenuInfo menuinfo) { super.oncreatecontextmenu(menu, v, menuinfo); MenuInflater inflater = getmenuinflater(); inflater.inflate(r.menu.context_menu, menu); Se a sua atividade usa um ListView e você deseja que todos os itens da lista forneçam um menu de contexto, registre todos os itens de um menu de contexto, passando o ListView para registerforcontextmenu(). Por exemplo, se você estiver usando uma ListActivity, registre todos os itens da lista como esta: registerforcontextmenu( getlistview() ); MenuInflater é usado para inflar o menu de contexto de um recurso de menu. (Você também pode usar o add() para adicionar itens de menu). Os parâmetros de método de retorno incluem o View que o usuário selecionou e ContextMenu.ContextMenuInfo que ANDROID, uma visão geral Anderson Duarte de Amorim 130

131 fornece informações adicionais sobre o item selecionado. Você pode usar esses parâmetros para determinar qual menu de contexto deve ser criado, mas neste exemplo, todos os menus de contexto para a atividade são os mesmos. Então, quando o usuário seleciona um item no menu de contexto, o sistema chama oncontextitemselected(). Aqui está um exemplo de como você pode manipular os itens 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 código é semelhante ao exemplo de criação de um Menu de Opções, em que getitemid() consulta o ID do item de menu selecionado e um switch corresponde ao item para as identificações que são definidos no recurso de menu. E como o exemplo do menu de opções, a declaração padrão chama a super classe no caso dela poder lidar com itens de menu não tratados aqui, se necessário. Neste exemplo, o item selecionado é um item da ListView. Para executar uma ação sobre o item selecionado, o aplicativo precisa saber o ID da lista para o item selecionado (a sua posição no ListView). Para obter o ID, o aplicativo chama getmenuinfo(), que retorna um objeto AdapterView.AdapterContextMenuInfo que inclui a identificação de lista para o item selecionado no campo id. Os métodos locais editnote() e deletenote() aceitam essa identificação da lista para executar uma ação nos dados especificados pelo ID da lista. Nota: Os itens em um menu de contexto não suportam ícones ou teclas de atalho. ANDROID, uma visão geral Anderson Duarte de Amorim 131

132 Criando Submenus Um submenu é um menu que o usuário pode abrir por selecionar um item em outro menu. Você pode adicionar um submenu a qualquer menu (com exceção de um submenu). Submenus são úteis quando seu aplicativo tem um monte de funções que podem ser organizadas em tópicos, como os itens na barra de uma aplicação 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=" <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 usuário seleciona um item do submenu, o respectivo método de retorno onitem-selected do menu pai recebe o evento. Por exemplo, se o menu acima é aplicado como um Menu de Opções, então o método onoptionsitemselected() é chamado quando um item de submenu é selecionado. Você também 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(). Outras funções do menu Aqui estão algumas outras características que podem ser aplicadas a itens do menu. Grupos de Menu Um grupo de menu é uma coleção de itens de menu que compartilham certas características. ANDROID, uma visão geral Anderson Duarte de Amorim 132

133 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 são verificados com setgroupcheckable() Você pode criar um grupo aninhando elementos <item> dentro de um elemento <group> em seu recurso de menu ou pela especificação de um ID de grupo com o método add(). Aqui está um exemplo de recurso de menu que inclui um grupo: <?xml version="1.0" encoding="utf-8"?> <menu xmlns: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 estão no grupo aparecem da mesma forma que o primeiro item que não está em um grupo - todos os três itens no menu são irmãos. No entanto, você pode modificar as características dos dois elementos do grupo, referenciando o ID do grupo e utilizando os métodos listados acima. Itens de menu verificados Um menu pode ser útil como uma interface fazendo das opções ativas e inativas, usando uma caixa de seleção para as opções de stand-alone, ou radion buttons para grupos com opções mutuamente exclusivas. A Figura 2 mostra um submenu com os itens que são verificados com radio buttons. Figura 3. Screenshot de um submenu com os itens verificados. ANDROID, uma visão geral Anderson Duarte de Amorim 133

134 Nota: Os itens de menu no menu de ícone (no menu Opções) não podem exibir uma caixa de seleção ou radio button. Se você optar por fazer os itens no menu do ícone selecionáveis, você deve manualmente indicar o estado marcado por trocar o ícone e/ou texto cada vez que ocorrem as mudanças 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 são verificados com um botão de rádio: <?xml version="1.0" encoding="utf-8"?> <menu xmlns: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 (botões de rádio) all Todos os itens podem ser verificados (caixas) none Nenhum item pode ser verificado Você pode aplicar um estado padrão verificado de um item usando o atributo android:checked no elemento <item> e alterá-lo em código com o método setchecked(). Quando um item checkable é selecionado, o sistema chama o seu método de retorno item-selected (como onoptionsitemselected()). É aqui que você deve definir o estado da caixa, pois um botão de opção ou de rádio não muda o seu estado automaticamente. ANDROID, uma visão geral Anderson Duarte de Amorim 134

135 Você pode consultar o estado atual do item (como era antes que o usuário selecionou) com ischecked() e, em seguida, definir o estado de verificado com setchecked(). Por 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ê não definir o estado de verificado dessa forma, o estado visível do item (a caixa de seleção ou botão de rádio) não vai mudar quando o usuário selecioná-lo. Quando você definir o estado, a atividade preserva o estado de verificado do item para que quando o usuário abra o menu mais tarde, o estado de verificado que você definiu esteja visível. Nota: os itens de menu verificáveis se destinam a serem usados apenas em uma sessão base e não serão salvos após a aplicação ser destruída. Se você tiver as configurações do aplicativo que você gostaria de salvar para o usuário, você deve armazenar os dados usando Preferências Compartilhadas. As teclas de atalho Para facilitar o acesso rápido aos itens do menu de opções quando o dispositivo do usuário tem um teclado físico, você pode adicionar atalhos de acesso rápido usando letras e/ou números, com os atributos android:alphabeticshortcut e android:numericshortcut no elemento <item>. Você também pode usar os métodos setalphabeticshortcut(char) e setnumericshortcut(char). Teclas de atalho não são case sensitive. Por exemplo, se você aplicar o caractere "s" como um atalho alfabético para um item "salvar" de menu, então quando o menu está aberto (ou quando o usuário segura o botão MENU) e o usuário pressiona a tecla "s", o item "Salvar" é selecionado. ANDROID, uma visão geral Anderson Duarte de Amorim 135

136 Esta tecla de atalho é exibida como uma dica no item de menu, abaixo do nome do item de menu (com exceção de itens no menu do ícone, que são exibidas somente se o usuário segura o botão MENU). Nota: as teclas de atalho para itens de menu só funcionam em dispositivos com um teclado de hardware. Atalhos não podem ser adicionado a itens de um menu de contexto. Adicionar intenções em menu dinamicamente Às vezes você quer um item de menu para iniciar uma atividade usando uma Intent (seja uma atividade em seu aplicativo ou outro aplicativo). Quando você sabe a intenção que você deseja usar e tem um item de menu específico que deve iniciar a intenção, você pode executar a intenção com startactivity() durante o apropriado método de retorno on-item-selected (como o callback onoptionsitemselected()). No entanto, se você não tiver certeza de que o dispositivo do usuário contém um aplicativo que lida com a intenção, então adicionar um item de menu que chama isso pode resultar em um item de menu que não funciona, porque a intenção pode não resolver a uma atividade. Para resolver isso, Android permite a você adicionar dinamicamente os itens do menu para o menu quando Android encontra atividades sobre o dispositivo que lidam com sua intenção. Para adicionar itens de menu baseado em atividades disponíveis que aceitam uma intenção: 1. Definir uma intenção, com a categoria CATEGORY_ALTERNATIVE e/ou CATEGORY_SELECTED_ALTERNATIVE, além de quaisquer outras exigências. 2. Chamar Menu.addIntentOptions(). Android então procura todas as aplicações que podem executar a intenção e adiciona-os ao seu menu. Se não houver aplicativos instalados que satisfazem a intenção, então não há itens de menu que sejam adicionados. ANDROID, uma visão geral Anderson Duarte de Amorim 136

137 Nota: CATEGORY_SELECTED_ALTERNATIVE é usada para segurar o elemento selecionado atualmente na tela. Assim, ele só deve ser utilizado para a criação de um menu em oncreatecontextmenu(). Por 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 intenção de filtro correspondente a intenção definida um item de menu é adicionado, utilizando o valor na intenção do filtro android:label como o título do item de menu e o ícone do aplicativo como o item ícone do menu. O método addintentoptions() retorna o número 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. Permitindo a sua atividade a ser adicionada para outros menus Você também pode oferecer os serviços de sua atividade para outras aplicações, para que seu aplicativo possa ser incluído no menu de outros (inverter os papéis descritos acima). ANDROID, uma visão geral Anderson Duarte de Amorim 137

138 Para ser incluído em outros menus de aplicativos, você precisa definir uma intenção de filtro, como de costume, mas não se esqueça de incluir o CATEGORY_ALTERNATIVE e/ou CATEGORY_SELECTED_ALTERNATIVE para o filtro de categoria intenções. Por exemplo: <intent-filter label="resize Image">... <category android:name="android.intent.category.alternative" /> <category android:name="android.intent.category.selected_alternative" />... </intent-filter> Leia mais sobre como escrever filtros de intenção em Intents and Intents Filters. ANDROID, uma visão geral Anderson Duarte de Amorim 138

139 Usando a barra de ação A barra de ação é um widget para atividades que substitui a tradicional barra de título no topo da tela. Por padrão, a barra de ação inclui o logotipo da aplicação do lado esquerdo, seguido do título da atividade, e todos os itens disponíveis no menu Opções no lado direito. A Barra de ação oferece vários recursos úteis, incluindo a capacidade de: Exibir itens do Menu de Opções diretamente na Barra de ação, como "itens de ação" - fornecendo acesso imediato às ações-chave dos usuários. Os itens de menu que não aparecem como itens de ação são colocados no menu de estouro, revelado por uma lista suspensa na barra de ações. Fornecer as guias para navegar entre os fragmentos. Forneça uma lista drop-down para a navegação. Fornecer interativas "visões de ação" no lugar de itens de ação (como uma caixa de pesquisa). Figura 1. Uma imagem da barra de ação na aplicação de , contendo itens de ação para compor novo e atualizar a caixa de entrada. Adicionando a barra de ação A barra de ação é incluída por padrão em todas as atividades que visam o Android 3.0 ou superior. Mais especificamente, todas as atividades que usam o novo tema "holográfico" incluem a barra de ação, e qualquer aplicação que tem como alvo o Android 3.0 automaticamente recebe esse tema. Uma aplicação é 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: ANDROID, uma visão geral Anderson Duarte de Amorim 139

140 <manifest xmlns: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 aplicação requer uma versão mínima do API Nível 4 (Android 1.6), mas também atinge API Nível 11 (Android 3.0). Dessa forma, quando o aplicativo é instalado em um dispositivo rodando Android 3.0 ou superior, o sistema aplica o tema holográfico para cada atividade, e assim, cada atividade inclui a Barra de Ações. No entanto, se você quiser usar APIs de Barra de Ações, tais como guias para adicionar ou modificar estilos da barra de ação, você precisa definir o android:minsdkversion para "11", assim você pode acessar a classe ActionBar. Removendo a barra de ação Se você quiser remover a barra de ação 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 ação, defina a propriedade de estilo android:windowactionbar false. Você também pode ocultar a barra de ação em tempo de execução chamando hide(), e depois mostrá-la novamente chamando show(). Por exemplo: ActionBar actionbar = getactionbar(); actionbar.hide(); Quando a barra de ação se esconde, o sistema ajusta seu conteúdo das atividades para preencher todo o espaço disponível na tela. Nota: Se você remover a Barra de ação usando um tema, a janela não vai permitir a barra de ação a todos, então você não pode adicioná-la em tempo de execução - chamar getactionbar() irá retornar null. ANDROID, uma visão geral Anderson Duarte de Amorim 140

141 Adicionando itens de ação Um item de ação que é simplesmente um item do menu de opções que você declara deve aparecer diretamente na barra de ações. Um item de ação pode incluir um ícone e/ou texto. Se um item de menu não aparece como um item de ação, o sistema coloca no menu de estouro, que o usuário pode abrir com o ícone do menu no lado direito da barra de ação. Figura 2. Uma barra de ação com dois itens de ação e menu de estouro. Quando a primeira atividade começa, o sistema preenche a barra de ação e menu de estouro chamando oncreateoptionsmenu() para sua atividade. Conforme discutido no guia para a criação de menus, é neste método callback que você define o menu de opções para a atividade. Você pode especificar um item de menu para aparecer como um item de ação, se não houver espaço 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 ação para um acesso rápido apenas se houver espaço disponível para ele. Se não houver espaço suficiente, o item é colocado no menu de transbordamento (revelado pelo ícone do menu no lado direito da barra de ação). Você também pode declarar um item de menu para aparecer como um item de ação a partir do seu código de aplicativo, chamando setshowasaction() no MenuItem e passando SHOW_AS_ACTION_IF_ROOM. Se o item de menu fornece tanto um título como um ícone, então o item de ação mostra apenas o ícone por default. Se você quiser incluir o texto do item de ação, adicione a flag "with text": em XML, adicionar withtext para o atributo android:showasaction ou, no código do aplicativo, use a flag SHOW_AS_ACTION_WITH_TEXT ao chamar setshowasaction(). A Figura 2 mostra uma barra de ação que tem dois itens de ação 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 ação em um arquivo de recurso de menu: ANDROID, uma visão geral Anderson Duarte de Amorim 141

142 <?xml version="1.0" encoding="utf-8"?> <menu xmlns:android=" <item android:showasaction="ifroom withtext" /> </menu> Neste caso, tanto as flags ifroom e withtext estão definidas, de modo que quando este item aparece como um item de ação, inclui o texto do título, juntamente com o ícone. Um item de menu colocado na barra de ação dispara os mesmos métodos de callback que outros itens do menu de opções. Quando o usuário seleciona um item de ação, 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 método onoptionsitemselected()é chamado para esse fragmento. No entanto, a atividade tem a chance de manipulá-lo primeiro, então o sistema chama onoptionsitemselected() da atividade antes de chamar o fragmento. Você também pode declarar um item que sempre aparece como um item de ação, mas você deve evitar fazê-lo, porque ele pode criar uma interface confusa se houver muitos itens de ação e também podem colidir com outros elementos na barra de ações. Usando o ícone do aplicativo como um item de ação Por padrão, o ícone do aplicativo aparece na barra de ações, no lado esquerdo. Ele também responde à interação do usuário (quando o usuário toca, ele responde visualmente do mesmo jeito que os itens de ação) e que é sua responsabilidade fazer algo quando o usuário toca-os. Figura 3. Barra de ação de , com o ícone do aplicativo no lado esquerdo. O comportamento deve ser normal para a sua aplicação para regressar à "HOME" à atividade ou ao estado inicial (como quando a atividade não mudou, mas os fragmentos foram alterados) quando o usuário toca o ícone. Se o usuário já está em casa ou no estado inicial, então você não precisa fazer nada. ANDROID, uma visão geral Anderson Duarte de Amorim 142

143 Quando o usuário toca o ícone, o sistema chama o método onoptionsitemselected() de sua atividade com o ID android.r.id.home. Então, você precisa adicionar uma condição para o seu método onoptionsitemselected() para receber android.r.id.home e executar a ação apropriada, como iniciar a atividade inicial ou remover recentes transações 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á começando já existe na tarefa atual, então todas as atividades em cima dela são destruídas e essa é trazida para frente. Você deve favorecer essa abordagem, porque ir para "HOME" é uma ação que é equivalente a "voltar atrás" e você geralmente não deve criar uma nova instância da atividade inicial. Caso contrário, você pode acabar com uma longa pilha de atividades na tarefa atual. Por exemplo, aqui está uma implementação do onoptionsitemselected() que retorna para a aplicação da "HOME" de 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); Usando o ícone do aplicativo para navegar "para cima" Você também pode usar o ícone do aplicativo para oferecer uma navegação "para cima" para o usuário. Isto é especialmente útil quando o aplicativo é composto por atividades que geralmente aparecem em uma certa ordem e se pretende facilitar a habilidade do usuário para navegar na hierarquia de atividade. 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 visão geral Anderson Duarte de Amorim 143

144 na atividade corrente). Tudo que você precisa fazer para indicar ao usuário que o comportamento é diferente é definir a barra de ação para "mostrar a HOME como para cima ". Você pode fazer isso chamando setdisplayhomeasupenabled(true) na barra de ações 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 ação "para protected void onstart() { super.onstart(); ActionBar actionbar = this.getactionbar(); actionbar.setdisplayhomeasupenabled(true); Então, sua atividade deve responder ao usuário 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ê não cria uma nova instância da atividade do pai, se já existe um. Adicionando uma exibição de ação Figura 5. Uma visão de ação com um widget SearchView. Uma exibição de ação é um widget que aparece na barra de ação como um substituto para um item de ação. Por exemplo, se você tem um item no menu opções para "Busca", você pode adicionar uma exibição de ação para o item que fornece um widget SearchView na barra de ação sempre que o item é ativado como um item de ação. Ao adicionar uma visão de ação para um item de menu, é importante que você ainda permita ao item se comportar como um item de menu normal quando ela não aparece na barra de ações. Por exemplo, um item de menu para realizar uma pesquisa deve, por padrão, abrir a janela de pesquisa do Android, mas se o item é colocado na barra de ação, a visão de ação aparece com um widget SearchView. A Figura 5 mostra um exemplo do SearchView em uma visão de ação. ANDROID, uma visão geral Anderson Duarte de Amorim 144

145 A melhor forma de declarar uma visão de ação 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=" <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=" <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 apareça como uma visão de ação quando o room está disponível. Se necessário, no entanto, pode forçar o item que sempre apareça como uma visão de ação, definindo android:showasaction para "always". Agora, quando o item de menu é exibido como um item de ação, esta vista de ação aparece em vez do ícone e/ou texto do título. No entanto, se não houver espaço suficiente na barra de ação, o item aparece no menu de estouro como um item de menu normal e você deve responder a ela a partir do método de retorno onoptionsitemselected(). Quando a primeira atividade começa, o sistema preenche a barra de ação e menu de estouro chamando oncreateoptionsmenu(). Depois de ter inflado seu menu neste método, você pode adquirir elementos em uma visão de ação (talvez a fim de anexar ouvintes) chamando finditem() com o ID do item de menu, então getactionview() no ANDROID, uma visão geral Anderson Duarte de Amorim 145

146 MenuItem retornado. Por exemplo, o widget de busca do modelo acima é adquirido como 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 Figura 6. Screenshot de abas na barra de ação, do modelo de aplicação do Honeycomb Gallery. A Barra de ação pode exibir guias que permitem ao usuário navegar entre diferentes fragmentos na atividade. Cada guia pode incluir um título e/ou um ícone. Para começar, o esquema deve incluir um View, em que cada Fragment associado com uma guia é exibida. Tenha certeza de que tem uma identificação que pode ser usada para fazer referência a ela em seu código. Para adicionar guias para a barra de ações: 1. Criar uma aplicação de ActionBar.TabListener para manipular os eventos de interação na barra de guias de ação. Você deve implementar todos os métodos: ontabselected(), ontabunselected(), e ontabreselected(). Cada método de retorno passa a ActionBar.Tab que recebeu o evento e um FragmentTransaction para você efetuar as transações do fragmento (adicionar ou remover fragmentos). ANDROID, uma visão geral Anderson Duarte de Amorim 146

147 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 = public void ontabselected(tab tab, FragmentTransaction ft) { ft.add(r.id.fragment_content, mfragment, public void ontabunselected(tab tab, FragmentTransaction ft) { public void ontabreselected(tab tab, FragmentTransaction ft) { // do nothing Esta implementação 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 não se esqueça 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 ação: a. Criar uma nova ActionBar.Tab chamando newtab() na ActionBar. b. Acrescentar o texto do título e/ou um ícone para o guia, chamando settext() e/ou seticon(). Dica: Esses métodos retornam a mesma instância ActionBar.Tab, assim você pode encadear as chamadas juntas. ANDROID, uma visão geral Anderson Duarte de Amorim 147

148 c. Declare o ActionBar.TabListener para usar a guia por meio de um exemplo de sua aplicação para settablistener(). 5. Adicione cada ActionBar.Tab à barra de ação, chamando addtab() na ActionBar e passe a ActionBar.Tab. Por exemplo, o código a seguir combina as etapas 2-5 para criar duas guias e adicionálas à Barra de 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 método 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 exibição 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(). Atenção: Você não deve chamar commit() para essas operações, o sistema chama-o para você e pode lançar uma exceção se você chamá-lo. Você também não pode adicionar essas transações 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 usuário retorna à sua aplicação, você pode ANDROID, uma visão geral Anderson Duarte de Amorim 148

149 abrir a guia. Quando é hora de salvar o estado, você pode consultar a atual guia selecionada com getselectednavigationindex(). Isso retorna a posição do índice da guia selecionada. Atenção: É importante que você salve o estado de cada fragmento quando necessário, pois quando o usuário alterna fragmentos com as guias, e em seguida, retorna a um fragmento anterior, aparece o caminho que ele deixou. Para obter informações sobre como salvar o seu estado de fragmento, consulte o guia do desenvolvedor sobre Fragmentos. Adicionando de navegação drop-down Como um outro modo de navegação em sua atividade, você pode fornecer uma lista suspensa na barra de ações. Por exemplo, a lista drop-down pode fornecer os meios alternativos para classificar o conteúdo da atividade ou mudar a conta do usuário. Aqui está uma lista rápida de medidas para permitir a navegação drop-down: 1. Criar um SpinnerAdapter que fornece a lista de itens selecionáveis para o dropdown e a disposição para usar ao desenhar cada item na lista. 2. Implementar ActionBar.OnNavigationListener para definir o comportamento quando o usuário seleciona um item da lista. 3. Habilitar o modo de navegação para a barra de ação com setnavigationmode(). Por exemplo: ActionBar actionbar = getactionbar(); actionbar.setnavigationmode(actionbar.navigation_mode_list); Nota: Você deve executar isto durante a sua atividade do método oncreate(). 4. Em seguida, defina o retorno para a lista drop-down com setlistnavigationcallbacks(). Por exemplo: actionbar.setlistnavigationcallbacks(mspinneradapter, mnavigationcallback); Este método tem a sua SpinnerAdapter e ActionBar.OnNavigationListener. Essa é a configuração básica. No entanto, a implementação da SpinnerAdapter e ActionBar.OnNavigationListener é onde a maioria do trabalho é feito. Há muitas ANDROID, uma visão geral Anderson Duarte de Amorim 149

150 maneiras que você pode aplicar isto para definir a funcionalidade para o seu drop-down de navegação e implementar vários tipos de SpinnerAdapter além do escopo deste documento (você deve referenciar para a classe SpinnerAdapter para obter mais informações). No entanto, abaixo há um exemplo simples para um SpinnerAdapter e ActionBar.OnNavigationListener para você começar. Exemplo de SpinnerAdapter e OnNavigationListener SpinnerAdapter é um adaptador que fornece dados para um widget spinner, como a lista drop-down na barra de ações. SpinnerAdapter é uma interface que você pode implementar, mas Android inclui algumas implementações úteis que você pode estender, como ArrayAdapter e SimpleCursorAdapter. Por exemplo, aqui está uma maneira fácil de criar um SpinnerAdapter usando a implementação de ArrayAdapter, que usa uma matriz de string como fonte de dados: SpinnerAdapter mspinneradapter = ArrayAdapter.createFromResource(this, R.array.action_list, android.r.layout.simple_spinner_dropdown_item); O método createfromresource() usa três parâmetros: a aplicação Context, a identificação 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, porém, você precisa criar o OnNavigationListener. A implementação do ActionBar.OnNavigationListener é onde você lida com as mudanças de fragmento ou outras modificações à sua atividade quando o usuário seleciona um item da lista drop-down. Há apenas um método callback para implementar o receptor: onnavigationitemselected(). ANDROID, uma visão geral Anderson Duarte de Amorim 150

151 O método onnavigationitemselected() recebe a posição do item na lista e um ID de único item fornecido pela SpinnerAdapter. Aqui está um exemplo que instancia uma implementação anônima 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 = 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 instância de OnNavigationListener está completo e agora você pode chamar setlistnavigationcallbacks() (na etapa 4), passando o ArrayAdapter e este OnNavigationListener. Neste exemplo, quando o usuário 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 seqüência de caracteres usado para identificar o fragmento na lista drop-down. ANDROID, uma visão geral Anderson Duarte de Amorim 151

152 Aqui está um olhar da classe ListContentFragment que define cada fragmento neste exemplo: public class ListContentFragment extends Fragment { private String 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 = 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 ação A barra de ação é o título do seu aplicativo e um ponto de interação primário para os usuários, então você pode querer modificar alguns em seu projeto, a fim de torná-lo sentir mais integrado com o design do aplicativo. Há várias maneiras que você pode fazer isso se quiser. Para modificações simples para o ActionBar, você pode usar os métodos a seguir: setbackgrounddrawable() Define um drawable para usar como fundo da barra de ação. O drawable deve ser uma imagem Nine-patch, uma forma, ou uma cor sólida, para que o sistema pode redimensionar a drawable com base no tamanho da barra de ação (você não deve usar uma imagem bitmap de tamanho fixo). setdisplayuselogoenabled() Permite o uso de uma imagem alternativa (a "logo") na barra de ação, em vez do ícone do aplicativo padrão. Um logotipo é muitas vezes uma imagem mais ampla, mais detalhada que representa a aplicação. Quando isso estiver ativado, o ANDROID, uma visão geral Anderson Duarte de Amorim 152

153 sistema utiliza a imagem do logotipo definido para a aplicação (ou a atividade individual) no arquivo de manifesto, com o atributo android:logo. O logotipo será redimensionado, conforme necessário para ajustar a altura da barra de ação. (Melhores práticas é projetar o logotipo com o mesmo tamanho do ícone do aplicativo.) Para personalizações mais complexas, você pode usar estilos e temas do Android para remodelar sua barra de ação de várias maneiras. A Barra de ação tem dois temas padrão, "dark" e "light". O tema escuro é aplicado com o tema padrão holográfico, 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 Ações. Algumas das propriedades da barra de ação você pode personalizar incluindo o seguinte: android:actionbartabstyle Estilo de abas na barra de ação. android:actionbartabbarstyle Estilo para a barra que aparece abaixo das abas na barra de ação. android:actionbartabtextstyle Estilo para o texto nos separadores. android:actiondropdownstyle Estilo para a lista drop-down utilizado para o menu de navegação de transbordamento e drop-down. android:actionbuttonstyle Estilo para a imagem de fundo usado para os botões na barra de ação. ANDROID, uma visão geral Anderson Duarte de Amorim 153

154 Por exemplo, aqui está um arquivo de recurso que define um tema personalizado para a barra de ação, baseado no tema padrão 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, não selecionado), o recurso drawable utilizado deve ser uma lista de estado drawable. Também é certo que o tema declara um tema principal, da qual ele herda todos os estilos não 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"... /> Além disso, se você quer criar um tema personalizado para a sua atividade que remove a barra de ação completamente, use os atributos de estilo a seguir: ANDROID, uma visão geral Anderson Duarte de Amorim 154

155 android:windowactionbar Defina esta propriedade de estilo como false para remover a barra de ações. android:windownotitle Defina esta propriedade de estilo como true também para remover a barra de título tradicional. ANDROID, uma visão geral Anderson Duarte de Amorim 155

156 Criando caixas de diálogo Uma caixa de diálogo é geralmente uma pequena janela que aparece na frente da atividade atual. A atividade em causa perde o foco e o diálogo aceita todas as interações do usuário. Os diálogos são normalmente utilizados para as notificações que devem interromper o usuário e para executar tarefas curtas que se relacionam diretamente com a aplicação em curso (como uma barra de progresso ou um prompt de login). A classe Dialog é a classe base para a criação de diálogos. No entanto, você geralmente não deve instanciar um Dialog diretamente. Em vez disso, você deve usar uma das seguintes subclasses: AlertDialog Uma caixa de diálogo que pode gerenciar zero, um, dois ou três botões, e/ou uma lista de itens selecionáveis que podem incluir caixas de verificação ou botões de rádio. O AlertDialog é capaz de construir a maioria das interfaces de diálogo com o usuário e é o tipo de caixa de diálogo sugerido. ProgressDialog Uma caixa de diálogo que exibe uma roda de progresso ou barra de progresso. Porque é uma extensão do AlertDialog, ele também suporta botões. DatePickerDialog Um diálogo que permite que o usuário selecione uma data. TimePickerDialog Um diálogo que permite ao usuário selecionar um tempo. Se você quiser personalizar a sua própria caixa de diálogo, você pode estender a base Dialog ou qualquer objeto das subclasses acima e definir um novo layout. Mostrando uma caixa de diálogo Um diálogo é sempre criado e exibido como parte de uma Activity. Você normalmente deve criar diálogos de dentro do método de retorno oncreatedialog(int) da sua atividade. Quando você usa esta chamada, o sistema Android gerencia automaticamente ANDROID, uma visão geral Anderson Duarte de Amorim 156

157 o estado de cada diálogo e os ganchos para a atividade, efetivamente tornando-o o "dono" de cada diálogo. Como tal, cada diálogo herda algumas propriedades da atividade. Por exemplo, quando uma janela é aberta, a tecla Menu revela o menu de opções definidas para a atividade e as teclas de volume modificam o fluxo de áudio usado pela atividade. Nota: Se você decidir criar um diálogo fora do método oncreatedialog(), não 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 número inteiro que identifica a caixa de diálogo 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 instância do Dialog. Neste método de retorno é passado o mesmo ID que você passou para showdialog(int). Depois de criar o diálogo, retorne o objeto no final do método. Antes que o diálogo ser exibido, o Android também chama o método callback opcional onpreparedialog(int, Dialog). Defina nesse método se você deseja alterar as propriedades da caixa de diálogo cada vez que for aberta. Este método é chamado toda vez que uma caixa de diálogo é aberta, enquanto oncreatedialog(int) é chamado apenas na primeira vez que uma caixa de diálogo é aberta. Se você não definir onpreparedialog(), então o diálogo continuará a ser o mesmo que era o tempo anterior que foi aberto. Este método também passa o ID do diálogo, além de um diálogo do objeto que você criou na oncreatedialog(). A melhor maneira de definir os métodos de retorno oncreatedialog(int) e onpreparedialog(int, Dialog) é com uma instrução switch que verifica o parâmetro id que é passado para o método. Cada caso deve verificar se há uma identificação única de diálogo e, em seguida, criar e definir o respectivo diálogo. Por exemplo, imagine um jogo que usa dois diálogos distintos: um para indicar que o jogo tem uma pausa e outra para indicar que o jogo acabou. Primeiro, defina um ID de número inteiro para cada caixa de diálogo: static final int DIALOG_PAUSED_ID = 0; static final int DIALOG_GAMEOVER_ID = 1; ANDROID, uma visão geral Anderson Duarte de Amorim 157

158 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, não há nenhum código dentro da declaração de caso, porque o procedimento para a definição de seu diálogo está fora do escopo desta seção. Quando é hora de mostrar um dos diálogos, chame showdialog(int) com o ID de um diálogo: showdialog(dialog_paused_id); Dispensar um diálogo Quando estiver pronto para fechar o diálogo, você pode descartá-lo chamando dismiss() no objeto Dialog. Se necessário, você também pode chamar dismissdialog(int) da atividade, o que efetivamente chama dismiss() na caixa de diálogo para você. Se você estiver usando oncreatedialog(int) para gerir o seu estado de diálogos (como discutido na seção anterior), então cada vez que o diálogo é indeferido, o estado do objeto de diálogo é mantido pela atividade. Se você decidir que você não precisa mais desse objeto ou é importante que o estado esteja limpo, então você deve chamar removedialog(int). Isto irá remover todas as referências internas ao objeto e se o diálogo está mostrando, vai dispensá-lo. Usando demissão de receptores Se você quiser que seu aplicativo execute alguns procedimentos no momento em que um diálogo é dispensado, então você deve anexar um receptor on-dismiss no seu diálogo. ANDROID, uma visão geral Anderson Duarte de Amorim 158

159 Primeiro defina a interface DialogInterface.OnDismissListener. Essa interface possui apenas um método, ondismiss(dialoginterface), que será chamado quando o diálogo for descartado. Depois, passe a sua implementação OnDismissListener para setondismisslistener(). No entanto, note que os diálogos também podem estar "cancelados". Este é um caso especial que indica que o diálogo foi explicitamente cancelado por parte do usuário. Isso ocorrerá se o usuário pressiona o botão "BACK " para fechar a janela, ou se a caixa de diálogo solicita explicitamente cancel() (talvez a partir de um botão "Cancelar" na caixa de diálogo). Quando um diálogo for cancelado, o OnDismissListener ainda será notificado, mas se você gostaria de ser informado de que o diálogo foi expressamente cancelado (e não dispensado normalmente), então você deve registrar um DialogInterface.OnCancelListener com setoncancellistener(). Criando um AlertDialog Um AlertDialog é uma extensão da classe Dialog. É capaz de construir a maioria das interfaces de usuário de diálogo e é o tipo de diálogo sugerido. Você deve usá-lo para o diálogo que usam qualquer uma das seguintes características: Um título Uma mensagem de texto Um, dois ou três botões Uma lista de itens selecionáveis (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 métodos públicos de classe para definir todas as propriedades AlertDialog. Depois que está finalizado com o construtor, recupere o objeto AlertDialog com create(). Os tópicos a seguir mostram como definir várias propriedades do AlertDialog usando a classe AlertDialog.Builder. Se você usar qualquer um dos seguintes códigos de exemplo dentro do seu método de retorno oncreatedialog(), você pode retornar o objeto resultante de diálogo para exibir o diálogo. ANDROID, uma visão geral Anderson Duarte de Amorim 159

160 Adicionando botões Para criar um AlertDialog com botões lado a lado, como a mostrada na imagem à direita, use o método 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 diálogo com setmessage(charsequence). Então, comece método de encadeamento e definir a janela para não ser cancelado (por isso o usuário não poderá fechar o diálogo com o botão traseiro) com setcancelable(boolean). Para cada botão, use um dos set...button() métodos, como setpositivebutton(), que aceita o nome do botão e um DialogInterface.OnClickListener que define as medidas a tomar quando o usuário seleciona o botão. Nota: Você só pode adicionar um botão de cada tipo à AlertDialog. Ou seja, você não pode ter mais de um botão "positivo". Isso limita o número de botões possíveis para três: positivo, neutro e negativo. Estes nomes são tecnicamente irrelevantes para a funcionalidade real de seus botões, mas deve ajudá-lo a acompanhar o que faz o quê. ANDROID, uma visão geral Anderson Duarte de Amorim 160

161 Adicionando uma lista Para criar um AlertDialog com uma lista de itens selecionáveis como o mostrado à esquerda, use o método 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 título para o diálogo com settitle(charsequence). Em seguida, adicione uma lista de itens selecionáveis com setitems(), que aceita um conjunto de itens a serem exibidos e um DialogInterface.OnClickListener que define as medidas a tomar quando o usuário seleciona um item. Adicionando caixas de seleção e botões de rádio Para criar uma lista de itens de escolha múltipla (caixas) ou itens de escolha única (botões de rádio) dentro do diálogo, use os métodos setmultichoiceitems() e setsinglechoiceitems(), respectivamente. Se você criar uma destas listas selecionáveis no método de retorno oncreatedialog(), o Android gerencia o estado da lista para você. Contanto que a atividade esteja ativa, o diálogo se lembra dos itens que foram previamente selecionados, mas quando o usuário sai da atividade, a seleção está perdida. ANDROID, uma visão geral Anderson Duarte de Amorim 161

162 Nota: Para salvar a seleção quando o usuário deixa ou faz pausa na atividade, você deve salvar e restaurar corretamente a configuração de todo o ciclo de vida de atividade. Para salvar permanentemente as seleções, mesmo quando o processo de atividade é completamente parado, você precisa salvar as configurações com uma das técnicas de Armazenamento de Dados. Para criar um AlertDialog com uma lista de itens de escolha simples, como a mostrada acima, use o mesmo código do exemplo anterior, mas substitua o método 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 parâmetro no método setsinglechoiceitems() é um valor inteiro para o checkeditem, que indica a posição de lista com base zero do item selecionado padrão. Use "-1" para indicar que nenhum item deve ser selecionado por padrão. Criar um ProgressDialog A ProgressDialog é uma extensão da classe AlertDialog que pode exibir uma animação 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 progressão definida. O diálogo também pode fornecer botões, como um de cancelar um download. Abrir uma janela de progresso pode ser tão simples como chamar ProgressDialog.show(). Por exemplo, o diálogo mostrado acima pode ser facilmente alcançado sem gerenciar o diálogo através da chamada oncreatedialog(int), conforme mostrado abaixo: ProgressDialog dialog = ProgressDialog.show(MyActivity.this, "", "Loading. Please wait...", true); ANDROID, uma visão geral Anderson Duarte de Amorim 162

163 O primeiro parâmetro é a aplicação Context, o segundo é um título para o diálogo (vazio), o terceiro é a mensagem e o último parâmetro é se o progresso é indeterminado (isso só é relevante quando cria uma barra de progresso, que é discutido na próxima seção). O estilo padrão de um diálogo de progresso é a roda. Se você deseja criar uma barra de progresso que mostra o progresso do carregamento com granularidade, mais código é necessário, como será discutido na próxima seção. Mostrando uma barra de progresso Para mostrar a progressão com uma barra de progresso animada: 1. Inicialize o ProgressDialog com o construtor da classe, ProgressDialog(Context). 2. Defina o estilo de progressos para "STYLE_HORIZONTAL" com setprogressstyle(int) e defina as outras propriedades, como a mensagem. 3. Quando estiver pronto para mostrar o diálogo, 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 concluída ou incrementprogressby(int) com um valor incremental para adicionar à porcentagem total concluída até agora. Por exemplo, sua configuração pode se parecer como esta: ProgressDialog progressdialog; progressdialog = new ProgressDialog(mContext); progressdialog.setprogressstyle(progressdialog.style_horizontal); progressdialog.setmessage("loading..."); progressdialog.setcancelable(false); ANDROID, uma visão geral Anderson Duarte de Amorim 163

164 A configuração é simples. A maior parte do código necessário para criar um diálogo de progresso está realmente envolvida no processo que atualizá-lo. Você pode achar que é necessário criar um segundo thread em sua aplicação para este trabalho e, em seguida, relatar o progresso de volta à atividade do thread de interface do usuário com um Handler do objeto. Se você não está familiarizado com o uso de threads adicionais com um manipulador, vejo o exemplo abaixo, que utiliza um segundo thread para incrementar um diálogo 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 através 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) { ANDROID, uma visão geral Anderson Duarte de Amorim 164

165 switch(id) { case PROGRESS_DIALOG: progressdialog = new ProgressDialog(NotificationTest.this); progressdialog.setprogressstyle(progressdialog.style_horizontal); progressdialog.setmessage("loading..."); return progressdialog; default: return 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; ANDROID, uma visão geral Anderson Duarte de Amorim 165

166 mhandler.sendmessage(msg); total++; /* sets the current state for the thread, * used to stop the thread */ public void setstate(int state) { mstate = state; Criando uma caixa de diálogo personalizada Se você quiser um projeto personalizado para um diálogo, você pode criar seu próprio layout para a janela de diálogo com elementos de layout e de widget. Depois de definido o layout, passar o objeto View raiz ou identificação do recurso de layout para setcontentview(view). Por exemplo, para criar o diálogo mostrado acima: 1. Criar um layout XML salvo como custom_dialog.xml: <LinearLayout xmlns:android=" android:id="@+id/layout_root" android:orientation="horizontal" android:layout_width="fill_parent" android:layout_height="fill_parent" android:padding="10dp" > <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="#fff" /> </LinearLayout> Esta XML define um ImageView e um TextView dentro de um LinearLayout. 2. Definir o layout acima como o conteúdo da View da caixa de diálogo e definir o conteúdo dos elementos ImageView e TextView: ANDROID, uma visão geral Anderson Duarte de Amorim 166

167 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 diálogo, definir o layout personalizado de conteúdo como conteúdo da View da caixa de diálogo com setcontentview(int), passando o ID do recurso de layout. Agora que o diálogo tem um layout definido, você pode capturar objetos View do layout com findviewbyid(int) e modificar seu conteúdo. 3. É isso aí. Agora você pode mostrar o diálogo como descrito em Mostrando um Diálogo. Um diálogo feito com a classe de diálogo base deve ter um título. Se você não chamar settitle(), o espaço usado para o título continua vazio, mas ainda visível. Se você não quer um título a todos, então você deve criar o seu diálogo personalizado usando a classe AlertDialog. No entanto, porque um AlertDialog é mais fácilmente criado com o AlertDialog.Builder, você não tem acesso ao método setcontentview(int) utilizado acima. Em vez disso, você deve usar setview(view). Este método aceita um objeto View, por isso é necessário 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 parâmetro é o ID do recurso layout e o segundo é a identificação da View raiz. Neste ponto, você pode usar o layout inflado para encontrar objetos View no layout e definir o conteúdo dos elementos ImageView e TextView. Então instanciar o AlertDialog.Builder e definir o layout inflados para o diálogo 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) ANDROID, uma visão geral Anderson Duarte de Amorim 167

168 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 botões geridos, listas selecionáveis, um título, um ícone e assim por diante. ANDROID, uma visão geral Anderson Duarte de Amorim 168

169 Manipulando eventos de UI No Android, há mais de um caminho para interceptar os eventos de interação do usuário com seu aplicativo. Ao considerar os eventos dentro de sua interface de usuário, a abordagem consiste em capturar os eventos do objeto View específico com que o usuário 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 vários métodos de retorno públicos que pareçam úteis para eventos de UI. Esses métodos são chamados pelo framework Android, quando a respectiva ação ocorre no objeto. Por exemplo, quando uma exibição (como um botão) é tocada, o método ontouchevent() é chamado no objeto. No entanto, a fim de interceptar isso, você deve estender a classe e substituir o método. No entanto, estender cada objeto View, a fim de lidar com um evento como esse não seria prático. É por isso que a classe View também contém uma coleção de interfaces aninhadas com callbacks que podem ser muito mais fácil de definir. Essas interfaces, chamadas de event listeners, são o seu bilhete para capturar a interação do usuário com sua interface do usuário. Enquanto você vai utilizar mais comumente os ouvintes de evento para receber a interação do usuário, 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 padrão para sua classe usando a classe de manipuladores de eventos. Os ouvintes de eventos Um receptor de evento é uma interface na classe View que contém um método de retorno único. Esses métodos serão chamados pelo framework Android quando o View para o receptor tenha sido registado é desencadeada pela interação do usuário com o item na interface do usuário. ANDROID, uma visão geral Anderson Duarte de Amorim 169

170 Incluído nas interfaces de ouvinte de evento são os métodos de retorno seguintes: onclick() A partir do View.OnClickListener. É chamado quando o usuário toca o item (quando em modo de tocar), ou incide sobre o item com a navegação por teclas ou trackball e pressiona a tecla "enter" ou pressiona o trackball. onlongclick() De View.OnLongClickListener. Isto é chamado quando o usuário toca e prende o item (quando no modo de tocar), ou incide sobre o item com a navegação por teclas ou trackball e pressiona e mantém a tecla "enter" ou pressiona e mantém pressionada a trackball (por um segundo). onfocuschange() De View.OnFocusChangeListener. Isto é chamado quando o usuário navega para ou longe do ponto, utilizando atalhos ou trackball. onkey() De View.OnKeyListener. Isto é chamado quando o usuário está centrado sobre o item e pressiona ou solta uma tecla no dispositivo. ontouch() De View.OnTouchListener. Isto é chamado quando o usuário executa uma ação 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 construído (como o resultado de um "clique longo" sustentado). Esses métodos são os únicos habitantes da suas respectivas interfaces. Para definir um desses métodos e lidar com seus eventos, implemente a interface aninhada em sua ANDROID, uma visão geral Anderson Duarte de Amorim 170

171 atividade ou defina-a como uma classe anônima. Em seguida, passe uma instância da sua aplicação com os respectivos métodos View.set...Listener(). (Por exemplo, chamar setonclicklistener() e passá-la a implementação do OnClickListener). O exemplo abaixo mostra como registrar um receptor no clique de um botão. // 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ê também pode achar mais conveniente para implementar OnClickListener como parte de sua atividade. Isso irá evitar a carga horária extra e alocação 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 não tem valor de retorno, mas alguns métodos ouvintes devem retornar um boolean. A razão 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 não 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ê não tem ANDROID, uma visão geral Anderson Duarte de Amorim 171

172 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 não 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ê não 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 várias ações que se sucedem. Então, se você retornar falso quando o evento de ação abaixo é recebido, você indica que não consumiram o evento e também não estão interessados em ações subseqüentes deste evento. Assim, você não será chamado para outras ações dentro do evento, como um gesto do dedo, ou um eventual evento de ação acima. Lembre-se que os principais eventos são sempre entregues para a corrente View em foco. Eles são 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, então você pode ver o curso de eventos através do método dispatchkeyevent(). Como alternativa à captura de eventos-chave através da sua view, você também 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 padrão apropriados a partir da definição de segunda classe. Como tal, retornando true destes ouvintes de evento irá parar a propagação do evento para ouvintes de eventos e também irá bloquear o retorno de chamada para o manipulador de eventos padrão no View. Então, 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, então você vai ser capaz de definir vários métodos de retorno usados como manipuladores de eventos padrão. No documento Construindo Componentes Personalizados, você aprenderá a ver alguns dos retornos comuns usados para tratamento de eventos, incluindo: ANDROID, uma visão geral Anderson Duarte de Amorim 172

173 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 métodos que você deve estar ciente de que não são 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 métodos: 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 são distribuídos aos views filhos. ViewParent.requestDisallowInterceptTouchEvent(boolean) - Chamar esta em cima de um pai view para indicar que ela não deve interceptar eventos de contato com onintercepttouchevent(motionevent). Modo de toque Quando um usuário está navegando uma interface de usuário com as teclas direcionais ou um trackball, é necessário dar atenção aos itens de recurso (como botões) que o usuário possa ver o que vai aceitar a entrada. Se o dispositivo tem capacidades de toque, no entanto, o usuário começa a interagir com a interface ao tocá-lo, então ele não é mais ANDROID, uma visão geral Anderson Duarte de Amorim 173

174 necessário para destacar itens, ou dar enfoque a uma visão particular. Assim, existe um modo de interação com o nome "modo de toque." Para um dispositivo sensível ao toque, uma vez que o usuário toca a tela, o aparelho entra em modo de tocar. Deste ponto em diante, somente as views em que o isfocusableintouchmode() está true poderão ser focadas, como os widgets de edição de texto. Outros views que são palpáveis, como botões, não vão tirar o foco quando tocado; eles vão simplesmente focar seus ouvintes com um clique, quando pressionados. Toda vez que um usuário 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 usuário pode continuar interagindo com a interface do usuário 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. Manipulação do foco O framework vai lidar com as rotinas de movimento do foco em resposta à entrada do usuário. Isso inclui a mudança do foco nas views que são removidas ou escondidas, ou quando as views novos se tornam disponíveis. Views indicam a sua disponibilidade para tirar o foco através do método 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 próximo em uma determinada direção. Em casos raros, o algoritmo padrão pode não coincidir com o comportamento desejado para o desenvolvedor. Nessas situações, você pode fornecer substituições explícitas 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: ANDROID, uma visão geral Anderson Duarte de Amorim 174

175 <LinearLayout android:orientation="vertical"... > <Button /> <Button /> </LinearLayout> Normalmente, neste layout vertical, navegando a partir do primeiro botão não leva a lugar nenhum, nem iria navegar abaixo do segundo botão. Agora que o botão superior foi definido como um fundo com o nextfocusup (e vice-versa), o foco de navegação irá circular de cima para baixo e de baixo para cima. Se você gostaria de declarar o view como passível de foco em sua interface do usuário (quando não é tradicional), adicione o atributo XML android:focusable para a view, na sua declaração de layout. Defina o valor true. Você pode também declarar uma view como passível de foco enquanto em modo de toque com android:focusableintouchmode. Para solicitar uma exibição especial para ter foco, chame requestfocus(). Para ouvir os eventos de foco (ser notificado quando um view recebe ou perde foco), use onfocuschange(). ANDROID, uma visão geral Anderson Duarte de Amorim 175

176 Notificar o usuário Vários tipos de situações podem surgir que requerem a notificação do usuário sobre um evento que ocorre em sua aplicação. Alguns eventos requerem que o usuário responda e outros não. Por exemplo: Quando um evento como salvar um arquivo for concluída, uma pequena mensagem deve aparecer para confirmar que o salvamento foi bem sucedido. Se o aplicativo é executado em segundo plano e requer atenção do usuário, o aplicativo deve criar uma notificação que permite ao usuário responder a conveniência dele ou dela. Se o aplicativo está executando o trabalho que o usuário deve aguardar (como carregar um arquivo), o aplicativo deve mostrar uma roda de progresso pairando ou uma barra. Cada uma dessas tarefas de notificação podem ser conseguidas usando uma técnica diferente: Uma notificação brinde, por breves mensagens que vêm do fundo. Uma notificação na barra de status, lembretes persistentes que vêm do fundo e solicitam resposta do usuário. Uma notificação de diálogo, para as notificações de atividades relacionadas. Notificação brinde Uma notificação brinde é uma mensagem que aparece na superfície da janela. Ela só enche o espaço necessário para a mensagem e a atividade atual do usuário permanece visível e interativa. A notificação automaticamente desaparece, e não aceita eventos de interação. Como um brinde pode ser criado a partir de um serviço em background, aparece mesmo que o aplicativo não esteja visível. ANDROID, uma visão geral Anderson Duarte de Amorim 176

177 Um brinde é melhor para mensagens de texto curtas, como "Arquivo salvo", quando você está bastante certo de que o usuário está prestando a atenção na tela. Um brinde não pode aceitar eventos de interação do usuário, se você gostaria que o usuário respondesse e agisse, considere usar uma notificação na barra de status. Criando notificações brinde A imagem abaixo mostra uma notificação brinde de exemplo da aplicação do alarme. Uma vez que um alarme é ativado, um brinde é exibido para garantir que o alarme foi ajustado. Um brinde pode ser criado e exibido a partir de uma Activity ou Service. Se você criar uma notificação de brinde de um serviço, ele aparece na frente da atividade atualmente em foco. considere usar uma notificação na barra de status. O Básico Se a resposta do usuário com a notificação é exigida, Primeiro, instanciar um objeto Toast com um dos métodos maketext(). Este método usa três parâmetros: a aplicação Context, a mensagem de texto e a duração para o brinde. Ele retorna um objeto Toast inicializado corretamente. Você pode exibir a notificação brinde com show(), como mostrado no exemplo a seguir: Context context = getapplicationcontext(); CharSequence text = "Hello toast!"; int duration = Toast.LENGTH_SHORT; Toast toast = Toast.makeText(context, text, duration); toast.show(); Este exemplo demonstra tudo o que precisa para a maioria das notificações brinde. Raramente é necessário algo a mais. Você pode, no entanto, querer a posição do brinde diferente ou até mesmo usar o seu próprio layout, em vez de uma simples mensagem de texto. As seções a seguir descrevem como você pode fazer essas coisas. ANDROID, uma visão geral Anderson Duarte de Amorim 177

178 Posicionar o seu brinde Uma notificação brinde padrão aparece perto da parte inferior da tela, centralizado horizontalmente. Você pode alterar esta posição com o método setgravity(int, int, int). Este aceita três parâmetros: a constante Gravity, um deslocamento da posição x e um deslocamento da posição 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 posição para a direita, aumente o valor do segundo parâmetro. Para empurrá-lo para baixo, aumente o valor do último parâmetro. Criando uma exibição personalizada brinde Se uma mensagem de texto simples não é suficiente, você pode criar um layout personalizado para a sua notificação brinde. Para criar um layout personalizado, definir um layout de view, em XML ou no código do aplicativo, e passar a View raiz para o método setview(view). Por exemplo, você pode criar o layout para o brinde visível na imagem à esquerda, com o seguinte XML (salvo como toast_layout.xml): <LinearLayout xmlns: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" ANDROID, uma visão geral Anderson Duarte de Amorim 178

179 android:layout_width="wrap_content" android:layout_height="fill_parent" android:textcolor="#fff" /> </LinearLayout> Observe que a identificação do elemento LinearLayout é "toast_layout". Você deve usar essa identificação 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 parâmetro é 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 conteúdo dos elementos ImageView e TextView. Finalmente, crie um novo brinde com Toast(Context) e defina algumas propriedades do brinde, tais como a gravidade e duração. Em seguida, chame setview(view) e passe seu layout inflado. Agora você pode exibir o brinde com o seu layout personalizado, chamando show(). Nota: Não use o construtor público para um brinde, a menos que vá definir o layout com setview(view). Se você não tem um layout personalizado para o uso, você deve usar maketext(context, int, int) para criar o Toast. Notificação na barra de status Uma notificação na barra de status adiciona um ícone para barra de status do sistema (com opcionais relógio/mensagem de texto) e uma mensagem expandida na janela "Notificações". Quando o usuário seleciona a mensagem ANDROID, uma visão geral Anderson Duarte de Amorim 179

180 expandida, o Android aciona uma Intent que é definida pela notificação (geralmente para lançar uma Activity). Você também pode configurar a notificação para alertar o usuário com um som, uma vibração e as luzes piscando no dispositivo. Este tipo de notificação é ideal quando o aplicativo está funcionando em um serviço de fundo e há necessidade de notificar o usuário sobre um evento. Se você precisa alertar o usuário sobre um evento que ocorre durante a sua atividade que ainda está em foco, considere usar uma notificação de diálogo em vez disso. Criação de notificações da barra de status Uma notificação na barra de status deve ser usada para qualquer caso em que um serviço de background precisa alertar o usuário sobre um evento que exige uma resposta. Um serviço de fundo nunca deve iniciar uma atividade por conta própria a fim de receber a interação do usuário. O serviço deveria criar uma notificação na barra de status que vai lançar a atividade quando selecionado pelo usuário. A imagem abaixo mostra a barra de status com um ícone de notificação no lado esquerdo. A imagem seguinte mostra mensagem expandida de notificação na janela "Notificações". O usuário pode visualizar a janela de notificações, puxando para baixo a barra de status (ou selecionando Notificações no menu de opções da Home). O Básico Uma Activity ou Service pode iniciar uma notificação na barra de status. Porque uma atividade pode executar ações somente quando ela está ativa e em foco, você deve criar suas notificações de um serviço. Desta forma, a notificação pode ser criada a partir do ANDROID, uma visão geral Anderson Duarte de Amorim 180

181 fundo, enquanto o usuário está usando outra aplicação ou quando o dispositivo estiver dormindo. Para criar uma notificação, você deve usar duas classes: Notification e NotificationManager. Use uma instância da classe Notification para definir as propriedades de sua notificação na barra de status, como o ícone da barra de status, a mensagem expandida e configurações extras, como um som para tocar. O NotificationManager é um serviço do sistema Android que executa e gerencia todas as notificações. Você não pode instanciar o NotificationManager. A fim de dar-lhe a sua notificação, você deve recuperar uma referência para o NotificationManager com getsystemservice() e então, quando você quer notificar o usuário, passá-lo com seu objeto de notificação notify(). Para criar uma notificação de barra de status: 1. Obtenha uma referência para o NotificationManager: String ns = Context.NOTIFICATION_SERVICE; NotificationManager mnotificationmanager = (NotificationManager) getsystemservice(ns); 2. Instanciar a notificação: int icon = R.drawable.notification_icon; CharSequence tickertext = "Hello"; long when = System.currentTimeMillis(); Notification notification = new Notification(icon, tickertext, when); 3. Definir mensagem expandida e intenção da notificação: Context context = getapplicationcontext(); CharSequence contenttitle = "My notification"; CharSequence contenttext = "Hello World!"; Intent notificationintent = new Intent(this, MyClass.class); PendingIntent contentintent = PendingIntent.getActivity(this, 0, notificationintent, 0); notification.setlatesteventinfo(context, contenttitle, contenttext, contentintent); 4. Passe a notificação ao NotificationManager: private static final int HELLO_ID = 1; mnotificationmanager.notify(hello_id, notification); É isso aí. Seu usuário já foi notificado. ANDROID, uma visão geral Anderson Duarte de Amorim 181

182 Gerenciando suas notificações O NotificationManager é um serviço do sistema que gerencia todas as notificações. Você deve obter uma referência a ele com o método getsystemservice(). Por exemplo: String ns = Context.NOTIFICATION_SERVICE; NotificationManager mnotificationmanager = (NotificationManager) getsystemservice(ns); Quando você quiser enviar sua notificação na barra de status, passar o objeto de notificação ao NotificationManager com notify(int, Notification). O primeiro parâmetro é o ID único para a notificação e o segundo é o objeto de notificação. O ID identifica a notificação a partir da sua aplicação. Isso é necessário se você precisa atualizar a notificação (se o aplicativo gerencia diferentes tipos de notificações) ou selecionar a ação apropriada quando o usuário retornar para a sua aplicação através da intenção definida na notificação. Para apagar a notificação de barra de status quando o usuário seleciona a partir da janela de notificações, adicione a flag "FLAG_AUTO_CANCEL" de seu objeto de notificação. Você também pode limpar manualmente com cancel(int), passando-lhe a identificação ou notificação ou limpar todas as suas notificações com cancelall(). Criando uma notificação Um objeto Notification define os detalhes da mensagem de notificação que é exibida na barra de status e janela de "Notificações", e qualquer alerta de outras configurações, tais como sons e luzes piscando. Uma notificação de barra de status exige o seguinte: Um ícone da barra de status Uma mensagem expandida e título para o modo expandido (a menos que você defina uma exibição personalizada ampliada) Um PendingIntent, para ser acionado quando a notificação for selecionada As configurações opcionais para a notificação de barra de status incluem: Uma mensagem de texto-relógio para a barra de status Um som de alerta ANDROID, uma visão geral Anderson Duarte de Amorim 182

183 Uma configuração vibrar Uma definição LED piscando O kit de arranque para uma nova notificação inclui o construtor Notification(int, CharSequence, long) e o método setlatesteventinfo(context, CharSequence, CharSequence, PendingIntent). Estes definem todas as definições necessárias para uma notificação. O trecho a seguir demonstra a configuração de notificação 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 notificação Você pode atualizar as informações em sua notificação 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 notificações existentes para exibir o número total de novas mensagens recebidas. Esta prática, de uma atualização de notificação existente é muito melhor do que a adição de novas notificações à NotificationManager porque evita a desordem na janela de notificações. Porque cada notificação é unicamente identificada pelo NotificationManager com um número de identificação inteiro, você pode revisar a notificação chamando setlatesteventinfo() com novos valores, mudar alguns valores de campo da notificação, e depois chamar notify() novamente. Você pode rever cada propriedade com os campos de membro de objeto (exceto para o contexto e no título da mensagem expandida e texto). Você deve sempre revisar a mensagem de texto quando você atualizar a notificação chamando setlatesteventinfo() com novos valores para contenttitle e contenttext. Em seguida, chamar notify() para ANDROID, uma visão geral Anderson Duarte de Amorim 183

184 atualizar a notificação. (Claro, se você criou uma exibição personalizada expandida, atualizar esses valores de texto e título não terá efeito) Adicionando um som Você pode alertar o usuário com o som de notificação padrão (que é definido pelo usuário) ou com um som especificado pelo seu aplicativo. Para utilizar o usuário padrão do som, adicione "DEFAULT_SOUND" para o campo de padrões: notification.defaults = Notification.DEFAULT_SOUND; Para usar um som diferente com as suas notificações, passe uma referência URI para o campo de som. O exemplo a seguir usa um arquivo de áudio conhecido gravado no cartão SD do dispositivo: notification.sound = Uri.parse("file:///sdcard/notification/ringer.mp3"); No próximo exemplo, o arquivo de áudio é escolhido do MediaStore 's ContentProvider: notification.sound = Uri.withAppendedPath(Audio.Media.INTERNAL_CONTENT_URI, "6"); Neste caso, a identificação exata do arquivo de mídia ("6") é conhecido e anexado ao conteúdo Uri. Se você não souber a identificação exata, você deve consultar todos os meios disponíveis no MediaStore com ContentResolver. Se você deseja que o som repeta continuamente até que o usuário responda à notificação ou a notificação seja cancelada, adicione "FLAG_INSISTENT" para o campo de sinalizadores. Nota: Se o campo padrão inclui "DEFAULT_SOUND", então o som padrão substitui qualquer som definido pelo campo de som. Adicionando vibração Você pode alertar o usuário com o modelo padrão de vibração ou com um modelo de vibração definido pelo seu aplicativo. Para usar o modelo padrão, adicione "DEFAULT_VIBRATE" para o campo de padrões: ANDROID, uma visão geral Anderson Duarte de Amorim 184

185 notification.defaults = Notification.DEFAULT_VIBRATE; Para definir o seu padrão de vibração própria, passe uma matriz de valores longos para o campo vibrar: long[] vibrate = {0,100,200,300; notification.vibrate = vibrate; O longo array define o padrão alternado para o comprimento de vibração e desligando (em milissegundos). O primeiro valor é o tempo de espera (desligado) antes de começar, o segundo valor é o comprimento da primeira vibração, o terceiro é o comprimento da próxima, e assim por diante. O padrão pode ser tão longo quanto queira, mas não pode ser configurado para repetir. Nota: Se o campo padrão inclui "DEFAULT_VIBRATE", então a vibração padrão substitui qualquer vibração definida pelo campo vibrate. Adicionando luzes a piscar Para alertar o usuário com luzes LED, você pode implementar o modelo de luz padrão (se disponível), ou definir sua própria cor e padrão para as luzes. Para usar a configuração padrão de luz, acrescentar "DEFAULT_LIGHTS" para o campo de padrões: notification.defaults = Notification.DEFAULT_LIGHTS; Para definir sua própria cor e padrão, definir um valor para o campo ledargb (para a cor), o campo ledoffms (período de tempo, em milésimos de segundo, para manter a luz apagada), o ledonms (período de tempo, em milissegundos, para manter a luz acesa), e também adicionar "FLAG_SHOW_LIGHTS" para o campo flags: notification.ledargb = 0xff00ff00; notification.ledonms = 300; notification.ledoffms = 1000; notification.flags = Notification.FLAG_SHOW_LIGHTS; Neste exemplo, a luz verde pisca várias vezes a cada 300 milésimos de segundo e desliga por um segundo. Nem todas as cores no espectro são suportadas pelo dispositivo de LEDs, e não é todo dispositivo que suporta as mesmas cores, então o hardware estima para o melhor de sua capacidade. Verde é a cor mais comum de notificação. ANDROID, uma visão geral Anderson Duarte de Amorim 185

186 Mais recursos Você pode adicionar várias características a mais às suas notificações usando campos de notificação e flags. Algumas características úteis incluem o seguinte: "FLAG_AUTO_CANCEL" Adicione isto ao campo de sinalizadores para cancelar automaticamente a notificação depois que ela é selecionada a partir da janela de notificações. "FLAG_INSISTENT" Adicione isto ao campo de sinalizadores para repetir o áudio até que o usuário responda. "FLAG_ONGOING_EVENT" Adicione isto ao campo de sinalizadores para agrupar notificações ao abrigo do título "em curso" da janela de notificações. Isso indica que o aplicativo está em curso - seus processos ainda estão em execução em segundo plano, mesmo quando o aplicativo não é visível (como a música ou uma chamada de telefone). "FLAG_NO_CLEAR" Adicione isto ao campo de sinalizadores para indicar que a notificação não deve ser limpa pelo botão "Limpar notificações". Isso é particularmente útil se a sua notificação está em curso. número Esse valor indica o número atual de eventos representados pela notificação. O número apropriado é sobreposto em cima do ícone da barra de status. Se você pretende usar esse campo, então você deve começar com "1" quando a notificação for criado pela primeira vez. (Se você alterar o valor de zero para qualquer coisa maior durante uma atualização, o número não é mostrado.) ANDROID, uma visão geral Anderson Duarte de Amorim 186

187 iconlevel Esse valor indica o nível atual de um LevelListDrawable que é usado para o ícone de notificação. Você pode animar o ícone na barra de status, alterando esse valor para correlacionar com os drawable é definido em um LevelListDrawable. Criar uma exibição personalizada expandida Por padrão, o modo expandido utilizado na janela "Notificações" inclui um título de base e mensagem de texto. Estes são definidos por parâmetros contenttext e contenttitle do método setlatesteventinfo(). No entanto, você também pode definir um layout personalizado para o modo de exibição expandido usando RemoteViews. A imagem à direita mostra um exemplo de uma exibição personalizada alargada, que usa um ImageView e TextView em LinearLayout. Para definir seu próprio layout para a mensagem expandida, instancie um objeto RemoteViews e passe-o para o campo contentview da sua notificação. Passe o PendingIntent ao campo contentintent. Criar uma exibição personalizada expandido é mais bem entendido com um exemplo: 1. Criar o layout XML para a exibição expandida. Por exemplo, crie um arquivo chamado layout custom_notification_layout.xml e construa-o assim: <LinearLayout xmlns: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> ANDROID, uma visão geral Anderson Duarte de Amorim 187

188 Este esquema é utilizado para a visualização expandida, mas o conteúdo do ImageView e TextView ainda precisam ser definidos pelo aplicativo. RemoteViews oferece alguns métodos adequados que lhe permitem definir o conteúdo No código do aplicativo, use os métodos RemoveViews para definir a imagem e texto. Em seguida, passe o objeto RemoteViews ao campo contentview da notificação, 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 identificação de recursos de layout para o construtor RemoteViews. Em seguida, defina o conteúdo para o ImageView e TextView, usando o setimageviewresource() e settextviewtext(). Em cada caso, passe o ID de referência do objeto View conveniente que você deseja definir, juntamente com o valor para essa visão. Finalmente, o objeto RemoteViews é passado para a notificação no âmbito contentview. 3. Porque você não precisa do método setlatesteventinfo() quando usando uma exibição personalizada, você deve definir as intenções para a notificação 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; 4. A notificação pode ser enviada, como de costume: mnotificationmanager.notify(custom_view_id, notification); A classe RemoteViews também inclui métodos que você pode usar para facilmente adicionar um Chronometer ou ProgressBar na view expandida da notificação. Para obter mais informações sobre como criar layouts personalizados com RemoteViews, consulte o RemoteViews. ANDROID, uma visão geral Anderson Duarte de Amorim 188

189 Nota: Ao criar uma view expandida customizada, você deve tomar cuidado especial para garantir que as funções personalizadas de seu layout haja corretamente no dispositivo em orientações e resoluções 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, não faça o seu layout personalizado demasiado complexo e não se esqueça de testá-lo em várias configurações. Notificação de diálogo Um diálogo é geralmente uma pequena janela que aparece na frente da atividade atual. A atividade perde o foco e o diálogo aceita a interação do usuário. Os diálogos são normalmente utilizados para notificações e atividades curtas que se relacionem diretamente com a aplicação em curso. Você deve usar uma caixa de diálogo quando você precisa mostrar uma barra de progresso ou uma mensagem curta que requer a confirmação do usuário (como um alerta com "OK" e "Cancelar"). Você pode usar também as janelas como parte integrante na interface do aplicativo e para outros fins além de notificações. Para uma discussão completa sobre todos os tipos disponíveis de diálogos, incluindo seus usos para as notificações, consulte Criando caixas de diálogo. ANDROID, uma visão geral Anderson Duarte de Amorim 189

190 Aplicando estilos e temas Um estilo é um conjunto de propriedades que especificam o aspecto e formato de um View ou janela. Um estilo pode especificar propriedades como altura, padding, cor de fonte, tamanho de fonte, cor de fundo e muito mais. Um estilo é definido em um recurso de XML que é separado do XML que especifica o layout. Estilos em Android compartilham uma filosofia semelhante à de estilo em cascata em web-design que permitem a você separar o design do conteúdo. Por exemplo, usando um estilo, você pode ter este layout XML: <TextView android:layout_width="fill_parent" android:layout_height="wrap_content" android:textcolor="#00ff00" android:typeface="monospace" android:text="@string/hello" /> 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 definição de estilo chamado CodeFont, e depois aplicado com o atributo style. Você verá a definição para esse estilo na seção seguinte. Um tema é um estilo aplicado a toda uma Activity ou aplicação, ao invés de um indivíduo View (como no exemplo acima). Quando um estilo é aplicado como um tema, a cada view da atividade ou da aplicação serão 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 monoespaçada verde. Definição de estilos Para criar um conjunto de estilos, salve um arquivo XML no diretório res/values/ do seu projeto. O nome do arquivo XML é arbitrário, mas deve usar a extensão.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 é obrigatório). Em seguida, adicione um elemento <item> para cada propriedade desse estilo, com um nome que declara a ANDROID, uma visão geral Anderson Duarte de Amorim 190

191 propriedade de estilo e um valor para ir com ele (este atributo é obrigatório). O valor para o <item> pode ser uma seqüência de palavras-chave, uma cor hexadecimal, uma referência 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 compilação, 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 demonstrado na introdução 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, então, substituir as propriedades de estilo herdado se você quiser. Lembre-se, um estilo que você deseja usar como uma atividade ou tema de aplicação é 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 aplicação inteira. Como aplicar um estilo para uma visão única ou como um tema de aplicação é discutido mais tarde. Herança 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 estão construídos na plataforma (Veja Usando estilos e temas da plataforma abaixo, para obter informações sobre herança de estilos definidos pela plataforma Android). Por exemplo, você pode herdar a aparência do texto padrão da plataforma Android e, em seguida, modificá-lo: ANDROID, uma visão geral Anderson Duarte de Amorim 191

192 <style name="greentext" <item name="android:textcolor">#00ff00</item> </style> Se você quer herdar os estilos que você definiu para si mesmo, você não 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 período. 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 não há atributo parent na tag <style>, mas porque o atributo name começa 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 referência a este novo estilo Você pode continuar herdando assim tantas vezes quanto quiser, encadeando os nomes com os períodos. 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 técnica de herança por encadeando de nomes só funciona para estilos definidos por seus próprios recursos. Você não pode herdar estilos internos do Android desta forma. Para fazer referência 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> estão disponíveis. Você provavelmente está familiarizado com alguns já, como layout_width e textcolor. Claro, há muito mais propriedades de estilo que você pode usar. ANDROID, uma visão geral Anderson Duarte de Amorim 192

193 O melhor lugar para encontrar propriedades que se aplicam a um determinado View é a referência de classe correspondente, que lista todos os atributos XML que são suportados. Por exemplo, todos os atributos listados na tabela de atributos XML TextView podem ser usados em uma definição de estilo para um elemento TextView (ou uma de suas subclasses). Um dos atributos listados na referência é android:inputtype, então 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 vários lugares, o custo-beneficio pode ser enorme. Para uma referência de todas as propriedades de estilo disponíveis, consulte a referência R.attr. Tenha em mente que todos os objetos view não aceitam todos os atributos de mesmo estilo, então você deve, normalmente, referenciar ao específico View para as propriedades de estilo suportadas. Entretanto, se você aplicar um estilo a uma exibição que não suporta todas as propriedades de estilo, o view irá aplicar apenas as propriedades que são suportadas e simplesmente ignorar os outros. Algumas propriedades de estilo, no entanto, não são suportadas por qualquer elemento View e só pode ser aplicado como um tema. Estas propriedades de estilo se aplicam a toda a janela e não a qualquer tipo de view. Por exemplo, propriedades de estilo para um tema podem ocultar o título do aplicativo, ocultar a barra de status, ou mudar o fundo da ANDROID, uma visão geral Anderson Duarte de Amorim 193

194 janela. Estes tipos de propriedades de estilo não pertencem a nenhum objeto View. Para descobrir essas propriedades de estilo theme-only, veja o R.attr de referência para os atributos que começam com window. Por exemplo, windownotitle e windowbackground são propriedades de estilo que só são eficazes quando o estilo é aplicado como um tema para uma atividade ou aplicação. Consulte a próxima seção para informações sobre como aplicar um estilo como um tema. Nota: Não se esqueça de prefixo dos nomes das propriedades em cada elemento <item> com o android: namespace. Por exemplo: <item name="android:inputtype">. Aplicando estilos e temas para a interface do usuário Há duas maneiras de definir um estilo: Para uma view individual, adicione o atributo style a um elemento view no XML para seu layout. Ou, para uma atividade inteira ou uma aplicação, adicione o atributo android:theme ao elemento <activity> ou <application> no manifesto do Android. Quando você aplica um estilo a uma única View no layout, as propriedades definidas pelo estilo são aplicadas somente ao View. Se um estilo é aplicado a um ViewGroup, a criança do elemento View não herdará as propriedades de estilo - apenas o elemento ao qual se aplicam diretamente o estilo vai aplicar suas propriedades. No entanto, você pode aplicar um estilo para que se aplique a todos os elementos View, aplicando o estilo como um tema. Para aplicar uma definição de estilo como um tema, você deve aplicar o estilo para uma Activity ou aplicação no manifesto do Android. Quando você fizer isso, todos os View dentro da atividade ou da aplicação serão aplicáveis a cada propriedade que ele suporta. Por exemplo, se você aplicar o estilo CodeFont dos exemplos anteriores a uma atividade, então todos os elementos View que suportam as propriedades de estilo de texto irá aplicá-los. Qualquer visão que não suporta as propriedades vai ignorá-los. Se o view suporta apenas algumas das propriedades, então é só aplicar essas propriedades. Aplicar um estilo a uma view Veja como definir um estilo para uma exibição no esquema XML: ANDROID, uma visão geral Anderson Duarte de Amorim 194

195 <TextView /> Agora este TextView será denominado como definido pelo estilo chamado CodeFont. (Veja o exemplo acima, em Definição de estilos). Nota: O atributo style não usa o android: namespace prefix. Aplicar um tema a uma atividade ou aplicação Para definir um tema para todas as atividades de sua aplicação, abra o arquivo AndroidManifest.xml e edite o tag <application> para incluir o atributo android:theme com o nome do estilo. Por exemplo: <application android:theme="@style/customtheme"> Se você quer um tema aplicado a apenas uma atividade em seu aplicativo, então, 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 diálogo: <activity android:theme="@android:style/theme.dialog"> Ou se você quiser que o fundo seja transparente, usar o tema translúcido: <activity android:theme="@android:style/theme.translucent"> 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 própria 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 referência a outro recurso, ao contrário do android:colorbackground, a ele pode não ser dada uma cor literal.) Agora use CustomTheme em vez de Theme.Light dentro do Manifesto Android: ANDROID, uma visão geral Anderson Duarte de Amorim 195

196 <activity Selecione um tema baseado na versão de plataforma Novas versões do Android têm temas adicionais disponíveis para os aplicativos, e você pode querer usar estes durante a execução nessas plataformas, enquanto continuam sendo compatíveis com versões anteriores. Você pode fazer isso através de um tema personalizado que usa a seleção de recursos para alternar entre os temas pai diferentes, baseado na versão da plataforma. Por exemplo, aqui está a declaração de um tema personalizado que é simplesmente o modelo padrão das plataformas do tema light. Ele vai em um arquivo XML por res/values (tipicamente res/values/styles.xml ): <style name="lightthemeselector" parent="android:theme.light">... </style> Para este tema usar o novo tema holográfico quando o aplicativo está rodando o Android 3.0 (API Nível 11) ou superior, você pode colocar uma declaração alternativa para o tema em um arquivo XML em res/values-v11, mas fazer do tema mãe o tema holográfico: <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 holográfico se em execução no Android 3.0 ou superior. Uma lista de atributos padrão que você pode usar em temas podem ser encontrados em R.styleable.Theme. Para obter mais informações sobre o fornecimento de recursos alternativos, como os temas e layouts, com base na versão de plataforma ou configurações de outro dispositivo, consulte o documento Fornecimento de Recursos. Usando estilos e temas da plataforma A plataforma Android oferece uma grande coleção de estilos e temas que você pode usar em seus aplicativos. Você pode encontrar uma referência de todos os estilos disponíveis na classe R.style. Para usar os estilos listados aqui, substituir todos os ANDROID, uma visão geral Anderson Duarte de Amorim 196

197 sublinhados no nome do estilo, com um período. Por exemplo, você pode aplicar o Theme_NoTitleBar tema com "@android:style/theme.notitlebar". O R.style, entretanto, não é bem documentado e não descreve minuciosamente os estilos, assim, ver o código fonte para estes estilos e temas lhe dará uma compreensão melhor do que as propriedades de estilo de cada um oferece. Para uma melhor referência para estilos e temas do Android, consulte os seguintes códigos fonte: Android Styles (styles.xml) Android Temas (themes.xml) Esses arquivos vão te ajudar a aprender através do exemplo. Por exemplo, no código fonte de temas Android, você encontrará uma declaração de <style name="theme.dialog">. Nesta definição, você verá todas as propriedades que são usadas para estilo de diálogos que são usadas pelo framework Android. Para uma referência de atributos de estilo disponíveis 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. ANDROID, uma visão geral Anderson Duarte de Amorim 197

198 Recursos de aplicação Você deve sempre externar recursos como imagens e seqüências de seu código de aplicação, para que você possa mantê-las de forma independente. Externalizar seus recursos também permite que você forneça recursos alternativos que oferecem suporte a configurações de dispositivos específicos, como línguas ou tamanhos de tela diferentes, o que se torna cada vez mais importante quanto mais dispositivos com Android tornamse disponíveis com configurações diferentes. A fim de proporcionar compatibilidade com diferentes configurações, você deve organizar os recursos em seu diretório do projeto res/, usando vários sub-diretórios que agrupam os recursos por tipo e configuração. Figura 1. Dois dispositivos diferentes, ambos os usando recursos padrão. Figura 2. Dois dispositivos diferentes, uma usando recursos alternativos. Para qualquer tipo de recurso, você pode especificar padrão e vários recursos alternativos para a sua aplicação: Os recursos padrão são aqueles que devem ser utilizados independentemente da configuração do aparelho ou quando não existem recursos alternativos que correspondam à configuração atual. Recursos alternativos são aqueles que você já projetou para uso com uma configuração específica. Para especificar que um grupo de recursos são de uma configuração específica, acrescente um qualificador de configuração adequada ao nome do diretório. ANDROID, uma visão geral Anderson Duarte de Amorim 198

199 Por exemplo, enquanto o seu layout padrão de interface do usuário é salvo no diretório res/layout/, você pode especificar um layout de interface diferente para ser usado quando a tela está na orientação paisagem, salvando-o no diretório res/layout-land/. Android aplica automaticamente os recursos apropriados por correspondência à configuração atual do dispositivo para os nomes do diretório de recursos. A figura 1 demonstra como um conjunto de recursos padrão de um aplicativo são aplicados a dois dispositivos diferentes, quando não há recursos alternativos disponíveis. A Figura 2 mostra o mesmo aplicativo com um conjunto de recursos alternativos que se qualificam para uma das configurações do dispositivo, assim, os dois dispositivos usam recursos diferentes. A informação acima é apenas uma introdução 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 aplicação, 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 configurações de dispositivo específico. Acessando recursos Como utilizar os recursos que você forneceu, seja por referenciá-los a partir do seu código de aplicativo ou de outros recursos XML. Tratando alterações em runtime Como gerenciar as alterações de configuração que ocorrem quando sua atividade está em execução. Localização Um guia de baixo para cima para localizar seu aplicativo usando recursos alternativos. Enquanto este é apenas um uso específico de recursos alternativos, é muito importante para alcançar mais usuários. ANDROID, uma visão geral Anderson Duarte de Amorim 199

200 Tipos de recursos Uma referência de vários tipos de recursos que você pode fornecer, descrevendo seus elementos XML, atributos e sintaxe. Por exemplo, esta referência mostra como criar um recurso para os menus do aplicativo, os desenhos, animações e muito mais. ANDROID, uma visão geral Anderson Duarte de Amorim 200

201 Armazenamento de dados Android oferece várias opções para você guardar dados da aplicação persistente. A solução que você escolher depende de suas necessidades específicas, tais como se os dados devem ser privados da sua aplicação ou acessíveis para outras aplicações (e do usuário) e quanto espaço seus dados requerem. Suas opções de armazenamento de dados são os seguintes: Preferências compartilhadas Armazenar dados privados primitivos em pares chave-valor. Armazenamento interno Armazenar dados privados sobre a memória do dispositivo. Armazenamento externo Armazenar dados públicos sobre o armazenamento compartilhado externo. Bancos de dados SQLite Armazenar dados estruturados em um banco privado. Conexão de rede Armazenar dados na web com seu servidor de rede própria. Android fornece uma maneira para que você exponha seus dados pessoais, mesmo para outras aplicações - com um provedor de conteúdo. Um provedor de conteúdo é um componente opcional que expõe acesso de leitura/gravação à sua aplicação de dados, sujeito a qualquer restrição que você pretende impor. Para obter mais informações sobre como usar provedores de conteúdo, consulte a documentação de provedores de conteúdo. Utilizando preferências compartilhadas A classe SharedPreferences fornece um framework geral que permite salvar e recuperar pares chave-valor persistente de tipos de dados primitivos. Você pode usar SharedPreferences para salvar os dados primitivos: booleans, floats, inteiros, longos, e ANDROID, uma visão geral Anderson Duarte de Amorim 201

202 strings. Estes dados vão persistir nas sessões de usuário (mesmo se sua aplicação é morta). Para obter um objeto SharedPreferences para sua aplicação, use um dos dois métodos: getsharedpreferences() - Use esta opção se você precisa de arquivos de múltiplas preferências identificados pelo nome, que você especifica com o parâmetro primeiro. getpreferences() - Use esta opção se você só precisa de um arquivo de preferências para a sua actividade. Porque este será o único arquivo de preferências para sua atividade, você não fornece um nome. Para escrever os valores: 1. Chame edit() para obter uma SharedPreferences.Editor. 2. Adicione valores com métodos como putboolean() e putstring(). 3. Empregue os novos valores com commit(). Para ler os valores, use métodos SharedPreferences como getboolean() e getstring(). Aqui está um exemplo que salva uma preferência para o modo silencioso keypress em uma calculadora: public class Calc extends Activity { public static final String PREFS_NAME = protected void oncreate(bundle state){ super.oncreate(state);... Preferências do usuário Preferências compartilhadas não são estritamente para o salvar "as preferências do usuário", como o toque de um usuário escolheu. Se você está interessado em criar preferências do usuário para seu aplicativo, consulte PreferenceActivity, que estabelece um quadro de atividades para você criar as preferências do usuário, o qual será automaticamente persistido (usando as preferências compartilhadas). // Restore preferences SharedPreferences settings = getsharedpreferences(prefs_name, 0); boolean silent = settings.getboolean("silentmode", false); setsilent(silent); ANDROID, uma visão geral Anderson Duarte de Amorim 202

203 @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(); Usando o armazenamento interno Você pode salvar arquivos diretamente na memória interna do dispositivo. Por padrão, os arquivos salvos no armazenamento interno são privados para sua aplicação e outras aplicações não podem acessá-los (nem mesmo o usuário). Quando o usuário desinstala o aplicativo, esses arquivos são removidos. Para criar e gravar um arquivo privado para o armazenamento interno: 1. Chame openfileoutput() com o nome do arquivo e o modo de funcionamento. Isso retorna um FileOutputStream. 2. Escreva no arquivo com o write(). 3. Feche o fluxo com close(). Por exemplo: String FILENAME = "hello_file"; String string = "hello world!"; FileOutputStream fos = openfileoutput(filename, Context.MODE_PRIVATE); fos.write(string.getbytes()); fos.close(); MODE_PRIVATE irá criar o arquivo (ou substituir um arquivo de mesmo nome) e torná-lo privado para sua aplicação. Outras modalidades disponíveis são: MODE_APPEND, MODE_WORLD_READABLE e MODE_WORLD_WRITEABLE. ANDROID, uma visão geral Anderson Duarte de Amorim 203

204 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 estático em seu aplicativo em tempo de compilação, salve o arquivo no diretório de res/raw/ do seu projeto. Você pode abri-lo com openrawresource(), passando a identificação de recurso R.raw.<filename>. Esse método retorna um InputStream que você pode usar para ler o arquivo (mas você não pode escrever no arquivo original). Salvando os arquivos de cache Se você gostaria de gravar alguns dados em cache, ao invés de armazená-lo persistentemente, você deve usar getcachedir() para abrir um arquivo que representa o diretório interno onde a sua aplicação deve salvar os arquivos de cache temporário. Quando o dispositivo está com pouco espaço de armazenamento interno, o Android pode excluir esses arquivos de cache para recuperar espaço. No entanto, você não deve confiar no sistema para limpar esses arquivos para você. Você deve sempre manter os arquivos de cache e manter dentro de um limite razoável de espaço consumido, como 1MB. Quando o usuário desinstala o aplicativo, esses arquivos são removidos. Outros métodos úteis: getfilesdir() Obtém o caminho absoluto para o diretório de arquivos onde os arquivos internos são salvos. getdir() Cria (ou abre um existente) diretório dentro de seu espaço de armazenamento interno. deletefile() Exclui um arquivo salvo na memória interna. ANDROID, uma visão geral Anderson Duarte de Amorim 204

205 filelist() Retorna uma matriz de arquivos atualmente salvos pela sua aplicação. Usando o armazenamento externo Cada dispositivo compatível com o Android suporta um "armazenamento externo" compartilhado que você pode usar para salvar arquivos. Pode ser uma mídia de armazenamento removível (como um cartão SD) ou uma memória interna (não removível). Os arquivos salvos no armazenamento externos são de leitura e podem ser modificados pelo usuário quando permitem armazenamento em massa USB para transferir arquivos de um computador. Atenção: os arquivos externos podem desaparecer se o usuário monta o armazenamento externo em um computador ou remove a mídia, e não há nenhuma segurança aplicada sobre os arquivos que você salva para o armazenamento externo. Todas as aplicações podem ler e gravar arquivos colocados no armazenamento externo e o usuário pode removê-los. Verificar a disponibilidade dos meios Antes de fazer qualquer trabalho com o armazenamento externo, você deve sempre chamar getexternalstoragestate() para verificar se os meios de comunicação estão disponíveis. A mídia pode ser montada a um computador, faltando, somente leitura, ou em algum outro estado. Por exemplo, aqui está como você pode verificar a disponibilidade: boolean mexternalstorageavailable = false; boolean mexternalstoragewriteable = false; String state = Environment.getExternalStorageState(); if (Environment.MEDIA_MOUNTED.equals(state)) { // We can read and write the media mexternalstorageavailable = mexternalstoragewriteable = true; else if (Environment.MEDIA_MOUNTED_READ_ONLY.equals(state)) { // We can only read the media mexternalstorageavailable = true; mexternalstoragewriteable = false; else { // Something else is wrong. It may be one of many other states, but all we need // to know is we can neither read nor write mexternalstorageavailable = mexternalstoragewriteable = false; ANDROID, uma visão geral Anderson Duarte de Amorim 205

206 Este exemplo verifica se o armazenamento externo está disponível para ler e escrever. O método getexternalstoragestate() retorna outros estados que você pode querer verificar, como se a mídia está sendo compartilhada (conectada a um computador), está totalmente ausente, foi mal removida, etc. Você pode usá-los para notificar o usuário com mais informações quando o aplicativo precisa de acesso à mídia. Acessando arquivos em armazenamento externo Se você estiver usando a API de nível 8 ou superior, use getexternalfilesdir() para abrir um arquivo que representa o diretório de armazenamento externo onde você deve salvar seus arquivos. Este método utiliza um parâmetro type que especifica o tipo de subdiretório que você deseja, como DIRECTORY_MUSIC e DIRECTORY_RINGTONES (passe null para receber a raiz do diretório do arquivo da aplicativo). Este método irá criar o diretório apropriado, se necessário. Ao especificar o tipo de diretório, você garante que a mídia scanner do Android irá categorizar corretamente seus arquivos no sistema (por exemplo, os ringtones são identificados como toques, e não música). Se o usuário desinstala o aplicativo, este diretório e todo seu conteúdo serão apagados. Se você estiver usando a API de nível 7 ou inferior, use getexternalstoragedirectory() para abrir um File que representa a raiz de armazenamento externo. Você deve então escrever os seus dados no seguinte diretório: /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 usuário está executando API nível 8 ou superior e desinstalar o aplicativo, este diretório e todo seu conteúdo serão apagados. Como salvar arquivos que devem ser compartilhados Se você deseja salvar os arquivos que não são específicos para a sua aplicação e que não devem ser excluídos quando o aplicativo é desinstalado, salva-os em um dos Escondendo seus arquivos a partir da Media Scanner Inclua um arquivo vazio chamado.nomedia em seu diretório de arquivos externos (note o ponto prefixo ao nome do arquivo). Isto irá prevenir o media scanner do Android de ler arquivos de mídia e incluí-los em aplicativos como Galley ou Music. ANDROID, uma visão geral Anderson Duarte de Amorim 206

207 diretórios públicos de armazenamento externo. Esses diretórios estão na origem do armazenamento externo, como Music/, Pictures/, Ringtones/ e outros. Na API nível 8 ou superior, use getexternalstoragepublicdirectory(),passando para ele o tipo de diretório público que deseja, tais como DIRECTORY_MUSIC, DIRECTORY_PICTURES, DIRECTORY_RINGTONES ou outros. Este método irá criar o diretório apropriado, se necessário. Se você estiver usando a API de nível 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 diretórios: Music/ - o scanner media classifica todas as mídias encontradas aqui como a música do usuário. Podcasts/ - scanner media classifica todas as mídias encontradas aqui como um podcast. Ringtones/ - scanner media classifica todas as mídias encontradas aqui como um ringtone. Alarms/ - scanner media classifica todas as mídias encontradas aqui como um som de alarme. Notifications/ - scanner media classifica todas as mídias encontradas aqui como um som de notificação. Pictures/ - todas as fotos (excluindo as tiradas com a câmera). Movies/ - todos os filmes (excluindo aqueles filmados com a câmera de vídeo). Download/ - downloads diversos. Salvando os arquivos de cache Se você estiver usando a API de nível ou superior, use 8 getexternalcachedir() para abrir um File que representa o diretório de armazenamento externo, onde você deve salvar os arquivos de cache. Se o usuário desinstala o aplicativo, esses arquivos serão automaticamente excluídos. No entanto, durante a vida do seu aplicativo, você deve gerenciar esses arquivos de cache e eliminar os que não são necessários, a fim de preservar o espaço do arquivo. ANDROID, uma visão geral Anderson Duarte de Amorim 207

208 Se você estiver usando a API de nível 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 diretório: /Android/data/<package_name>/cache/ O <package_name> é o seu estilo nome do pacote Java, tal qual "com.example.android.app". Utilizando bancos de dados Android oferece suporte completo para bancos de dados SQLite. Qualquer banco de dados que você criar serão acessíveis pelo nome de qualquer classe na aplicação, mas não fora da aplicação. O método recomendado para criar um novo banco de dados SQLite é criar uma subclasse de SQLiteOpenHelper e substituir o método oncreate(), no qual você pode executar um comando SQLite para criar tabelas no banco de dados. Por exemplo: public class DictionaryOpenHelper extends SQLiteOpenHelper { private static final int DATABASE_VERSION = 2; private static final String DICTIONARY_TABLE_NAME = "dictionary"; private static final String DICTIONARY_TABLE_CREATE = "CREATE TABLE " + DICTIONARY_TABLE_NAME + " (" + KEY_WORD + " TEXT, " + KEY_DEFINITION + " TEXT);"; DictionaryOpenHelper(Context context) { super(context, DATABASE_NAME, null, public void oncreate(sqlitedatabase db) { db.execsql(dictionary_table_create); Você pode obter uma instância de sua implementação 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 métodos para operações de SQLite. ANDROID, uma visão geral Anderson Duarte de Amorim 208

209 Você pode executar consultas SQLite usando métodos query() SQLiteDatabase, que aceitam parâmetros de consulta diversos, tais como a tabela a ser consultada, a projeção, seleção, colunas, 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 aplicações Note Pad e Dicionário pesquisável. Android não impõe qualquer limitação para além dos conceitospadrão SQLite. Nós recomendamos incluir um valor de campo autoincrementado como chave que pode ser usado como uma identificação única para localizar rapidamente um registro. Isso não é necessária para dados privados, mas se você implementar um provedor de conteúdo, você deve incluir uma identificação exclusiva com a constante BaseColumns._ID. Banco de dados de depuração O Android SDK inclui uma ferramenta sqlite3 de banco de dados que permite que você navegue sobre o conteúdo da tabela, execute comandos SQL e execute outras funções úteis em bancos de dados SQLite. Usando uma conexão de rede Você pode usar a rede (quando disponível) para armazenar e recuperar dados sobre os seus próprios serviços baseados na web. Para fazer operações de rede, use as classes dos seguintes pacotes: java.net.* android.net.* ANDROID, uma visão geral Anderson Duarte de Amorim 209

210 Artigos Acessibilidade Linguagens e recursos Text-to-Speech TTS: também conhecido como speech synthesis (síntese de fala, em português) é 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 inglês (britânico ou americano), francês, alemão, italiano e espanhol e precisa saber qual idioma pronunciar para adequar a voz, afinal, uma mesma palavra possui pronuncias diferentes dependendo da língua. Uma checagem da disponibilidade do recurso se faz necessário 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 específicos do idioma, sendo assim, o seguinte código verifica a presença 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 criação do objeto TextToSpeech. Em caso negativo, o dispositivo irá utilizar o ACTION_INSTALL_TTS_DATA que dispara uma ação levando o usuário a fazer a instalação manualmente acessando o Android Market; A instalação é feita automaticamente após a conclusão do download. Uma implementação da verificação 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); ANDROID, uma visão geral Anderson Duarte de Amorim 210

211 No construtor da instância TextToSpeech nós passamos uma referência ao Contexto a ser usado (neste caso a atividade atual), e um OnInitListener (aqui a nossa atividade também). Dessa forma é habilitado para que a aplicação seja notificada quando o Text- To-Speech é totalmente carregado, então podemos começar a configurar-lo e usá-lo. Linguagens e localidade No Google I/O 2009 foi mostrado uma utilização do TTS para falar o resultado de uma tradução de e para uma das línguas disponíveis. Um exemplo de chamada é como o abaixo: mtts.setlanguage(locale.us); Ou para verificar se uma linguagem está disponível, basta usar o trecho abaixo que retornará TextToSpeech.LANG_COUNTRY_AVAILABLE para indicar que o idioma e o país, como descrito pelo parâmetro de localidade, são suportados (e os dados estão corretamente instalados), como também pode retornar TextToSpeech.LANG_AVAILABLE indicando que a língua está disponível ou o oposto TextToSpeech.LANG_MISSING_DATA. mtts.islanguageavailable(locale.uk)) mtts.islanguageavailable(locale.france)) mtts.islanguageavailable(new Locale("spa", "ESP"))) Obs.: para usar o código Locale.getDefault(), deve-se certificar primeiramente se o idioma padrão é suportado. Fazendo o dispositivo falar A maneira mais simples de fazer isso é usando o método speak() como: String mytext1 = "Did you sleep well?"; String mytext2 = "I hope so, because it's time to wake up."; mtts.speak(mytext1, TextToSpeech.QUEUE_FLUSH, null); mtts.speak(mytext2, TextToSpeech.QUEUE_ADD, null); O mecanismo TTS gerencia uma fila global de todas as entradas para sintetizar, que também são conhecidos como "expressões". Cada TextToSpeech pode gerir sua própria fila a fim de controlar o que vai interromper a emissão atual e que é simplesmente uma fila de espera. ANDROID, uma visão geral Anderson Duarte de Amorim 211

212 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 definições de alarme que o usuário escolheu no dispositivo. O último parâmetro do método speak() permite que você passe para os parâmetros 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 são assíncronas, pode ser necessário identificar se uma síntese foi concluída, 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 método, repare que a mensagem foi usada para ser identificada no método: public void onutterancecompleted(string uttid) { if (uttid == "end of wakeup message ID") { playannoyingmusic(); Como o recurso de fala exige bastante processamento, numa situação 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 serviço dedicado compartilhado entre todos os aplicativos que usam esse recurso. Quando você terminar de usar o TTS, use a instrução mtts.shutdown() dentro do método ondestroy(), por exemplo. ANDROID, uma visão geral Anderson Duarte de Amorim 212

213 Interface Toque O modo de toque é um estado da hierarquia de vista que depende unicamente da interação do usuário com o telefone. Por si só, o modo de tocar é algo muito fácil de entender, pois ele simplesmente indica se a interação do usuário passado foi realizada com a tela sensível ao toque. Por exemplo, se você estiver usando um dispositivo com Android, a seleção de um widget com o trackball vai levá-lo sair do modo de tocar, no entanto, se você toca um botão na tela com seu dedo, você entrará no modo de tocar. Quando o usuário não estiver em modo de tocar, nós falamos sobre o modo de trackball, o modo de navegação ou a navegação por teclado, por isso não 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 conseqüências de entrar no modo de tocar é muito maior do que você imagina. Vejamos algumas das razões. Toque em modo de seleção e foco Criar um conjunto de ferramentas UI para dispositivos móveis é difícil porque são vários os mecanismos de interação. Alguns dispositivos oferecem apenas 12 teclas, algumas têm uma tela sensível ao toque, alguns exigem uma caneta, alguns têm ambos um ecrã táctil e um teclado. Com base nos recursos de hardware do usuário, ele pode interagir com seu aplicativo usando mecanismos diferentes, então tivemos que pensar muito sobre todos os possíveis problemas que possam surgir. Uma questão nos levou a criar o modo de toque. Imagine um aplicativo simples, ApiDemos por exemplo, que mostra uma lista de itens de texto. O usuário pode navegar livremente pela lista usando a trackball, mas também, em alternativa, deslocar e arremessar a lista usando a tela sensível ao toque. O problema neste cenário é como lidar com a seleção corretamente quando o usuário manipula a lista através da tela sensível ao toque. Neste caso, se o usuário selecionar um item no topo da lista e então arremessa a lista para o fundo, o que deve acontecer com a seleção? E se ele permanecer no item e rolar ANDROID, uma visão geral Anderson Duarte de Amorim 213

214 para fora da tela? O que deve acontecer se o usuário decidiu então mover a seleção com o trackball? Ou pior, o que deve acontecer se o usuário pressiona o trackball para agir de acordo com o item selecionado, que não é mostrado na tela mais? Após cuidadosa consideração, decidimos remover por completo a seleção, quando o usuário manipula a interface do usuário através da tela sensível ao toque. No modo de toque, não há foco e não há seleção. Qualquer item selecionado em uma lista de em uma grade fica desmarcada, logo que o usuário entra no modo de tocar. Da mesma forma, quaisquer widgets ficaram desfocados quando o usuário entra no modo de tocar. A imagem abaixo ilustra o que acontece quando o usuário toca uma lista depois de selecionar um item com o trackball. Para tornar as coisas mais naturais para o usuário, o quadro sabe como ressuscitar a seleção / foco sempre que o usuário sai do modo de tocar. Por exemplo, se o usuário fosse usar o trackball novamente, a seleção iria reaparecer no item previamente selecionado. É por isso que alguns desenvolvedores estão confusos quando se criar uma exibição personalizada e começar a receber os principais eventos só depois de mover o trackball uma vez: a sua aplicação está no modo de tocar, e eles precisam usar o trackball para sair do modo de tocar e ressuscitar o foco. ANDROID, uma visão geral Anderson Duarte de Amorim 214

215 A relação entre o modo de toque, seleção e foco significa que você não deve confiar na seleção e/ou foco existir em sua aplicação. Um problema muito comum com o Android para novos desenvolvedores é contar com ListView.getSelectedItemPosition(). No modo de toque, este método retornará INVALID_POSITION. Focando no modo Touch Em geral, o foco não 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 usuário inserir texto dentro de um campo de texto na tela, sem primeiro selecioná-la com a bola ou o dedo. Quando um usuário toca a tela, o aplicativo irá entrar no modo de toque se ele não estava no modo de tocar já. O que acontece durante a transição para o modo de tocar depende do que o usuário tocou, e que atualmente tem foco. Se o usuário toca um widget que é focusable no modo de tocar, o widget irá receber o foco. Caso contrário, qualquer elemento ao qual se dedica atualmente não vai manter o foco a menos que seja focusable no modo de tocar. Por exemplo, na figura abaixo, quando o usuário 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 código ou de XML. No entanto, você deve usá-lo com parcimônia e só em situações muito específicas, porque quebra a coerência com o comportamento normal da interface do Android. Um jogo é um bom exemplo de uma aplicação que pode fazer bom uso do focusable na propriedade de modo sensível 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 usuário bate um AutoCompleteTextView com o dedo, o foco permanece no campo de texto de entrada: ANDROID, uma visão geral Anderson Duarte de Amorim 215

216 Novos desenvolvedores para o Android, muitas vezes pensam que focusable no modo de tocar é a solução que eles precisam para "consertar" o problema do "desaparecimento" da seleção/foco. Nós 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 hábitos do usuário. O quadro Android contém todas as ferramentas necessárias para lidar com as interações do usuário sem usar focusable no modo de tocar. Por exemplo, em vez de tentar fazer ListView sempre manter a sua seleção, basta usar o modo de escolha apropriada, como mostrado na setchoicemode(int). Gestos As telas de toque são uma ótima maneira de interagir com aplicações em dispositivos móveis. Com uma tela de toque, os usuários podem facilmente tocar, arrastar, arremessar ou deslizar rapidamente e realizar ações em seus aplicativos favoritos. Para os desenvolvedores de aplicativos o Android faz com que seja fácil reconhecer ações simples, mas tem sido mais difícil de lidar com gestos complicados, às vezes exigindo que os desenvolvedores escrevam um monte de código. É 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 código fonte dos exemplos Método de entrada de dados A partir do Android 1.5, a plataforma Android oferece um Input Method Framework (FMI) que permite a criação de métodos de entrada na tela, como teclados virtuais. Este artigo fornece uma visão geral de editores de método de Android de entrada (IME) e o que um aplicativo precisa fazer para trabalhar bem com eles. O FMI é concebido para ANDROID, uma visão geral Anderson Duarte de Amorim 216

217 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 experiência para os usuários. O que é um método de entrada? O FMI Android foi concebido para suportar uma variedade de IMEs, incluindo o teclado virtual, reconhecedores de mão-escrita, e tradutores teclado duro. Nosso foco, no entanto, será em teclados virtuais, já que este é o tipo de método de entrada que atualmente faz parte da plataforma. Um usuário normalmente irá acessar o IME atual, tocando em uma exibição 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 espaço disponível entre a aplicação 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 visão focada atualmente é visível. Este é o modo padrão, pois é mais seguro para as aplicações existentes. ANDROID, uma visão geral Anderson Duarte de Amorim 217

218 Na maioria das vezes o layout da tela é um resize, onde a janela da aplicação é redimensionada para ser totalmente visível. Um exemplo é mostrado aqui, quando escrevo uma mensagem de 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 têm uma área redimensionável que pode ser reduzida para dar espaço suficiente, mas o espaço vertical neste modo é realmente nada menos do que o que está disponível na orientação paisagem. O principal modo final é fullscreen ou modo de extrato. Isso é usado quando o IME é muito grande para o espaço compartilhar com a aplicação de base. Com o IME padrão, você só vai encontrar essa situação quando a tela está em uma orientação horizontal, embora IMEs sejam livres para usá-lo sempre que desejarem. Neste caso, a janela da aplicação é deixada como está, e simplesmente o IME exibe a tela inteira em cima dela, como mostrado aqui: ANDROID, uma visão geral Anderson Duarte de Amorim 218

219 Porque o IME está cobrindo o aplicativo, ele tem a sua área de edição própria, o que mostra o texto, na verdade contida na petição inicial. Existem também algumas oportunidades limitadas à aplicação que tem que personalizar as partes do IME para melhorar a experiência do usuário. Atributos básicos XML para controlar IMEs Há uma série de coisas que o sistema faz para tentar ajudar de trabalho existente com as aplicações IMEs tão bem quanto possível, tais como: Use pan e scan por padrão, a menos que possa razoavelmente supor que o modo de redimensionar vai trabalhar pela existência de listas, percorrer as exibições, etc. Analisar no TextView vários atributos existentes para adivinhar o tipo de conteúdo (números, texto simples, senha, etc.) para ajudar o teclado a exibir um esquema de chave apropriado. Atribuir algumas ações padrão para o IME fullscreen, como "campo próximo" e "feito". Há também algumas coisas simples que você pode fazer na sua aplicação que, muitas vezes, melhoram significativamente sua experiência de usuário. Exceto quando mencionado explicitamente, estes irão trabalhar em qualquer versão da plataforma Android, mesmo os anteriores para o Android 1.5 (uma vez que irá simplesmente ignorar essas novas opções). 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 informação muito mais rica ANDROID, uma visão geral Anderson Duarte de Amorim 219

220 sobre o conteúdo 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 três partes: A classe é a interpretação geral de caracteres. As classes atualmente suportadas são text (plain text), number (número decimal), phone (número de telefone), e datetime (uma data ou hora). A variação é um refinamento da classe. No atributo, normalmente você vai especificar a classe e variante juntamente com a classe como um prefixo. Por exemplo, text address é um campo de texto onde o usuário irá inserir algo que é um endereço de correio (foo@bar.com) para a disposição das teclas terá "caráter" de acesso fácil, e numbersigned é um campo numérico com um sinal. Se somente a classe é especificado, então você obtém o padrão / variante genérica. Sinalizadores adicionais podem ser especificados de abastecimento de refinamento. Esses sinalizadores são específicos para uma classe. Por exemplo, alguns sinalizadores para o text de classe são textcapsentences, textautocorrect e textmultiline. Como exemplo, aqui é o EditText novo para a aplicação 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 aplicação a fazer é especificar o comportamento global da sua janela em relação ao método de entrada. O aspecto mais ANDROID, uma visão geral Anderson Duarte de Amorim 220

221 visível disto é o controle redimensionar VS. pan e scan mode, mas existem outras coisas que você pode fazer bem para melhorar sua experiência de usuário. Você normalmente irá controlar esse comportamento através do android:windowsoftinputmode em cada <activity> em sua AndroidManifest.xml. Como o tipo de entrada, há um par de peças 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 situações onde o usuário move a ele. O sistema não mostrará automaticamente um IME, por padrão, mas em alguns casos pode ser conveniente para o usuário se uma aplicação permite esse comportamento. Você pode solicitar este com statevisible. Há também um número de opções de outro estado para o controle mais detalhado que você pode encontrar na documentação. Um exemplo típico desse campo pode ser visto na atividade de edição do contato, o que garante que ele é redimensionado e exibe automaticamente o IME para o usuário: <activity name="editcontactactivity" android:windowsoftinputmode="statevisible adjustresize">... </activity> Controlando os botões de ação Para a personalização final, vamos olhar para a "ação" de botões no IME. Existem atualmente dois tipos de ações: A tecla enter em um teclado virtual é normalmente ligada a uma ação quando não estiverem operando em um multi-line de edição de texto. Quando em modo de tela cheia, um IME pode também colocar um botão de ação adicional à direita do texto que está sendo editado, dando ao usuário o acesso rápido a uma operação de aplicativos comuns. ANDROID, uma visão geral Anderson Duarte de Amorim 221

222 Estas opções são controladas com o atributo android:imeoptions em TextView. O valor que você fornecer aqui pode ser qualquer combinação de: Uma das ações 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 após este, você pode explicitamente forçar a nenhuma ação com actionnone. O flagnoenteraction informa o IME que a ação não deve estar disponível na tecla enter, mesmo que o texto em si não é multi-linha. Isso evita ter ações irrecuperáveis (enviar) que pode ser tocado acidentalmente pelo usuário durante a digitação. O flagnoaccessoryaction remove o botão de ação da área de texto, deixando mais espaço para o texto. O flagnoextractui remove completamente a área de texto, permitindo que o aplicativo possa ser visto por trás dele. A anterior mensagem de aplicação MI também fornece um exemplo de um uso interessante da imeoptions, para especificar a ação de envio, mas não que seja mostrado a tecla Enter: android:imeoptions="actionsend flagnoenteraction" APIs para controlar IMEs Para um controle mais avançado sobre o IME, há uma variedade de novas APIs que você pode usar. A menos que tenha um cuidado especial (como por meio de reflexão), utilizando essas APIs fará com que seu aplicativo seja incompatível com as versões 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 método de entrada, como explicitamente esconder ou mostrar a área atual do IME de entrada. ANDROID, uma visão geral Anderson Duarte de Amorim 222

223 Há também novas bandeiras controlando a interação do método de entrada, que você pode controlar através da existente Window.addFlags() e novos Window.setSoftInputMode(). A classe PopupWindow acrescentou métodos correspondentes para controlar essas opções 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 atrás do IME atual. A maior parte da interação entre um IME ativos e a aplicação é feita através do android.view.inputmethod.inputconnection. Esta é a API implementada em uma aplicação, que um IME chama para realizar as operações de edição apropriada sobre o pedido. Você não vai precisar se preocupar com isso, pois TextView oferece sua própria implementação para si mesmo. Há também 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 opções IME, e outros dados), novamente, a maioria dos desenvolvedores não precisarão se preocupar com isso, pois TextView cuida disso para você. Criando um método de entrada de dados Para criar um método de entrada (IME) para inserir texto em campos de texto e outras exibições, você precisa estender a classe InputMethodService. Essa classe fornece grande parte da implementação de base para um método de entrada, em termos de administrar o estado e a visibilidade do método de entrada e se comunicar com a atividade visível no momento. O típico ciclo de vida de um InputMethodService: ANDROID, uma visão geral Anderson Duarte de Amorim 223

224 ANDROID, uma visão geral Anderson Duarte de Amorim 224

225 Campos de um aplicativo de texto podem ter diferentes tipos de entrada especificada sobre eles, como o texto de forma livre, numérico, URL, endereço de e busca. Quando você implementa um novo método de entrada, você precisa estar ciente dos tipos de entrada diferentes. Os métodos de entrada não são automaticamente comutados para diferentes tipos de entrada e por isso é necessário para suportar todos os tipos no IME. No entanto, o IME não é responsável por validar a entrada enviada para o aplicativo. Essa é a responsabilidade da aplicação. Por exemplo, o LatinIME equipados com a plataforma Android oferece layouts diferentes para o texto e entrada de número de telefone: Preste atenção específica ao enviar o texto para campos de senha. Certifique-se que a senha não é visível na sua interface do usuário - nem no modo de exibição de entrada ou o ponto de vista dos candidatos. Além disso, não salvar a senha em qualquer lugar sem explicitamente informar o utilizador. A interface do usuário deve ser capaz de escala entre as orientações retrato e paisagem. No modo IME não fullscreen, deixar espaço suficiente para a aplicação para mostrar o campo de texto e qualquer contexto associado. De preferência, não 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 aplicação do texto. Para enviar um evento-chave, você pode simplesmente construir objetos KeyEvent e chamar InputConnection.sendKeyEvent(). Aqui estão alguns exemplos: InputConnection ic = getcurrentinputconnection(); long eventtime = SystemClock.uptimeMillis(); ic.sendkeyevent(new KeyEvent(eventTime, eventtime, ANDROID, uma visão geral Anderson Duarte de Amorim 225

226 KeyEvent.ACTION_DOWN, keyeventcode, 0, 0, 0, 0, KeyEvent.FLAG_SOFT_KEYBOARD KeyEvent.FLAG_KEEP_TOUCH_MODE)); ic.sendkeyevent(new KeyEvent(SystemClock.uptimeMillis(), eventtime, KeyEvent.ACTION_UP, keyeventcode, 0, 0, 0, 0, KeyEvent.FLAG_SOFT_KEYBOARD KeyEvent.FLAG_KEEP_TOUCH_MODE)); Ou então use o seguinte comando: InputMethodService.sendDownUpKeyEvents(keyEventCode); Ao editar texto em um campo de texto, alguns dos métodos mais úteis na android.view.inputmethod.inputconnection são: gettextbeforecursor() gettextaftercursor() deletesurroundingtext() committext() Ações 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 combinálas para criar renderizações 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 botões em todos os aplicativos usam uma instância diferente drawable como pano de fundo. No entanto, todas estas partes drawables possuem um estado comum, o chamado "estado constante". O conteúdo deste estado varia de acordo com o tipo de drawable você está usando, mas, geralmente, contém todas as propriedades que podem ser definidos por um recurso. No caso de um botão, o constante estado contém uma imagem bitmap. Desta forma, todos os botões em todos os aplicativos compartilham o mesmo bitmap, o que economiza um monte de memória. O diagrama abaixo mostra como as entidades são criadas quando você atribuir o recurso de mesma imagem como fundo de dois pontos de vista diferentes. Como você ANDROID, uma visão geral Anderson Duarte de Amorim 226

227 pode ver dois drawables são 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 desperdício de memória, mas pode causar problemas quando você tentar modificar as propriedades de um drawable. Imagine uma aplicação com uma lista de livros. Cada livro tem uma estrela ao lado de seu nome, totalmente opaco quando o usuário marca o livro como um dos favoritos, e translúcido quando o livro não é um favorito. Para conseguir esse efeito, você provavelmente vai escrever o seguinte código em seu método 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); / translúcido ANDROID, uma visão geral Anderson Duarte de Amorim 227

228 Infelizmente, este pedaço de código gera um resultado um pouco estranho: todas as drawables têm a mesma opacidade. Esse resultado é explicado pela constante estado. Mesmo que nós estamos começando uma nova instância 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 instância muda drawable a opacidade de todas as outras instâncias. Android 1.5 e superior oferecem uma maneira muito fácil de resolver esse problema com a nova mutate() método. Quando você chamar esse método 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 são ainda comuns, mesmo depois de uma mutação drawable. O diagrama abaixo mostra o que acontece quando você chama mutate() em um drawable: ANDROID, uma visão geral Anderson Duarte de Amorim 228

229 Agora, o código a ser escrito é parecido com o abaixo. Drawable star = context.getresources().getdrawable(r.drawable.star); if (book.isfavorite()) { star.mutate().setalpha(255); // opaque else { star. mutate().setalpha(70); // translucent Assim, um exemplo se uso, como o citado acerca dos livros, fica como a figura abaixo. Truques de layout: criando layouts eficientes O Android UI Toolkit oferece diversos gerenciadores de layout que são bastante fáceis de usar e, na maioria das vezes, você só precisa das características básicas destes gerenciadores de layout para implementar uma interface de usuário. Ater-se às características básicas infelizmente não é a forma mais eficiente para criar interfaces de usuário. Um exemplo comum é o abuso de LinearLayout, o que leva a uma proliferação de pontos de vista e hierarquia de vista. Cada ponto de vista - ou pior, cada gerente de layout - que você adicionar à sua aplicação tem um custo: layout de inicialização, e o desenho se torna mais lento. A passagem de layout pode ser muito ANDROID, uma visão geral Anderson Duarte de Amorim 229

230 cara principalmente quando você aninhar diversos LinearLayout que utilizam o weight do parâmetro, 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 título em cima e uma descrição opcional abaixo do título. Uma ImageView e dois TextView são posicionados em relação uns aos outros, aqui é o wireframe do layout como capturado pelos HierarchyViewer : A implementação desta estrutura é simples com LinearLayout. O item em si é uma LinearLayout horizontal com um ImageView e um LinearLayout vertical, que contém as duas TextView. Aqui está o código fonte deste esquema: <LinearLayout xmlns: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" ANDROID, uma visão geral Anderson Duarte de Amorim 230

231 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 nível na hierarquia do ponto de vista, por item da lista. A implementação do layout com um RelativeLayout é simples: <RelativeLayout xmlns: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" ANDROID, uma visão geral Anderson Duarte de Amorim 231

232 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_alignparentright="true" android:layout_alignparenttop="true" android:layout_alignwithparentifmissing="true" android:gravity="center_vertical" android:text="my Application" /> </RelativeLayout> Esta nova aplicação se comporta exatamente da mesma forma que a implementação anterior, exceto em um caso: o item da lista que se pretende apresentar tem duas linhas de texto: o título e uma descrição opcional. Quando uma descrição não está disponível para um determinado item da lista o aplicativo simplesmente define a visibilidade do segundo TextView como GONE. Isso funciona perfeitamente com o LinearLayout, mas não com o RelativeLayout: Em um RelativeLayout, as vistas são alinhadas com a sua mãe, com o RelativeLayout em si, ou com outras visões. Por exemplo, nós declaramos que a descrição está alinhado com a parte inferior da RelativeLayout e que o título é colocado acima da descrição e ancorado a mãe da top. Com a descrição GONE, o RelativeLayout não sabe a posição da margem inferior do título. Para resolver esse problema, você pode usar um parâmetro muito especial chamado layout_alignwithparentifmissing. Este parâmetro boolean simplesmente diz ao RelativeLayout a utilizar os seus próprios limites como âncoras quando um alvo está faltando. Por exemplo, se você posicionar uma view à direita de uma GONE e definir alignwithparentifmissing como true, ANDROID, uma visão geral Anderson Duarte de Amorim 232

233 RelativeLayout vez vai ancorar o fim de sua borda esquerda. No nosso caso, usando alignwithparentifmissing fará RelativeLayout alinhar a parte inferior do título com si mesmo. O resultado é o seguinte: O comportamento do nosso layout está perfeito, mesmo quando a descrição é GONE. Ainda melhor, a hierarquia é mais simples porque não estamos usando pesos LinearLayout's é também mais eficiente. A diferença entre as duas implementações torna-se evidente quando se comparam as hierarquias em HierarchyViewer: ANDROID, uma visão geral Anderson Duarte de Amorim 233

234 Truques de layout: usando ViewStub Compartilhamento e reutilização de componentes de interface do usuário são muito fáceis com o Android, graças à tag <include/>. Às vezes é tão fácil criar complexas construções UI que UI termina com um grande número de pontos de vista, algumas das quais raramente são utilizados. Felizmente, o Android oferece um widget muito especial chamado ViewStub, que traz todos os benefícios da <include /> sem poluir a interface do usuário com views raramente utilizadas. A ViewStub é uma visão leve. Não tem dimensão, não tira nada e não participa no layout de qualquer forma. Isso significa que uma ViewStub é muito barata para inflar e muito barata para se manter em uma hierarquia de vista. A ViewStub pode ser melhor descrita como um preguiçoso <include />. O esquema referenciado por um ViewStub é inflado e adicionado à interface do usuário somente quando assim o decidir. A figura a seguir vem da aplicação Prateleira. O principal objetivo da atividade mostrado na imagem é apresentar ao usuário uma lista pesquisável dos livros: ANDROID, uma visão geral Anderson Duarte de Amorim 234

235 A atividade também é usada quando o usuário adiciona ou importa novos livros. Durante essa operação, a Prateleira mostra bits adicionais de interface do usuário. A imagem abaixo mostra a barra de progresso e um botão cancelar que aparecerá na parte inferior da tela durante uma importação: Como a importação de livros não é uma operação comum, pelo menos quando comparado à visita a lista de livros, o painel de importação é representado inicialmente por um ViewStub : ANDROID, uma visão geral Anderson Duarte de Amorim 235

236 Quando o usuário inicia o processo de importação, o ViewStub é inflado e passa a ter o conteúdo do arquivo de layout que faz referência: ANDROID, uma visão geral Anderson Duarte de Amorim 236

237 Para usar um ViewStub, tudo que você precisa é especificar um atributo android:id, para depois inflar, e um atributo android:layout para fazer referência 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 incluído. Finalmente, os parâmetros de layout especificados no topo serão aplicados para a raiz do layout incluído. 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 método inflate(). Você também pode simplesmente alterar a visibilidade do stub para VISIBLE ou INVISIBLE e o stub irá inflar. Note, no entanto que o método 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 após o stub ser inflado, o topo é removido da hierarquia de vista. Como tal, é necessário manter uma referência de vida longa, por exemplo, em um campo de instância de classe, a uma ViewStub. Um ViewStub é um grande compromisso entre a facilidade de programação e de eficiência. Em vez de encher vistas manualmente e adicioná-los em tempo de execução de sua hierarquia de vista, basta usar um ViewStub. É barato e fácil. A única desvantagem de ViewStub é que atualmente não suporta a tag <merge />. Truques de layout: mesclando layouts A tag <merge /> foi criada com a finalidade de otimizar layouts Android, reduzindo o número de níveis em árvores de vista. É mais fácil entender o problema que esta tag resolve olhando um exemplo. O esquema XML a seguir declara um layout que mostra uma imagem com o título em cima dela. A estrutura é bastante simples, uma FrameLayout é usada para empilhar um TextView em cima de um ImageView : ANDROID, uma visão geral Anderson Duarte de Amorim 237

238 <FrameLayout xmlns: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" /> <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> Isso torna o layout bem e nada parece errado com ele: ANDROID, uma visão geral Anderson Duarte de Amorim 238

239 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 razão. Mas como poderíamos nos livrar do presente FrameLayout? Afinal de contas, documentos XML requerem uma marca de raiz e tags em esquemas XML sempre representam instâncias. É 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 visão geral Anderson Duarte de Amorim 239

240 <merge xmlns:android=" <ImageView android:layout_width="fill_parent" android:layout_height="fill_parent" android:scaletype="center" /> <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" </merge> android:text="golden Gate" /> Com esta nova versão, tanto o TextView quanto o ImageView serão adicionados diretamente ao nível superior. O resultado será o mesmo, mas visualmente a hierarquia do ponto de vista é simples: ANDROID, uma visão geral Anderson Duarte de Amorim 240

241 Obviamente, o uso do <merge /> funciona neste caso porque o nodo pai é sempre um FrameLayout. Você não pode aplicar este truque se o layout estava usando um LinearLayout como sua marca raiz, por exemplo. O <merge /> pode ser útil em outras situações, no entanto. Por exemplo, ele funciona perfeitamente quando combinado com o <include />. Você também pode usar <merge /> quando você cria um composto de exibição personalizado. Vamos ver como podemos usar essa tag para criar uma nova visão chamada OkCancelBar que simplesmente mostra dois botões com rótulos personalizados. <merge xmlns:android=" xmlns:okcancelbar=" <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> ANDROID, uma visão geral Anderson Duarte de Amorim 241

242 O código fonte do OkCancelBar é muito simples, porque os dois botões são 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); ANDROID, uma visão geral Anderson Duarte de Amorim 242

243 array.recycle(); Os dois botões são definidos no esquema XML a seguir. Como você pode ver, usamos o <merge /> para adicionar os dois botões diretamente ao OkCancelBar. Cada botão está incluído a partir do arquivo XML externo mesmo layout para torná-los mais fáceis de manter, nós simplesmente substituimos o seu id: <merge xmlns:android=" <include layout="@layout/okcancelbar_button" android:id="@+id/okcancelbar_ok" /> <include layout="@layout/okcancelbar_button" android:id="@+id/okcancelbar_cancel" /> </merge> Nós criamos uma forma flexível e fácil de manter a exibição personalizada que gera uma hierarquia de vista eficiente: ANDROID, uma visão geral Anderson Duarte de Amorim 243

244 O <merge /> é extremamente útil e pode fazer maravilhas em seu código. No entanto, ele sofre de um par de limitações: <merge /> só pode ser usado como a tag raiz de um esquema XML Ao inflar um layout começando com uma <merge /> você deve especificar um pai ViewGroup e você deve definir attachtoroot como true ListView, uma otimização ListView é um dos widgets mais amplamente utilizados no Android. É bastante fácil de usar, muito flexível e incrivelmente poderoso. Um dos problemas mais comuns com ListView acontece quando você tenta usar um plano personalizado. Por padrão, como muitos widgets do Android, o ListView tem um fundo transparente, o que significa que você pode ver através do padrão da janela do fundo. Além disso, ListView permite as margens de desvanecimento por padrão, como você pode ver no topo da tela a seguir - o texto do primeiro item desvanece-se gradualmente para preto. Esta técnica é utilizada em todo o sistema para indicar que o contêiner pode ser rolado. ANDROID, uma visão geral Anderson Duarte de Amorim 244

245 O efeito de fade é implementado usando uma combinação de Canvas.saveLayerAlpha() e Porter-Duff Destination Out blending mode. Infelizmente, as coisas começam 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 padrão 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 otimização do quadro Android ativada por padrão em todas as instâncias do ListView. Esta aplicação 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 prestação em um bitmap fora da tela e, em seguida, requer a mistura extra (o que implica readbacks da memória). ListView s são, na maioria das vezes exibidos em uma base sólida, não há nenhuma razão para enveredar por esse caminho caro. É por isso que nós introduzimos uma otimização chamada de pitada de cor cache. A dica de cor cache é uma cor RGB definido por padrão com a cor de fundo da janela, que é # no tema escuro do ANDROID, uma visão geral Anderson Duarte de Amorim 245

246 Android. Quando esta dica é definida, ListView (na verdade, sua classe base View) sabe que vai recorrer a um fundo sólido e substitui, portanto, a cara renderização 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 não explica por que a lista inteira fica em preto durante um pergaminho. Como mencionado anteriormente, ListView tem um fundo transparente/translúcido por padrão, assim como todos os widgets padrão na caixa de ferramentas UI Android. Isto implica que, quando ListView redesenha seus filhos, tem que misturar as crianças com janela de fundo. Mais uma vez, isto requer readbacks caros de memória que são 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 operações 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 otimização de cor, se você usar uma cor de fundo não-contínua, ou definir a dica para o valor de cor sólido adequado. Você pode fazer isso a partir do código ou, de preferência, a partir de XML, usando o android:cachecolorhint. Para desabilitar a otimização, basta usar a cor transparente # A figura abaixo mostra uma lista com android:cachecolorhint="# " definido no arquivo de layout XML: ANDROID, uma visão geral Anderson Duarte de Amorim 246

247 Como você pode ver, o fade funciona perfeitamente contra o fundo personalizado em madeira. O recurso de cache de sugestão de cor é interessante porque mostra como as otimizações podem tornar sua vida mais difícil em algumas situações. Neste caso específico, porém, o benefício do comportamento padrão compensa a maior complexidade. Live folders Live Folders, introduzida no Android 1.5 API (Nível 3), permitem a exibição de qualquer fonte de dados na tela inicial, sem forçar o usuário a lançar uma aplicação. Uma live folder é simplesmente uma visão em tempo real de um ContentProvider. Como tal, uma live folder pode ser usada para exibir todos os contatos do usuário ou bookmarks, , listas de reprodução, um feed RSS, e assim por diante. As possibilidades são infinitas! A plataforma inclui várias pastas padrão para a exibição de contatos. Por exemplo, a imagem abaixo mostra o conteúdo das pastas ao vivo que mostra todos os contatos com um número de telefone: ANDROID, uma visão geral Anderson Duarte de Amorim 247

248 Se a sincronização de contatos acontece em segundo plano enquanto o usuário está visitando esta pasta ao vivo, o usuário verá a mudança acontecer em tempo real. Live folders não são apenas úteis, mas elas também são fáceis de adicionar ao seu aplicativo. Este artigo mostra como adicionar uma live folder para uma aplicação, como por exemplo as chamadas Prateleiras. Para entender melhor como trabalham as pastas, você pode baixar o código fonte da aplicação e modificá-lo seguindo as instruções abaixo. Para dar ao usuário a opção de criar uma nova pasta para um aplicativo, você primeiro precisa criar uma nova atividade com a intenção de filtro cuja ação é android.intent.action.create_live_folder. Para isso, basta abrir AndroidManifest.xml e adicionar algo semelhante a isto: <activity android:name=".activity.bookshelflivefolder" android:label="bookshelf"> <intent-filter> <action android:name="android.intent.action.create_live_folder" /> <category android:name="android.intent.category.default" /> </intent-filter> </activity> O rótulo e o ícone desta atividade são o que o usuário verá na tela inicial quando se escolhe uma pasta: ANDROID, uma visão geral Anderson Duarte de Amorim 248

249 Uma vez que você só precisa de uma intenção de filtro, é possível e, por vezes aconselhável, a reutilização de uma atividade existente. No caso de Prateleiras, vamos criar uma nova atividade, org.curiouscreature.android.shelves.activity.bookshelflivefolder. O papel desta atividade é enviar um resultado Intent para Página contendo a descrição da live folder: o seu nome, ícone, modo de apresentação e conteúdo URI. O URI conteúdo é muito importante, pois descreve o que ContentProvider será usado para preencher a live folder. O código da atividade é muito simples, como você pode ver aqui: public class BookShelfLiveFolder extends Activity { public static final Uri CONTENT_URI = 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 intenção de um URI, content://shelves/live_folders/books, e três extras para descrever a pasta ao vivo. Existem outros extras e constantes que você pode usar e você deve consultar a documentação do android.provider.livefolders para mais detalhes. ANDROID, uma visão geral Anderson Duarte de Amorim 249

250 Quando a Home recebe esta ação, uma nova live folder é criada no desktop do usuário, com o nome e o ícone que você forneceu. Então, quando o usuário clica na pasta para abri-la ao vivo, a Home consulta o provedor de conteúdo referenciado pelo URI fornecido. Prestadores de pastas Live devem obedecer a regras específicas de nomeação. O Cursor retornado pelo método 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 descrição, a intenção de associar ao item (acionado quando o usuário clicar nesse item), etc. Novamente, consulte a documentação do android.provider.livefolders para mais detalhes. No nosso exemplo, tudo o que precisamos fazer é modificar o provedor existente nas prateleiras chamado org.curiouscreature.android.shelves.provider.booksprovider. Primeiro, precisamos modificar o URI_MATCHER para reconhecer nosso content://shelves/live_folders/books URI de conteúdo: private static final int LIVE_FOLDER_BOOKS = 4; //... URI_MATCHER.addURI(AUTHORITY, "live_folders/books", LIVE_FOLDER_BOOKS); Então, precisamos criar um mapa de nova projeção para o cursor. Um mapa de projeção 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 título e uma descrição para cada linha, Home irá exibir automaticamente cada item da live folder com duas linhas de texto. Finalmente, vamos ANDROID, uma visão geral Anderson Duarte de Amorim 250

251 implementar a query(), fornecendo o nosso mapa de projeção 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 títulos e autores, e bastou algumas linhas de código: ANDROID, uma visão geral Anderson Duarte de Amorim 251

252 A API de live folders é extremamente simples e depende apenas de intenções e URI. Se você quiser ver mais exemplos de aplicação das pastas, você pode ler o código-fonte do aplicativo de contatos e do provedor de Contatos. Live Wallpapers Começando com o Android 2.1 (API Nível 7), os utilizadores podem agora desfrutar de papéis de parede ao vivo - mais ricos, animados, cenários interativos - em suas telas iniciais. Um papel de parede ao vivo é muito semelhante a uma aplicação Android normal e tem acesso a todas as facilidades da plataforma: SGL (desenho 2D), OpenGL (desenho 3D), GPS, acelerômetro, acesso à rede, etc. Os papéis de parede ao vivo, incluído no Nexus One, demonstram o uso de algumas dessas APIs para criar experiências divertidas e interessantes. Por exemplo, o papel de parede da grama usa a localização do telefone para calcular o nascer e o por do sol, a fim de exibir o céu adequado. Criar o seu próprio papel de parede ao vivo é fácil, especialmente se você teve experiência anterior com SurfaceView ou Canvas. Para saber como criar um papel de parede ao vivo, você deve verificar se o código de exemplo CubeLiveWallpaper. Em termos de execução, um papel de parede ao vivo é muito similar a um Service. A única diferença é a adição de um novo método, oncreateengine(), cujo objetivo é criar um WallpaperService.Engine. O dispositivo é responsável pela gestão do ciclo de vida e desenho de um papel de parede. O sistema fornece uma superfície 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 código, tanto quanto possível para evitar o uso excessivo de CPU, não só para a vida da bateria, mas também para evitar a abrandar o resto do sistema. É também por isso que a parte mais importante do ciclo de vida de um papel de parede é quando se torna visível, como indicado por uma ANDROID, uma visão geral Anderson Duarte de Amorim 252

253 chamada para onvisibilitychanged(). Quando invisíveis, como quando o usuário inicia um aplicativo que cobre a tela inicial, o papel de parede tem que parar todas as atividades. O dispositivo também pode implementar vários métodos para interagir com o usuário ou o aplicativo de origem. Por exemplo, para reagir ao toque, basta implementar ontouchevent(). Finalmente, os aplicativos podem enviar comandos arbitrários para o papel de parede ao vivo. Atualmente, apenas o pedido inicial padrão envia comandos para o oncommand() do papel de parede ao vivo: 1. android.wallpaper.tap: Quando o usuário bate um espaço vazio na área de trabalho. Este comando é interpretado pelo dispositivo para fazer o papel de parede reagir à interação do usuário. 2. android.home.drop: Quando o usuário solta um ícone ou um widget no espaço de trabalho. Se você está desenvolvendo um papel de parede ao vivo, lembre-se que o recurso só é suportado no Android 2.1 (API nível 7) e versões 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 código 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 usuários de aplicações disponíveis. Quando você declarar esse recurso, o Android Market exibe sua aplicação apenas aos usuários cujas dispositivos suportam wallpapers ao vivo, enquanto oculta de outros dispositivos sobre os quais não seria capaz de executar. ANDROID, uma visão geral Anderson Duarte de Amorim 253

254 Usando webviews Um pequeno aplicativo chamado WebViewDemo mostra como você pode adicionar conteúdo da Web em seu aplicativo. Você pode encontrá-la no projeto de aplicativos para Android. Esta aplicação demonstra como você pode incorporar um WebView em uma atividade e também como você pode ter comunicação bidirecional entre o aplicativo e o conteúdo da web. Um WebView utiliza o mesmo processamento e motor de JavaScript, o navegador, mas ele é executado sob o controle de sua aplicação. O WebView podem ser em tela cheia ou você pode misturá-la com outras visões. O WebView pode baixar conteúdo da web, ou pode vir a partir de arquivos locais armazenados em seu diretório de ativos. O conteúdo pode até ser gerado dinamicamente pelo código do aplicativo. Este aplicativo não faz muita coisa: quando você clica sobre o Android, ele levanta o braço. Isso poderia, naturalmente, ser facilmente conseguido com um pouco de JavaScript. Em vez disso, porém, WebViewDemo toma um caminho um pouco mais complicado para ilustrar duas características muito poderosa de WebView. Primeiro, o JavaScript em execução dentro do WebView pode se ligar com o código em sua atividade. Você pode usar isso para fazer suas ações disparar JavaScript como começar 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 métodos você ANDROID, uma visão geral Anderson Duarte de Amorim 254

Usando e Gerenciando Activities

Usando e Gerenciando Activities Usando e Gerenciando Activities Ciclo de vida Activity 2 Especificando a execução Especifica a Activity que é ponto principal de entrada de sua aplicação Se a ação MAIN action ou a categoria LAUNCHER não

Leia mais

Android DEFINIÇÕES E CICLO DE VIDA. Prof. Dr. Joaquim assunção.

Android DEFINIÇÕES E CICLO DE VIDA. Prof. Dr. Joaquim assunção. Android DEFINIÇÕES E CICLO DE VIDA Prof. Dr. Joaquim assunção. Parte 1/2 Bases Fundamentos Os aplicativos do Android são programados em linguagem de programação Java ou Kotlin. As ferramentas Android SDK

Leia mais

TUTORIAL ANDROID ACTIVITY - CONSTRUÇÃO DE TELAS

TUTORIAL ANDROID ACTIVITY - CONSTRUÇÃO DE TELAS TUTORIAL ANDROID ACTIVITY - CONSTRUÇÃO DE TELAS Uma activity é um componente do aplicativo que fornece uma tela com o qual os usuários podem interagir. Uma aplicação geralmente consiste de múltiplas activities,

Leia mais

Programação para Dispositivos Móveis

Programação para Dispositivos Móveis Programação para Dispositivos Móveis Professor Ariel da Silva Dias Desenvolvendo para Android Android Core Uma aplicação Android é formada por um conjunto de componentes; A este conjunto damos o nome de

Leia mais

Android. Interfaces: widgets

Android. Interfaces: widgets Android Interfaces: widgets Relembrando... Após a criação do projeto, será criada uma estrutura de diretórios necessária para um projeto Android. A pasta src contém os fontes das classe que representam

Leia mais

Desenvolvimento de um aplicativo básico usando o Google Android

Desenvolvimento de um aplicativo básico usando o Google Android Desenvolvimento de um aplicativo básico usando o Google Android (Activity e o seu Ciclo de Vida) Programação de Dispositivos Móveis Mauro Lopes Carvalho Silva Professor EBTT DAI Departamento de Informática

Leia mais

Desenvolvimento de um aplicativo básico usando o Google Android

Desenvolvimento de um aplicativo básico usando o Google Android Desenvolvimento de um aplicativo básico usando o Google Android (Activity e Intent) Programação de Dispositivos Móveis Mauro Lopes Carvalho Silva Professor EBTT DAI Departamento de Informática Campus Monte

Leia mais

Android OLÁ MUNDO MÓVEL. Prof. Dr. Joaquim assunção.

Android OLÁ MUNDO MÓVEL. Prof. Dr. Joaquim assunção. Android OLÁ MUNDO MÓVEL Prof. Dr. Joaquim assunção. Parte 1/3 SDK e Android Studio Java SE Development Kit Download and Install JDK 6 http://www.oracle.com/technetwork/java/javase/downloads/index.html

Leia mais

Log, Ciclo de Vida e Diálogos. Prof. Fellipe Aleixo (fellipe.aleixo@ifrn.edu.br)

Log, Ciclo de Vida e Diálogos. Prof. Fellipe Aleixo (fellipe.aleixo@ifrn.edu.br) Log, Ciclo de Vida e Diálogos Prof. Fellipe Aleixo (fellipe.aleixo@ifrn.edu.br) Conteúdo Log Classe android.u:l.log LogCat Ciclo de Vida Pilha de a:vidades Métodos e estados da a:vidade Instance State

Leia mais

Aplicações que executam, em geral, processos longos em background desprovidos de interface. Usado para executar tarefas em segundo plano

Aplicações que executam, em geral, processos longos em background desprovidos de interface. Usado para executar tarefas em segundo plano Serviços Serviços Aplicações que executam, em geral, processos longos em background desprovidos de interface. Usado para executar tarefas em segundo plano Estas tarefas não possuem um tempo definido de

Leia mais

Módulo 2 - Novas Activities Android. Programação Orientada a Objetos Prof. Rone Ilídio - UFSJ

Módulo 2 - Novas Activities Android. Programação Orientada a Objetos Prof. Rone Ilídio - UFSJ Módulo 2 - Novas Activities Android Programação Orientada a Objetos Prof. Rone Ilídio - UFSJ Inserindo a segunda activity Para inserir uma nova activity basta clicar com o botão direito sobre o pacote,

Leia mais

Capítulo 02: Cadastro de Alunos

Capítulo 02: Cadastro de Alunos Capítulo 02: Cadastro de Alunos Instrutor Programador desde 2000 Aluno de doutorado Mestre em informática pelo ICOMP/UFAM Especialista em aplicações WEB FUCAPI marcio.palheta@gmail.com sites.google.com/site/marcio

Leia mais

Desenvolvimento de Aplicativos Android

Desenvolvimento de Aplicativos Android Desenvolvimento de Aplicativos Android Criando uma Interface Simples A partir do diretório res/layout/ abra o activity_main.xml. Este arquivo XML define o layout da sua activity. Ele contém o texto padrão

Leia mais

Programação para Dispositivos Móveis. Activity e Intent

Programação para Dispositivos Móveis. Activity e Intent Programação para Dispositivos Móveis Activity e Intent Activity É um módulo único e independente do aplicativo que fornece uma tela com a qual os usuários podem interagir O gerenciamento na memória, o

Leia mais

Fragments. Criar um novo projeto. Selecionar a API. Navigation Drawer Activity. Fragments. Luiz Eduardo Guarino de Vasconcelos

Fragments. Criar um novo projeto. Selecionar a API. Navigation Drawer Activity. Fragments. Luiz Eduardo Guarino de Vasconcelos Criar um novo projeto Selecionar a API Navigation Drawer Activity MainActivity Finish. Adicionar as Dependências do ButterKnife. butterknife butterknife-compiler. Veja o tutorial do ButterKnife no site.

Leia mais

PROGRAMAÇÃO PARA DISPOSITIVOS MÓVEIS

PROGRAMAÇÃO PARA DISPOSITIVOS MÓVEIS PROGRAMAÇÃO PARA DISPOSITIVOS MÓVEIS Hello World Professor: Danilo Giacobo OBJETIVOS DA AULA Desenvolver o primeiro aplicativo Android Se familiarizar com o ambiente de desenvolvimento Conhecer os principais

Leia mais

Expectativa de respostas

Expectativa de respostas Expectativa de respostas Prova Objetiva Questão Resposta 1 A 2 A 3 C 4 B 5 B 6 ANULADA 7 A 8 D 9 A 10 C 11 B 12 ANULADA 13 C 14 D 15 B 16 B 17 ANULADA 18 C 19 C 20 C Prova Discursiva 1. Explique cada um

Leia mais

Computação Móvel Activity (Ref. Cap. 4)

Computação Móvel Activity (Ref. Cap. 4) Universidade Federal de Ouro Preto Departamento de Computação e Sistemas - DECSI Computação Móvel Activity (Ref. Cap. 4) Vicente Amorim vicente.amorim.ufop@gmail.com Sumário * Activity - Classes FragmentActivity

Leia mais

Utilitário de Configuração do Computador Guia do Usuário

Utilitário de Configuração do Computador Guia do Usuário Utilitário de Configuração do Computador Guia do Usuário Copyright 2007 Hewlett-Packard Development Company, L.P. Windows é uma marca registrada da Microsoft Corporation nos Estados Unidos. As informações

Leia mais

PROGRAMAÇÃO PARA DISPOSITIVOS MÓVEIS

PROGRAMAÇÃO PARA DISPOSITIVOS MÓVEIS PROGRAMAÇÃO PARA DISPOSITIVOS MÓVEIS A classe Intent Professor: Danilo Giacobo OBJETIVOS DA AULA Alternar entre múltiplas telas de uma aplicação Android. Conhecer a classe Intent. Associar as telas do

Leia mais

Programação para Android. Aula 06: Activity, menus e action bar

Programação para Android. Aula 06: Activity, menus e action bar Programação para Android Aula 06: Activity, menus e action bar Activity A classe Activity é quem gerencia a interface com o usuário. Ela quem recebe as requisições, as trata e processa. Na programação

Leia mais

Programação para a Plataforma Android Aula 16. Fragmentos

Programação para a Plataforma Android Aula 16. Fragmentos Programação para a Plataforma Android Aula 16 Fragmentos O que são fragmentos Como combinar múl?plas visões em uma única tela? Como lidar com telas de tamanhos variados? Como modificar a visão de uma a?vidade

Leia mais

Manual do KXSLDbg. Keith Isdale Tradução: Marcus Gama

Manual do KXSLDbg. Keith Isdale Tradução: Marcus Gama Keith Isdale Tradução: Marcus Gama 2 Conteúdo 1 Introdução 5 1.1 Recursos........................................... 5 2 Usando o KXSLDbg 6 2.1 Configurando uma Sessão do KXSLDbg.........................

Leia mais

Computação II Orientação a Objetos

Computação II Orientação a Objetos Computação II Orientação a Objetos Fabio Mascarenhas - 2016.2 http://www.dcc.ufrj.br/~fabiom/java Android Android é um sistema operacional para dispositivos móveis Kernel Linux, drivers e bibliotecas do

Leia mais

1. Introdução O que é Microsoft PowerPoint Recursos de PowerPoint. Introdução

1. Introdução O que é Microsoft PowerPoint Recursos de PowerPoint. Introdução 1. Introdução 1.1. O que é Microsoft PowerPoint 2007 Microsoft Office PowerPoint 2007 é um software de apresentação gráfica produzido pela Microsoft Corporation para o sistema operacional Microsoft Windows.

Leia mais

Outlook Web App (OWA)

Outlook Web App (OWA) Outlook Web App (OWA) 2010 Índice 1. O que é o Outlook Web App (OWA) 2010?... 3 2. Como acessar o OWA:... 3 3. Como navegar no OWA... 5 4. As seções do OWA... 5 5. O painel de mensagens OWA... 6 5.1 Como

Leia mais

Google Drive Formulários

Google Drive Formulários Google Drive Formulários Sumário Formulário de pesquisa com o Google Drive... 3 Criando o formulário... 3 Criando as perguntas... 4 Configurando a página de confirmação... 9 Adicionando conteúdo multimídia

Leia mais

Centro de Suporte. (Sistema Android) RCAMail Manual de Utilização Página 1

Centro de Suporte. (Sistema Android) RCAMail Manual de Utilização Página 1 (Sistema Android) Manual de Utilização Página 1 Sumário 1. Acesso ao no Android (aplicativo E-mail )... 4 2. Tela inicial do aplicativo E-mail e suas pastas... 5 2.1 Pasta Entrada... 5 2.2 Pasta Rascunhos...

Leia mais

Manual Coleção Interativa Papel Professor Versão 2.5.3

Manual Coleção Interativa Papel Professor Versão 2.5.3 Manual Coleção Interativa Papel Professor / 33 Manual Coleção Interativa Papel Professor Versão 2.5.3 Manual Coleção Interativa Papel Professor 2/ 33 Manual Coleção Interativa ACESSAR A COLEÇÃO INTERATIVA...

Leia mais

Retrofit. Criar um novo projeto. Selecionar a API. Retrofit para consumir Web Service Luiz Eduardo Guarino de Vasconcelos

Retrofit. Criar um novo projeto. Selecionar a API. Retrofit para consumir Web Service Luiz Eduardo Guarino de Vasconcelos Retrofit Criar um novo projeto Selecionar a API Empty Activity MainActivity Finish. Adicionar Novas Dependências Menu File > Project Structure Modulo app > Aba Dependencies Clique em adicionar (+) no canto

Leia mais

Pré-requisitos: Conhecimentos de informática gerencial e lógica de programação.

Pré-requisitos: Conhecimentos de informática gerencial e lógica de programação. CURSO DESENVOLVEDOR FRONT-END HTML5/CSS3/JavaScript Objetivo: Este curso visa introduzir o aluno do mundo do desenvolvimento Web, com aplicabilidade, ensino e capacitação nas principais linguagens de diagramação

Leia mais

Índice. 1. Introdução Instalação: Eclipse e Android Primeira aplicação em Android... 11

Índice. 1. Introdução Instalação: Eclipse e Android Primeira aplicação em Android... 11 Índice 1. Introdução... 03 2. Instalação: Eclipse e Android... 04 3. Primeira aplicação em Android... 11 1. Introdução Android trata-se de um sistema operacional baseado em Linux. No dia 05 de novembro

Leia mais

Tutorial Android Speech

Tutorial Android Speech Tutorial Android Speech O sistema operacional Android já dispõe de uma funcionalidade interna para síntese e reconhecimento de voz que pode ser incorporado a qualquer aplicação. Essa funcionalidade utiliza

Leia mais

Introdução a Tecnologia da Informação

Introdução a Tecnologia da Informação Introdução a Tecnologia da Informação Informática Básica Software de apresentação Prof. Jonatas Bastos Power Point p Faz parte do pacote Microsoft Office; p Software com muitos recursos para construção

Leia mais

Manual Gerenciador de Aprendizagem Papel Professor Versão 2.5.3

Manual Gerenciador de Aprendizagem Papel Professor Versão 2.5.3 Manual GA, Papel Professor / 37 Manual Gerenciador de Aprendizagem Papel Professor Versão 2.5.3 Manual GA, Papel Professor 2/ 37 Manual Gerenciador de Aprendizagem ACESSAR O GERENCIADOR DE APRENDIZAGEM...

Leia mais

Utilitário de Configuração do Computador Guia do Usuário

Utilitário de Configuração do Computador Guia do Usuário Utilitário de Configuração do Computador Guia do Usuário Copyright 2008 Hewlett-Packard Development Company, L.P. Windows é uma marca registrada da Microsoft Corporation nos Estados Unidos. As informações

Leia mais

Migrando para o Access 2010

Migrando para o Access 2010 Neste guia Microsoft O Microsoft Access 2010 está com visual bem diferente, por isso, criamos este guia para ajudar você a minimizar a curva de aprendizado. Leia-o para saber mais sobre as principais partes

Leia mais

ÍNDICE. PowerPoint CAPÍTULO 1... CAPÍTULO 2... CAPÍTULO 3...

ÍNDICE. PowerPoint CAPÍTULO 1... CAPÍTULO 2... CAPÍTULO 3... ÍNDICE CAPÍTULO 1... Iniciando o PowerPoint 2016...08 Conhecendo a tela...09 Exibir réguas e grades...14 Slide mestre...16 Iniciar uma apresentação em branco...17 Abrir uma apresentação existente...17

Leia mais

Prof: Ricardo Quintão Site:

Prof: Ricardo Quintão   Site: Prof: Ricardo Quintão email: ricardo.quintao@uva.br Site: www.rgquintao.com.br Vamos agora criar o nosso primeiro projeto Android. Na criação de um projeto novo, o ADT já cria um programa de exemplo que

Leia mais

Executar uma macro clicando em um botão da Barra de Ferramentas de Acesso Rápido

Executar uma macro clicando em um botão da Barra de Ferramentas de Acesso Rápido Página 1 de 8 Excel > Macros Executar uma macro Mostrar tudo Há várias maneiras de executar uma macro no Microsoft Excel. Macro é uma ação ou um conjunto de ações que você pode usar para automatizar tarefas.

Leia mais

Utilização do Fiery WebSpooler

Utilização do Fiery WebSpooler 18 Utilização do Fiery WebSpooler O Fiery WebSpooler permite o rastreamento e o gerenciamento de trabalhos a partir de diversas plataformas na Internet ou intranet. O Fiery WebSpooler, uma das ferramentas

Leia mais

Ashampoo Rescue Disc

Ashampoo Rescue Disc 1 Ashampoo Rescue Disc Este programa permite você criar um CD, DVD ou Pendrive de recuperação. O Sistema de recuperação é destinado a dois tipos de situações: 1. Restaurar um backup para o seu disco principal.

Leia mais

WordPress Institucional UFPel Manual do tema UFPel 2.0

WordPress Institucional UFPel Manual do tema UFPel 2.0 PRÓ-REITORIA DE GESTÃO DA INFORMAÇÃO E COMUNICAÇÃO COORDENAÇÃO DE SISTEMAS DE INFORMAÇÃO SEÇÃO DE PROJETOS DE WEBSITES WordPress Institucional UFPel Manual do tema UFPel 2.0 Versão 2.8.5 Julho de 2017

Leia mais

Inicialização Rápida do GroupWise Messenger 18 Móvel

Inicialização Rápida do GroupWise Messenger 18 Móvel Inicialização Rápida do GrpWise Messenger 18 Móvel Novembro de 2017 Inicialização Rápida do GrpWise Messenger Móvel O GrpWise Messenger está disponível para seu dispositivo móvel ios, Android BlackBerry

Leia mais

Questionário de revisão para AV1 de Informática Aplicada Valor 1,0 ponto - Deverá ser entregue no dia da prova.

Questionário de revisão para AV1 de Informática Aplicada Valor 1,0 ponto - Deverá ser entregue no dia da prova. Questionário de revisão para AV1 de Informática Aplicada Valor 1,0 ponto - Deverá ser entregue no dia da prova. 1) Observe os seguintes procedimentos para copiar um arquivo de uma pasta para outra pasta

Leia mais

DESENVOLVIMENTO PARA DISPOSITIVOS MÓVEIS. PROFª. M.Sc. JULIANA H Q BENACCHIO

DESENVOLVIMENTO PARA DISPOSITIVOS MÓVEIS. PROFª. M.Sc. JULIANA H Q BENACCHIO DESENVOLVIMENTO PARA DISPOSITIVOS MÓVEIS PROFª. M.Sc. JULIANA H Q BENACCHIO Action Bar A action bar é a barra superior da aplicação Surgiu no Android 3.0 (API Level 11) Benefícios Identifica a aplicação

Leia mais

Associações de arquivos. Mike McBride Tradução: Lisiane Sztoltz

Associações de arquivos. Mike McBride Tradução: Lisiane Sztoltz Mike McBride Tradução: Lisiane Sztoltz 2 Conteúdo 1 Associações de arquivos 4 1.1 Introdução.......................................... 4 1.2 Como usar este módulo.................................. 4 1.2.1

Leia mais

Cisco Unified Attendant Console Compact Edition v8.6.5

Cisco Unified Attendant Console Compact Edition v8.6.5 Este guia descreve resumidamente os atalhos de teclado, controles de interface e símbolos de status do telefone do Cisco Unified Attendant Console Compact Edition. Os principais elementos da interface

Leia mais

Classes o Objetos. Classes, objetos, métodos e variáveis de instância

Classes o Objetos. Classes, objetos, métodos e variáveis de instância Classes o Objetos Um recurso comum de cada aplicativo feito até agora é que todas as instruções que realizavam tarefas localizavam-se no método main. Se você tornar parte de uma equipe de desenvolvimento

Leia mais

Bem-vindo ao tópico sobre valores definidos pelo usuário.

Bem-vindo ao tópico sobre valores definidos pelo usuário. Bem-vindo ao tópico sobre valores definidos pelo usuário. 1 Após a conclusão deste tópico, você estará apto a adicionar valores definidos pelo usuário a campos de formulário para automatizar a entrada

Leia mais

Com a OABRJ Digital você trabalha de forma colaborativa, simples e objetiva, em uma única tela.

Com a OABRJ Digital você trabalha de forma colaborativa, simples e objetiva, em uma única tela. MANUAL A OABRJ Digital possui uma interface simples e de fácil utilização Com a OABRJ Digital você trabalha de forma colaborativa, simples e objetiva, em uma única tela. Acesso ao OAB Digital Tela Principal

Leia mais

Android: Ciclo de vida da Activity

Android: Ciclo de vida da Activity Se sua aplicação estiver em execução e o celular receber uma ligação? O que acontecerá com seu aplicativo? Quais métodos serão executados e em qual ordem? Para respondermos essas perguntas e entendermos

Leia mais

Utilização de Base de Dados com BluePlant. Sumário

Utilização de Base de Dados com BluePlant. Sumário Nota de Aplicação NAP154 Utilização de Base de Dados com BluePlant Sumário 1. Descrição... 2 2. Introdução... 2 3. Definição da Arquitetura de Referência... 2 3.1 Material Utilizado no Exemplo... 2 4.

Leia mais

Carregar Documentos Fiscais Fornecedor (Modelo 93) Fatura de Conhecimento de Transporte. Última Atualização 11/01/2019

Carregar Documentos Fiscais Fornecedor (Modelo 93) Fatura de Conhecimento de Transporte. Última Atualização 11/01/2019 Carregar Documentos Fiscais Fornecedor (Modelo 93) Fatura de Conhecimento de Transporte Última Atualização 11/01/2019 Menu I. Objetivos II. Como Acessar III. Envio de Documento Fiscal Não Eletrônico Fatura

Leia mais

Universidade Federal do Paraná

Universidade Federal do Paraná Universidade Federal do Paraná Departamento de Informática Ciência da Computação Tópicos em Computação Android Ciclo de vida activities, tasks, modelo de navegação Prof. Eduardo Todt 2018 objetivos Conhecer

Leia mais

Android Banco de Dados. Ivan Nicoli

Android Banco de Dados. Ivan Nicoli Android Banco de Dados Ivan Nicoli SQLite O Android tem suporte ao SQLite (http://www.sqlite.org), um leve e poderoso banco de dados. Cada aplicação pode criar um ou mais banco de dados, que ficam localizados

Leia mais

GUIA PRÁTICO. Câmera frontal. Diminuir/ Aumentar volume. Tecla Liga/ Desliga. Câmera. Sensor de impressão digital 5026J CJB1L43ALBRA

GUIA PRÁTICO. Câmera frontal. Diminuir/ Aumentar volume. Tecla Liga/ Desliga. Câmera. Sensor de impressão digital 5026J CJB1L43ALBRA GUIA PRÁTICO Câmera frontal Diminuir/ Aumentar volume 6" Tecla Liga/ Desliga Câmera Sensor de impressão digital 5026J 1 CJB1L43ALBRA 1 Carregue completamente o dispositivo para o primeiro uso. Abra a tampa

Leia mais

Informática. LibreOffice Impress. Professor Márcio Hunecke.

Informática. LibreOffice Impress. Professor Márcio Hunecke. Informática LibreOffice Impress Professor Márcio Hunecke Informática Aula XX LIBREOFFICE IMPRESS Modos de Exibição Normal Alterna para a exibição normal, na qual é possível criar e editar slides. Estrutura

Leia mais

UNIVERSIDADE FEDERAL DO RIO GRANDE DO NORTE Ficha de Expectativa de Resposta da Prova Escrita

UNIVERSIDADE FEDERAL DO RIO GRANDE DO NORTE Ficha de Expectativa de Resposta da Prova Escrita UNIVERSIDADE FEDERAL DO RIO GRANDE DO NORTE Ficha de Expectativa de Resposta da Prova Escrita Departamento Acadêmico ou Unidade Acadêmica Especializada em Ciências Agrárias Unidade Acadêmica Especializada

Leia mais

Dreamweaver CS5 Plano de Aula - 24 Aulas (Aulas de 1 Hora).

Dreamweaver CS5 Plano de Aula - 24 Aulas (Aulas de 1 Hora). 4149 - Dreamweaver CS5 Plano de Aula - 24 Aulas (Aulas de 1 Hora). Aula 1 Capítulo 1 - Introdução 1.1. Novidades do Dreamweaver CS5...23 1.2. Área de Trabalho...23 1.2.1. Tela de Boas-vindas...24 1.2.2.

Leia mais

Manual do Usuário Brother Meter Read Tool

Manual do Usuário Brother Meter Read Tool Manual do Usuário Brother Meter Read Tool BRA-POR Versão 0 Direitos autorais Copyright 2017 Brother Industries, Ltd. Todos os direitos reservados. As informações incluídas neste documento estão sujeitas

Leia mais

Login. Criar uma nova Activity. Login. Luiz Eduardo Guarino de Vasconcelos

Login. Criar uma nova Activity. Login. Luiz Eduardo Guarino de Vasconcelos Criar uma nova Activity Observe no AndroidManifest.xml que foi criada a segunda Activity. Nesse arquivo: - defini-la como a primeira a ser executada (recortar o intent-filter da MainActivity para a Activity)

Leia mais

Criando as primeiras telas (Activity)

Criando as primeiras telas (Activity) File > New > New Project Observe o conteúdo dos arquivos MainActivity e activity_main.xml. Alterar strings.xml primeiro app Usar FindUsages para

Leia mais

Operação remota utilizando o EOS Utility

Operação remota utilizando o EOS Utility Observe que, neste documento, as páginas no manual Wi-Fi do produto são referenciadas. Consulte o site da Canon para baixar o PDF completo. Com o EOS Utility é possível utilizar o Pairing Software (software

Leia mais

LibreOffice Calc (Editor de planilha eletrônica) Lara Popov Zambiasi Bazzi Oberderfer professores.chapeco.ifsc.edu.

LibreOffice Calc (Editor de planilha eletrônica) Lara Popov Zambiasi Bazzi Oberderfer professores.chapeco.ifsc.edu. LibreOffice Calc (Editor de planilha eletrônica) Lara Popov Zambiasi Bazzi Oberderfer larapopov@ifscedubr professoreschapecoifscedubr/lara Libre Office Calc É um editor de planilha eletrônica, que tem

Leia mais

COMO COMEÇAR Guia de Referência Rápida MAPAS

COMO COMEÇAR Guia de Referência Rápida MAPAS www.farmcommand.com COMO COMEÇAR Guia de Referência Rápida MAPAS www.farmersedge.com.br MAPAS Você pode gerenciar e visualizar sua fazenda através do Gerenciados de Mapas. Por padrão, sua fazenda irá aparecer

Leia mais

Programação para Dispositivos Móveis

Programação para Dispositivos Móveis Prof. MSc. Flávio Barros flavioifma@gmail.com www.flaviobarros.com.br Programação para Dispositivos Móveis Aula - Service Caxias - MA Roteiro Service Service Fundamentos Componente responsável por rodar

Leia mais

MANUAL DO PROFESSOR AMBIENTE VIRTUAL DE APRENDIZAEGEM

MANUAL DO PROFESSOR AMBIENTE VIRTUAL DE APRENDIZAEGEM MANUAL DO PROFESSOR AMBIENTE VIRTUAL DE APRENDIZAEGEM MANUAL DO PROFESSOR AMBIENTE VIRTUAL DE APRENDIZAGEM Ana Amélia de Souza Pereira Christien Lana Rachid Maio/2017 LISTA DE FIGURA Figura 1 - Página

Leia mais

Informática. Microsoft Outlook Professor Márcio Hunecke.

Informática. Microsoft Outlook Professor Márcio Hunecke. Informática Microsoft Outlook 2007 Professor Márcio Hunecke www.acasadoconcurseiro.com.br Informática MICROSOFT OUTLOOK O QUE É O OUTLOOK? O Microsoft Outlook 2007 oferece excelentes ferramentas de gerenciamento

Leia mais

Plano de Aula - Dreamweaver CS5 - cód Horas/Aula

Plano de Aula - Dreamweaver CS5 - cód Horas/Aula Plano de Aula - Dreamweaver CS5 - cód.4149 24 Horas/Aula Aula 1 Capítulo 1 - Introdução Aula 2 Continuação do Capítulo 1 - Introdução Aula 3 Capítulo 2 - Site do Dreamweaver 1.1. Novidades do Dreamweaver

Leia mais

Instalação e utilização do Software Pináculo SMS

Instalação e utilização do Software Pináculo SMS Instalação e utilização do Software Pináculo SMS Características do produto Pináculo SMS: Sem limite de quantidade de envios de SMS; Limite de 140 caracteres por mensagem; Histórico de mensagens enviadas

Leia mais

COLABORATIVO Ver 1 01 de Dezembro de 2016

COLABORATIVO Ver 1 01 de Dezembro de 2016 COLABORATIVO Ver 1 01 de Dezembro de 2016 Menu Colaborativo O CRM Senior prioriza o fluxo da informação na organização, onde possui agenda corporativa dos usuários, tarefas, eventos, recados e consulta

Leia mais

MANUAL. ecosistemas.net.br

MANUAL. ecosistemas.net.br MANUAL A Eco.Suite possui uma interface simples e de fácil utilização Com a Eco.Suite você trabalha de forma colaborativa, simples e objetiva, em uma única tela. Acesso ao Eco.Suite Tela Principal Após

Leia mais

Tutorial de Manipulação de dados com SQLite

Tutorial de Manipulação de dados com SQLite Universidade Federal do Piauí UFPI Centro de Ciências da Natureza CCN Curso: Ciência da Computação Disciplina: Engenharia de Software II Projeto: B Equipe: New Easii Team Tutorial de Manipulação de dados

Leia mais

MANUAL DE UTILIZAÇÃO DO SOFTWARE DE IMPRESSÃO DE ETIQUETAS MOORE.

MANUAL DE UTILIZAÇÃO DO SOFTWARE DE IMPRESSÃO DE ETIQUETAS MOORE. MANUAL DE UTILIZAÇÃO DO SOFTWARE DE IMPRESSÃO DE ETIQUETAS MOORE. Uma marca de sucesso da 1 CONTEÚDO 3 3 3 4 4 5 5 6 6 6 6 7 7 7 7 8 9 9 10 10 10 11 11 11 11 12 12 13 SOFTWARE DE IMPRESSÃO DE ETIQUETAS

Leia mais

Manual de Utilização do software Colacril Office para criação e impressão de etiquetas. Manual de Utilização

Manual de Utilização do software Colacril Office para criação e impressão de etiquetas. Manual de Utilização Manual de Utilização do software Colacril Office para criação e impressão de etiquetas. Manual de Utilização Conteúdo Colacril Office... 3 Instalação do Colacril... 3 Inicialização do Colacril Office...

Leia mais

INTRODUÇÃO À PROGRAMAÇÃO PARA DISPOSITIVOS MÓVEIS. ADS 6º Período

INTRODUÇÃO À PROGRAMAÇÃO PARA DISPOSITIVOS MÓVEIS. ADS 6º Período INTRODUÇÃO À PROGRAMAÇÃO PARA DISPOSITIVOS MÓVEIS ADS 6º Período Activity INTRODUÇÃO À PROGRAMAÇÃO PARA DISPOSITIVOS MÓVEIS INTRODUÇÃO À PROGRAMAÇÃO PARA DISPOSITIVOS MÓVEIS Activity A classe activity

Leia mais

Guia para testes AfixInv (Demonstração)

Guia para testes AfixInv (Demonstração) Guia para testes AfixInv (Demonstração) INTRODUÇÃO Esse guia foi criado para auxiliar a demonstração da solução para inventários do Ativo Imobilizado utilizando o aplicativo AfixInv. AfixInv aplicativo

Leia mais

Utilitário de configuração do computador Guia do usuário

Utilitário de configuração do computador Guia do usuário Utilitário de configuração do computador Guia do usuário Copyright 2008 Hewlett-Packard Development Company, L.P. Bluetooth é uma marca comercial de seu proprietário e utilizada sob licença pela Hewlett-Packard

Leia mais

5.0 GUIA PRÁTICO. Flash Câmera frontal 2 Carregar a bateria. Diminuir/ Aumentar volume Tecla Liga/ Desliga. Início. Visão geral. Voltar.

5.0 GUIA PRÁTICO. Flash Câmera frontal 2 Carregar a bateria. Diminuir/ Aumentar volume Tecla Liga/ Desliga. Início. Visão geral. Voltar. GUIA PRÁTICO 1 Colocar ou retirar a tampa traseira. Flash Câmera frontal 2 Carregar a bateria. 5.0 Diminuir/ Aumentar volume Tecla Liga/ Desliga SIM2 Voltar Início Visão geral 3 Inserir ou retirar o SIM.

Leia mais

MANUAL DE NAVEGAÇÃO UNICURITIBA VIRTUAL PROFESSOR

MANUAL DE NAVEGAÇÃO UNICURITIBA VIRTUAL PROFESSOR MANUAL DE NAVEGAÇÃO UNICURITIBA VIRTUAL PROFESSOR ACESSANDO O UNICURITIBA VIRTUAL Acesse o site do UNICURITIBA: http://unicuritiba.edu.br Clique no link Portal do Professor, que fica no canto superior

Leia mais

Ashampoo Rescue Disc

Ashampoo Rescue Disc 1 Ashampoo Rescue Disc O Software permite-lhe criar um CD, DVD ou Pen USB de restauro que pode utilizar para: 1. Restaurar uma cópia de segurança para o seu disco rígido principal. Isto não pode ser efetuado

Leia mais

Guia para testes Afixinv Demonstração

Guia para testes Afixinv Demonstração Guia para testes Afixinv Demonstração Introdução Esse guia foi criado para auxiliar a demonstração da solução para inventários do Ativo Imobilizado utilizando o aplicativo AfixInv. AfixInv aplicativo para

Leia mais

NIVELAMENTO DE INFORMÁTICA. Professor: Cleber Semensate

NIVELAMENTO DE INFORMÁTICA. Professor: Cleber Semensate NIVELAMENTO DE INFORMÁTICA Professor: Cleber Semensate 1 Cronograma: Revisão da Aula Anterior Animação entre slides Transição entre slides SmartArt Exercício de Fixação 2 Revisão MICROSOFT POWER POINT

Leia mais

Mapa Aula Introdução: 2. Objetivos: 3. Vocabulário interessante:

Mapa Aula Introdução: 2. Objetivos: 3. Vocabulário interessante: Mapa Aula 1 1. Introdução: Seja bem-vindo ao mais interativo tutorial feito até o dia de hoje (30.09.17), dentro do drive IEEE SSIT UnB Projetos SIGNAL Mit App Inventor Projeto 4. A principal deste tutorial

Leia mais

Profª. Maria José da Silva Página 1

Profª. Maria José da Silva Página 1 E-Mail: mariajosefatern@yahoo.com.br Profª. Maria José da Silva Página 1 Sumário Introdução 03 A Janela PowerPoint 04 Excluindo Slides 06 Criando Apresentação 06 Salvando o Documento 07 Configurando a

Leia mais

STD SERVIÇO DE BACKUP EM NUVEM

STD SERVIÇO DE BACKUP EM NUVEM Select Soluções Manual de Instalação Windows SBackup STD SERVIÇO DE BACKUP EM NUVEM Sumário 1. REQUERIMENTOS DE HARDWARE E SOFTWARE... 3 1.1. SOFTWARE... 3 2. PRIMEIROS PASSOS... 4 3. DOWNLOAD E INSTALAÇÃO

Leia mais

Nota de Aplicação: Utilização de Base de Dados MySQL com BluePlant. Sumário

Nota de Aplicação: Utilização de Base de Dados MySQL com BluePlant. Sumário Nota de Aplicação NAP155 Utilização de Base de Dados MySQL com BluePlant Sumário 1. Descrição... Erro! Indicador não definido. 2. Introdução... Erro! Indicador não definido. 3. Definição da Arquitetura

Leia mais

Carregar Documentos Fiscais - Fornecedor (Modelo 57) - Conhecimento de Transporte Eletrônico. Última Atualização 11/01/2019

Carregar Documentos Fiscais - Fornecedor (Modelo 57) - Conhecimento de Transporte Eletrônico. Última Atualização 11/01/2019 Carregar Documentos Fiscais - Fornecedor (Modelo 57) - Conhecimento de Transporte Eletrônico Última Atualização 11/01/2019 Menu I. Objetivos II. Como Acessar III. Envio de Documento Fiscal Eletrônico CTE

Leia mais

Trabalhando com Mensagens. File > New > New Project. Uso de mensagens (Toast) Luiz Eduardo Guarino de Vasconcelos

Trabalhando com Mensagens. File > New > New Project. Uso de mensagens (Toast) Luiz Eduardo Guarino de Vasconcelos Trabalhando com Mensagens File > New > New Project Alterando o Título da ActionBar Alterar strings.xml exemplo1 exemplo1 - Guarino

Leia mais

Capture Pro Software. Introdução. A-61640_pt-br

Capture Pro Software. Introdução. A-61640_pt-br Capture Pro Software Introdução A-61640_pt-br Introdução ao Alaris Capture Pro Software e Capture Pro Limited Edition Instalando o software: Capture Pro Software e Network Edition... 1 Instalando o software:

Leia mais

Personalizando o seu PC

Personalizando o seu PC Novo no Windows 7? Mesmo que ele tenha muito em comum com a versão do Windows que você usava antes, você ainda pode precisar de uma ajuda para fazer tudo direitinho. Este guia contém muitas informações

Leia mais

5.0. Guia Prático 5 4G. Luz de notificação 2 Inserir ou retirar a. Tecla Liga/ Desliga Aumentar/ Diminuir volume. tampa traseira. bateria.

5.0. Guia Prático 5 4G. Luz de notificação 2 Inserir ou retirar a. Tecla Liga/ Desliga Aumentar/ Diminuir volume. tampa traseira. bateria. 1 1 Inserir ou retirar a tampa traseira 5 4G Guia Prático Luz de notificação 2 Inserir ou retirar a bateria 2 5.0 Tecla Liga/ Desliga Aumentar/ Diminuir volume 3 Carregar a bateria * 4 4 4 Inserir ou retirar

Leia mais

AULA 3. Minicurso PET-EE UFRN

AULA 3. Minicurso PET-EE UFRN AULA 3 Minicurso PET-EE UFRN Nesta aula iremos continuar o exemplo anterior criando uma nova activity e adicionando ao botão um método que irá iniciar a mesma. Começaremos criando o método de envio do

Leia mais

Bem-vindo ao tópico sobre procedimentos de autorização no SAP Business One.

Bem-vindo ao tópico sobre procedimentos de autorização no SAP Business One. Bem-vindo ao tópico sobre procedimentos de autorização no SAP Business One. 1 Após a conclusão deste tópico, você estará apto a descrever o fluxo do processo empresarial quando é utilizado um procedimento

Leia mais

Desenvolvedor Android: Avançado. Plano de Estudo

Desenvolvedor Android: Avançado. Plano de Estudo Desenvolvedor Android: Avançado Plano de Estudo Descrição do programa A Certificação Android fornece as ferramentas necessárias para projetar e implementar aplicativos para dispositivos Android, com base

Leia mais

Desenvolvimento de um aplicativo básico usando o Google Android

Desenvolvimento de um aplicativo básico usando o Google Android Desenvolvimento de um aplicativo básico usando o Google Android (Intent e Intent Filter) Programação de Dispositivos Móveis Mauro Lopes Carvalho Silva Professor EBTT DAI Departamento de Informática Campus

Leia mais

Navegar entre páginas Necessário o uso de Intent. Intenção de ir a algum lugar, acessar outros recursos, outros apps.

Navegar entre páginas Necessário o uso de Intent. Intenção de ir a algum lugar, acessar outros recursos, outros apps. Navegar entre páginas Necessário o uso de Intent. Intenção de ir a algum lugar, acessar outros recursos, outros apps. Alterar o oncreate dentro de LoginActivity.java, para chamar uma próxima Activity.

Leia mais

Programação para Dispositivos Móveis. Activities

Programação para Dispositivos Móveis. Activities Programação para Dispositivos Móveis Activities Activity Uma activity é uma tarefa, muito focada, do que um usuário pode fazer. Quase todas as atividades interagem com o usu ário, então uma classe de atividade

Leia mais