Tutorial Android #23 – Widgets (I)

Padrão

Olá pessoal! No post de hoje vamos ver a primeira parte sobre como criarmos widgets no Android.

Pra quem não sabe, widgets é uma espécie de miniatura do aplicativo que você pode deixar em uma das áreas de trabalho do Android, colocando à disposição do usuário informações de maneira mais rápida e prática. O widget também pode redirecionar o usuário para o aplicativo principal, funcionando como uma espécie de “atalho”.

Bom, vamos então começar a colocar a mão na massa!

Primeiramente, precisamos definir o layout do nosso widget. Para isso, crie o arquivo widget.xml dentro da pasta res/layout. Ele será bastante simples, inicialmente apenas exibindo o nome de um restaurante cadastrado. Sendo assim, ele terá apenas um TextView em sua estrutura:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:background="@drawable/frame">
    <TextView android:id="@+id/nome"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerVertical="true"
        android:layout_alignParentLeft="true"
        android:textSize="10pt"
        android:textColor="#FFFFFF"/>
</RelativeLayout>

De diferente do que já fizemos das outras vezes, somente as propriedades que modificam o tamanho e a cor do texto. No mais, tudo dentro dos conformes. O arquivo frame.9.png pode ser baixado junto com o projeto no fim do post. Por que este 9? Porque a imagem é uma NinePatch, ideal para compor fundos de frames. Entenda melhor como funciona aqui.

O próximo passo é criarmos uma classe para gerenciar o conteúdo do widget. Inicialmente, apenas crie uma classe chamada WidgetAplicativo dentro do pacote net.rafaeltoledo.restaurante, estendendo AppWidgetProvider.

package net.rafaeltoledo.restaurante;

import android.appwidget.AppWidgetProvider;

public class WidgetAplicativo extends AppWidgetProvider {
}

Continuando, vamos agora definir algumas propriedades do widget em um arquivo XML. Crie dentro da pasta res/xml o arquivo provedor_widget.xml.

<?xml version="1.0" encoding="utf-8"?>
<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
	android:minWidth="300dip"
	android:minHeight="79dip"
	android:updatePeriodMillis="1800000"
	android:initialLayout="@layout/widget"
/>

Basicamente definimos a largura e altura mínimas, o tempo de atualização das informações do widget (no caso, dos restaurantes – a cada 30 minutos) e qual o layout a ser utilizado por ele (no caso, o que definimos no XML anterior).

Em seguida, precisamos atualizar o AndroidManifest.xml para que o nosso aplicativo suporte o widget. Adicione o seguinte nó receiver ao final do nó application.

<receiver android:name=".WidgetAplicativo"
	android:label="@string/app_name"
	android:icon="@drawable/ic_launcher">
	<intent-filter>
		<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
	</intent-filter>
	<meta-data android:name="android.appwidget.provider"
		android:resource="@xml/provedor_widget" />
</receiver>

Neste trecho, definimos que a classe que representa o widget é a WidgetApp, que o nome e o ícone a serem exibidos nas opções são os mesmos da aplicação no menu (app_name e ic_launcher). Além disso, definimos que o widget realizará operações de atualização e que suas propriedades estão definidas no arquivo provedor_widget dentro da pasta xml.

Por fim, vamos implementar o método onUpdate() para a classe WidgetApp. É este método que fará a busca em nosso banco de dados para exibir o nome de um restaurante.

@Override
public void onUpdate(Context context, AppWidgetManager appWidgetManager,
		int[] appWidgetIds) {
	ComponentName cn = new ComponentName(context, WidgetApp.class);
	RemoteViews atualizarFrame = new RemoteViews("net.rafaeltoledo.restaurante", R.layout.widget);
	GerenciadorRestaurantes gerenciador = new GerenciadorRestaurantes(context);

	try {
		Cursor c = gerenciador.getReadableDatabase().rawQuery("SELECT COUNT(*) FROM restaurantes", null);
		c.moveToFirst();
		int count = c.getInt(0);
		c.close();

		if (count > 0) {
			int offset = (int) (count * Math.random());
			String args[] = {String.valueOf(offset)};
			c = gerenciador.getReadableDatabase().rawQuery("SELECT nome FROM restaurantes LIMIT 1 OFFSET ?", args);
			c.moveToFirst();
			atualizarFrame.setTextViewText(R.id.nome, c.getString(0));
		} else {
			atualizarFrame.setTextViewText(R.id.nome, context.getString(R.string.vazio));
		}
	} finally {
		gerenciador.close();
	}

	appWidgetManager.updateAppWidget(cn, atualizarFrame);
}

Resumidamente, esse trecho de código:

  • Cria um objeto RemoteView, que nos permite modificar o widget;
  • Estabelece uma conexão com o banco de dados;
  • Verifica quantos restaurantes salvos existem;
  • Carrega um restaurante aleatório (por isso o uso de Math.random());
  • Exibe o nome do restaurante, ou uma mensagem dizendo que não existem restaurantes cadastrados;
  • Atualiza o widget propriamente dito.

A mensagem “vazio” (R.string.vazio) deve ser definida nos seus arquivos string.xml nas pastas values que você tem. No meu caso, vou defini-la em português e em espanhol (idiomas que minha aplicação suporta).

<string name="vazio">Nenhum registro.</string>
<string name="vazio">Ningún registro.</string>

E pronto! Para ativar o widget, clique e segure sobre a área de trabalho para aparecer o menu e a opção de inserir widget.

Pra baixar o projeto, só clicar aqui.

Bom, é isso pessoal! No próximo post vamos melhorar esse widget! Até lá!

3 comentários sobre “Tutorial Android #23 – Widgets (I)

  1. André Kunde

    Parabéns Rafael!
    Muito legal este tutorial…. eu já tinha visto um sobre widgets, mas não tão claro assim…

    Queria saber também se você pode me ajudar…. Estou acompanhando a sequencia dos tutoriais, mas queria mudar a minha aplicação, deixando de utilizar as abas…. gostaria de trabalhar com botões que chamam outras activities…. você sabe como posso fazer??

    • Basicamente, você realiza a a chamadas a novas Activities através de Intents. Nos tutoriais anteriores você encontra vários exemplos desse tipo de chamadas. Em alguns dias vou montar uma página pra centralizar todos os tutoriais e facilitar a busca entre os conteúdos. 🙂

  2. André Kunde

    uhm….
    é…. eu acompanhei só até antes da integração com o twitter….
    é que eu tentei ‘separar’ a tela lista da tela de cadastro/alteração
    com uma activity para cada tela….
    aí não consegui acertar a passagem de parâmetros…. :/

    mas então vou aguardar a organizada na página…. valeu!

Deixe uma resposta