En esta página, se explican las prácticas recomendadas para crear un widget más avanzado que brinde una mejor experiencia del usuario.
Optimizaciones para actualizar el contenido de los widgets
Actualizar el contenido de un widget puede ser costoso en términos de procesamiento. Para ahorrar batería, optimiza el tipo, la frecuencia y el momento de la actualización.
Tipos de actualizaciones de widgets
Existen tres formas de actualizar un widget: una actualización completa, una parcial y, en el caso de un widget de colección, una actualización de datos. Cada uno tiene diferentes costos y ramificaciones de procesamiento.
A continuación, se describe cada tipo de actualización y se proporcionan fragmentos de código para cada uno.
- Actualización completa: Llama a
AppWidgetManager.updateAppWidget(int, android.widget.RemoteViews)para actualizar por completo el widget. Esto reemplaza elRemoteViewsproporcionado anteriormente por unRemoteViewsnuevo. Esta es la actualización más costosa a nivel informático.
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)
Actualización parcial: Llama a
AppWidgetManager.partiallyUpdateAppWidgetpara actualizar partes del widget. Esto combina elRemoteViewsnuevo con elRemoteViewsproporcionado anteriormente. Este método se ignora si un widget no recibe al menos una actualización completa a través deupdateAppWidget(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)
- Actualización de datos de la colección: Llama a
AppWidgetManager.notifyAppWidgetViewDataChangedpara invalidar los datos de una vista de colección en tu widget. Esto activaRemoteViewsFactory.onDataSetChanged. Mientras tanto, se muestran los datos antiguos en el widget. Puedes realizar tareas costosas de forma síncrona con este método de manera segura.
val appWidgetManager = AppWidgetManager.getInstance(context) appWidgetManager.notifyAppWidgetViewDataChanged(appWidgetId, R.id.widget_listview)
Puedes llamar a estos métodos desde cualquier lugar de tu app, siempre y cuando tenga el mismo UID que la clase AppWidgetProvider correspondiente.
Determina la frecuencia con la que se debe actualizar un widget
Los widgets se actualizan de forma periódica según el valor proporcionado para el atributo updatePeriodMillis. El widget se puede actualizar en respuesta a la interacción del usuario, las actualizaciones de transmisión o ambas.
Actualiza periódicamente
Puedes controlar la frecuencia de la actualización periódica especificando un valor para
AppWidgetProviderInfo.updatePeriodMillis en el XML de appwidget-provider. Cada actualización activa el método AppWidgetProvider.onUpdate(), que es donde puedes colocar el código para actualizar el widget. Sin embargo, considera las alternativas para las actualizaciones del receptor de transmisiones que se describen en una sección siguiente si tu widget necesita cargar datos de forma asíncrona o tarda más de 10 segundos en actualizarse, ya que, después de ese tiempo, el sistema considera que un BroadcastReceiver no responde.
updatePeriodMillis no admite valores inferiores a 30 minutos. Sin embargo, si
quieres inhabilitar las actualizaciones periódicas, puedes especificar 0.
Puedes permitir que los usuarios ajusten la frecuencia de las actualizaciones en un parámetro de configuración. Por
ejemplo, es posible que deseen que un indicador de cotización se actualice cada 15 minutos o solo cuatro
veces al día. En este caso, establece updatePeriodMillis en 0 y usa
WorkManager en su lugar.
Actualiza en respuesta a una interacción del usuario
Estas son algunas formas recomendadas de actualizar el widget en función de la interacción del usuario:
Desde una actividad de la app: Llama directamente a
AppWidgetManager.updateAppWidgeten respuesta a una interacción del usuario, como una presión.Desde interacciones remotas, como una notificación o un widget de app: construye un
PendingIntenty, luego, actualiza el widget desde elActivity,BroadcastoServiceinvocados. Puedes elegir tu propia prioridad. Por ejemplo, si seleccionas unBroadcastpara elPendingIntent, puedes elegir una transmisión en primer plano para darle prioridad alBroadcastReceiver.
Actualiza en respuesta a un evento de transmisión
Un ejemplo de un evento de transmisión que requiere que se actualice un widget es cuando el usuario toma una foto. En este caso, quieres actualizar el widget cuando se detecte una foto nueva.
Puedes programar el trabajo con WorkManager y especificar un activador de URI de contenido con el método Constraints.Builder.addContentUriTrigger.
También puedes registrar un BroadcastReceiver para la transmisión, por ejemplo, escuchando ACTION_LOCALE_CHANGED.
Sin embargo, como esto consume recursos del dispositivo, úsalo con cuidado y escucha solo la transmisión específica. Con la introducción de las limitaciones de transmisión en Android 7.0 (nivel de API 24) y Android 8.0 (nivel de API 26), las apps no pueden registrar transmisiones implícitas en sus manifiestos, con ciertas excepciones.
Consideraciones para actualizar un widget desde un BroadcastReceiver
Si el widget se actualiza desde un BroadcastReceiver, incluido AppWidgetProvider, ten en cuenta las siguientes consideraciones sobre la duración y la prioridad de una actualización de widget.
Duración de la actualización
Como regla, el sistema permite que los receptores de transmisiones, que suelen ejecutarse en el subproceso principal de la app, se ejecuten durante un máximo de 10 segundos antes de considerarlos como no responsivos y activar un error de Aplicación no responde (ANR). Para evitar bloquear el subproceso principal mientras se controla la transmisión, usa el método goAsync. Si se tarda más en actualizar el widget, considera programar una tarea con WorkManager.
Caution: Any work you do here blocks further broadcasts until it completes,
so it can slow the receiving of later events.
Consulta Consideraciones de seguridad y prácticas recomendadas para obtener más información.
Prioridad de la actualización
De forma predeterminada, las transmisiones, incluidas las que se realizan con AppWidgetProvider.onUpdate, se ejecutan como procesos en segundo plano. Esto significa que los recursos del sistema sobrecargados pueden causar un retraso en la invocación del receptor de transmisiones. Para priorizar la transmisión, conviértela en un proceso en primer plano.
Por ejemplo, agrega la marca Intent.FLAG_RECEIVER_FOREGROUND al Intent que se pasa al PendingIntent.getBroadcast cuando el usuario presiona una parte determinada del widget.