Olá. Estou criando um widget para o Amor por SMS, então irei aproveitar e fazer este tutorial.
O que é um app widget? É uma funcionalidade de um aplicativo que pode ser adicionada na tela principal (home) e é atualizada periodicamente, exibindo informação e/ou recebendo interação com o usuário.
Iniciamente vamos declarar nosso AppWidgetProvider no AndroidManifest.xml entre a tag <application>:
<receiver android:name="MeuAppWidgetProvider" > <intent-filter> <action android:name="android.appwidget.action.APPWIDGET_UPDATE" /> </intent-filter> <meta-data android:name="android.appwidget.provider" android:resource="@xml/appwidget_info" /> </receiver>
O <receiver> especifica o nome do AppWidgetProvider, que iremos definir em breve. O <intent-filter> declara a ação que o widget irá receber por broadcast, no caso APPWIDGET_UPDATE, que é a atualização periodica do widget. O <meta-data> especifica o AppWidgetProviderInfo
que devemos fornecer e que atribui propriedades básicas do widget tais com largura e altura mínima, periodicidade do update, entre outros. Vamos então criar o arquivo appwidget_info.xml na pasta res/xml/ (se essa pasta não existir, crie-a):<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android" android:minWidth="294dp" android:minHeight="72dp" android:updatePeriodMillis="86400000" android:previewImage="@drawable/preview" android:initialLayout="@layout/meu_appwidget" android:configure="com.example.android.MeuAppWidgetConfigure" android:resizeMode="horizontal|vertical"> </appwidget-provider>
Ok, vamos por partes:
- android:minWidth e android:minHeight especificam o tamanho minimo necessário para o widget;
- android:updatePeriodMillis é a periodicidade da atualização em milisegundos (86400000 = 24h);
- android:previewImage é uma pre-visualização de como o widget ficará depois de configurado (acho que só é utilizado para versões 3.0+), use esse aplicativo para tirar a foto do widget depois de pronto;
- android:initialLayout é o layout do seu widget;
- android:configure é uma activity de configuração do widget que você pode, ou não, criar e será lançada toda vez que colocarem um widget na tela;
- android:resizeMode especifica em quais direções o widget pode ser redimensionado: horizontal, vertical ou none.
Vamos então criar o layout do widget, que é basicamente a criação de um layout para activitys com algumas restrições: apenas FrameLayout, LinearLayout e RelativeLayout são suportados como layouts e apenas AnalogClock, Button, Chronometer, ImageButton, ImageView, ProgressBar, TextView, ViewFlipper, ListView, GridView, StackView e AdapterViewFlipper são suportados (seus descendentes não são) como widget (não confundir esses widget - que são funcionalidades da view - com app widget que estamos contruindo aqui para ser exibido na home).
É uma boa pratica deixar um espaço na borda do widget, assim ele não fica colado com as bordas da tela nem com outros widgets. O Android 4.0 já faz isso automaticamente, mas as versões anteriores não, então vamos implementar meu_appwidget.xml em /res/layout/ dessa forma:
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:padding="@dimen/widget_margin"> <LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="horizontal" android:background="@drawable/my_widget_background"> <TextView android:layout_width="match_parent" android:layout_height="match_parent" android:text="Testando."/> </LinearLayout> </FrameLayout>
O que importa aqui é o android:padding="@dimen/widget_margin" o qual iremos definir um para versões anteriores ao 4.0 e outra para a 4.0. O LinearLayout pode ser trocado por outro da sua preferencia, dentro das especificações, e o TextView está a titulo de teste. Vamos então criar os recursos de dimensão (se o arquivo já existe apenas adicione o campo):
res/values/dimens.xml:
<dimen name="widget_margin">4dp</dimen>
res/values-v14/dimens.xml:
<dimen name="widget_margin">0dp</dimen>
Pronto! Agora vamos finalmente implementar nossa AppWidgetProvider, que é onde ficará todo o código do nosso widget, assim como registro de Listeners. AppWidgetProvider é uma extensão do BroadcastReceiver, que - caso você não saiba - recebe as mensagens de Broadcast que são Intents enviadas para todos os aplicativos no sistema, então se você não quiser usar o AppWidgetProvider, apenas estenda um BroadcastReceiver e implemente o onReceive para Intents com ações começadas por 'ACTION_APPWIDGET_'.
O AppWidgetProvider pode implementar os seguintes métodos:
- onUpdate: Executado periodicamente no tempo definido em updatePeriodMillis pelo AppWidgetProviderInfo, e caso você não tenha definido uma activity de configuração ele também será chamado ao adicionar um novo widget na tela;
- onDeleted: Executado quando um widget é deletado da home;
- onEnabled: Executado quando um widget é adicionado pela primeira vez na tela. Útil para criação de banco de dados especifico do widget, ou chamada de um Service;
- onDisabled: Executado quando a ultima instância do widget é deletado da home. Útil para desfazer coisas provisórias feitas em onEnabled;
- onReceive: Chamada que todo broadcast faz e que no nosso caso será chamada sempre antes das citadas acima.
Vamos então definir MeuAppWidgetProvider:
public class MeuAppWidgetProvider extends AppWidgetProvider {
public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
final int N = appWidgetIds.length;
for (int i=0; i<N; i++) {
int appWidgetId = appWidgetIds[i];
RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.meu_appwidget);
appWidgetManager.updateAppWidget(appWidgetId, views);
}
}
}
Como estamos apenas testando, só implementarei o onUpdate. É preciso lembrar que você pode ter mais de um instância de um widget na home, entretanto só ocorerrá a chama de onUpdate apenas uma vez, e para todas as instâncias. Cabe a você atualizar todas usando o parâmetro appWidgetIds que identifica cada uma. Por isso precisamos daquele for, assim o código seguinte é executado para todas as instâncias do widget. Registros de event handler (click de botão, etc...) é feito após a criação de views e usando ela para encontrar as views filhas.
Agora vamos tentar executar o aplicativo e colocar o widget. Se você fez tudo certo deve receber a seguinte mensagem ao tentar adicionar: "O aplicativo não foi instalado no seu telefone". Isso acontece pois no appwidget_info.xml definimos uma activity de configuração mas não a implementamos ainda. Então, a título de teste, retire a linha do android:configure e tente novamente. No meu caso obtive isso:
Seu resultado pode variar a depender do background definido. |
Tudo certo então. Vamos implementar agora a MeuAppWidgetConfigure. Desfaça a mudança feita no ultimo passo (de excluir a linha android:configure do appwidget_info.xml). Ela também precisa ser declarada no AndroidManifest.xml assim como qualquer outra activity, adicione isso dentro da tag <application>:
<activity android:name=".MeuAppWidgetConfigure"> <intent-filter> <action android:name="android.appwidget.action.APPWIDGET_CONFIGURE"/> </intent-filter> </activity>
Vamos criar o layout da activity (meu_configure_appwidget.xml), que inicialmente vamos apenas colocar um botão de confirmar, mas você pode colocar o que quiser para configurar o widget de acordo com suas necessidades:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:oritentation="vertical"> <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:id="@+id/btn_confirm"> android:text="Confirmar"/> </LinearLayout>
E finalmente criar o MeuAppWidgetConfigure em si:
import android.app.Activity;
import android.appwidget.AppWidgetManager;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.RemoteViews;
public class MensagemAppWidgetConfigure extends Activity {
private Button mConfirmar;
private int mAppWidgetId;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.mensagem_configure_appwidget);
setResult(RESULT_CANCELED);
Bundle extras = getIntent().getExtras();
if (extras != null) {
mAppWidgetId = extras.getInt(
AppWidgetManager.EXTRA_APPWIDGET_ID,
AppWidgetManager.INVALID_APPWIDGET_ID);
}
AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(this);
RemoteViews views = new RemoteViews(getPackageName(),
R.layout.mensagem_appwidget);
//Registro de eventos do widget registrados aqui!
appWidgetManager.updateAppWidget(mAppWidgetId, views);
mConfirmar = (Button) findViewById(R.id.btn_confirm);
mConfirmar.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent resultValue = new Intent();
resultValue.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, mAppWidgetId);
setResult(RESULT_OK, resultValue);
finish();
}
});
}
}
Algumas considerações:
- setResult(RESULT_CANCELED) precisa ser setado no inicio, pois caso o usuário não confirme a configuração o widget não deve ser criado;
- Pegamos o id do widget pela intent que foi usada para chamar a activity (extras.getInt(AppWidgetManager.EXTRA_APPWIDGET_ID, AppWidgetManager.INVALID_APPWIDGET_ID));
- Fazemos basicamente o mesmo trabalho feito no onUpdate para configurar o widget;
- Criamos a ação do botão de confirmar para terminar a configuração;
- É obrigatório o resultado ser RESULT_OK com uma Intent contendo o id do widget!
Pronto! Agora você tem seu app widget funcionando, com uma activity de configuração.
6 comentários:
Diga Gustavo,
Segui todos os passos do seu tutorial mas continua aparecendo a mensagem "O aplicativo não está instalado!".
@Anônimo: Onde aparece essa mensagem? Isso pode ser problema quanto ao app ser instalado no SD Card ou problema de assinatura quando você transformou o projeto em apk, talvez usando uma keystore diferente.
Não compila, mostram 3 erros, não reconhece my_widget_background, na classe MeuAppWidgetProvider não é reconhecido R.layout.meu_appwidget, e acho que estou criando o template de xml errado para appwidget_info.xml, pois mostra erro no começo do arquivo.
Vc criou um projeto a parte ou esta usando o projeto do seu app para fazer o widget? qual é a melhor pratica nesse caso?
Quero fazer um app tipo do beautiful widgets, onde vc toca no widget e ele abre informações detalhadas em outra tela.
Seria criar um app e o widget juntos no mesmo projeto? Obrigado
qual programa vc usa para fazer.
No ultimo arquivo, você deve substituir "mensagem_configure_appwidget" por "widget_configure" e "mensagem_appwidget" por "meu_appwidget".
Ótimo tutorial, parabéns...
Ah sim... verifiquem se o caminho do android:configure está correto...
Postar um comentário