Nesta página, explicamos as práticas recomendadas para criar um widget mais avançado para uma melhor experiência do usuário.
Otimizações para atualizar o conteúdo do widget
A atualização do conteúdo do widget pode ser computacionalmente cara. Para economizar bateria, otimize o tipo, a frequência e o momento da atualização.
Tipos de atualizações de widgets
Há três maneiras de atualizar um widget: uma atualização completa, uma parcial e, no caso de um widget de coleção, uma atualização de dados. Cada uma tem custos e ramificações computacionais diferentes.
Veja a seguir uma descrição de cada tipo de atualização e snippets de código para cada um.
- Atualização completa:chame
AppWidgetManager.updateAppWidget(int, android.widget.RemoteViews)para atualizar totalmente o widget. Isso substitui oRemoteViewsfornecido anteriormente por um novoRemoteViews. Essa é a atualização mais cara em termos de computação.
val appWidgetManager = AppWidgetManager.getInstance(context) val remoteViews = RemoteViews(context.packageName, R.layout.widgetlayout).apply { setTextViewText(R.id.textview_widget_layout1, "Updated text1") setTextViewText(R.id.textview_widget_layout2, "Updated text2") } appWidgetManager.updateAppWidget(appWidgetId, remoteViews)
- Atualização parcial:chame
AppWidgetManager.partiallyUpdateAppWidgetpara atualizar partes do widget. Isso mescla o novoRemoteViewscom oRemoteViewsfornecido anteriormente. Esse método será ignorado se um widget não receber pelo menos uma atualização completa porupdateAppWidget(int[], RemoteViews).
val appWidgetManager = AppWidgetManager.getInstance(context) val remoteViews = RemoteViews(context.packageName, R.layout.widgetlayout).apply { setTextViewText(R.id.textview_widget_layout, "Updated text") } appWidgetManager.partiallyUpdateAppWidget(appWidgetId, remoteViews)
- Atualização de dados da coleção:chame
AppWidgetManager.notifyAppWidgetViewDataChangedpara invalidar os dados de uma visualização de coleção no widget. Isso acionaRemoteViewsFactory.onDataSetChanged. Enquanto isso, os dados antigos são exibidos no widget. É possível realizar tarefas caras de forma síncrona com esse método.
val appWidgetManager = AppWidgetManager.getInstance(context) appWidgetManager.notifyAppWidgetViewDataChanged(appWidgetId, R.id.widget_listview)
É possível chamar esses métodos de qualquer lugar no app, desde que ele tenha o
mesmo UID da classe
AppWidgetProvider correspondente.
Determinar a frequência de atualização de um widget
Os widgets são atualizados periodicamente, dependendo do valor fornecido para o atributo
updatePeriodMillis. O widget pode ser atualizado em resposta à interação do usuário, a atualizações de transmissão
ou a ambos.
Atualizar periodicamente
É possível controlar a frequência da atualização periódica especificando um valor para
AppWidgetProviderInfo.updatePeriodMillis no XML appwidget-provider. Cada
atualização aciona o método AppWidgetProvider.onUpdate(), que é onde você
pode colocar o código para atualizar o widget. No entanto, considere as alternativas para
atualizações do broadcast receiver descritas em uma
seção a seguir se o widget precisar carregar dados de forma assíncrona ou levar mais
de 10 segundos para ser atualizado, porque, após 10 segundos, o sistema considera que um
BroadcastReceiver não está respondendo.
updatePeriodMillis não aceita valores inferiores a 30 minutos. No entanto, se
você quiser desativar as atualizações periódicas, especifique 0.
Você pode permitir que os usuários ajustem a frequência das atualizações em uma configuração. Por
exemplo, eles podem querer que um ticker de ações seja atualizado a cada 15 minutos ou apenas quatro
vezes por dia. Nesse caso, defina updatePeriodMillis como 0 e use
WorkManager.
Atualizar em resposta a uma interação do usuário
Confira algumas maneiras recomendadas de atualizar o widget com base na interação do usuário:
Em uma atividade do app:chame diretamente
AppWidgetManager.updateAppWidgetem resposta a uma interação do usuário, como um toque.Em interações remotas, como uma notificação ou um widget de app:crie um
PendingIntente atualize o widget doActivity,BroadcastouServiceinvocado. Você pode escolher sua própria prioridade. Por exemplo, se você selecionar umBroadcastpara oPendingIntent, poderá escolher uma transmissão em primeiro plano para dar prioridade aoBroadcastReceiver.
Atualizar em resposta a um evento de transmissão
Um exemplo de evento de transmissão que exige a atualização de um widget é quando o usuário tira uma foto. Nesse caso, você quer atualizar o widget quando uma nova foto for detectada.
É possível programar o trabalho com WorkManager e especificar um acionador de URI de conteúdo
usando o método
Constraints.Builder.addContentUriTrigger.
Também é possível registrar um BroadcastReceiver para a transmissão, por exemplo,
detectando ACTION_LOCALE_CHANGED.
No entanto, como isso consome recursos do dispositivo, use com cuidado e ouça
apenas a transmissão específica. Com a introdução das limitações de transmissão no Android 7.0 (nível 24 da API) e no Android 8.0 (nível 26 da API), os apps não podem registrar transmissões implícitas nos manifestos, com algumas exceções.
Considerações ao atualizar um widget de um BroadcastReceiver
Se o widget for atualizado de um BroadcastReceiver, incluindo
AppWidgetProvider, considere as seguintes informações sobre a
duração e a prioridade de uma atualização de widget.
Duração da atualização
Como regra, o sistema permite que os broadcast receivers, que geralmente são executados na linha de execução principal do app, sejam executados por até 10 segundos antes de serem considerados sem resposta e acionarem um erro O app não está respondendo (ANR). Para evitar o bloqueio da
linha de execução principal ao processar a transmissão, use o
método goAsync. Se a atualização do widget demorar mais, programe uma tarefa usando WorkManager.
Caution: Any work you do here blocks further broadcasts until it completes,
so it can slow the receiving of later events.
Consulte Considerações de segurança e práticas recomendadas para mais informações.
Prioridade da atualização
Por padrão, as transmissões, incluindo as feitas usando
AppWidgetProvider.onUpdate, são executadas como processos em segundo plano. Isso significa
que recursos do sistema sobrecarregados podem causar um atraso na invocação do broadcast
receiver. Para priorizar a transmissão, torne-a um processo em primeiro plano.
Por exemplo, adicione a flag Intent.FLAG_RECEIVER_FOREGROUND
ao Intent transmitido para o PendingIntent.getBroadcast quando o usuário
tocar em uma determinada parte do widget.