На этой странице объясняются рекомендуемые методы создания более продвинутого виджета для лучшего взаимодействия с пользователем.
Оптимизация обновления контента виджета
Обновление содержимого виджета может быть дорогостоящим с точки зрения вычислений. Чтобы экономить заряд батареи, оптимизируйте тип, частоту и время обновления.
Типы обновлений виджетов
Существует три способа обновления виджета: полное обновление, частичное обновление и, в случае виджета коллекции, обновление данных. Каждый из них имеет разные вычислительные затраты и последствия.
Ниже описаны все типы обновлений и приведены фрагменты кода для каждого из них.
- Полное обновление. Вызовите
AppWidgetManager.updateAppWidget(int, android.widget.RemoteViews), чтобы полностью обновить виджет. Это заменяет ранее предоставленныйRemoteViewsновымRemoteViews. Это наиболее ресурсоемкое обновление.
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)
- Частичное обновление. Вызовите
AppWidgetManager.partiallyUpdateAppWidget, чтобы обновить части виджета. НовыйRemoteViewsбудет объединен с ранее указаннымRemoteViews. Этот метод игнорируется, если виджет не получает хотя бы одно полное обновление черезupdateAppWidget(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)
- Обновление данных коллекции. Вызовите
AppWidgetManager.notifyAppWidgetViewDataChanged, чтобы аннулировать данные представления коллекции в виджете. Это активируетRemoteViewsFactory.onDataSetChanged. До этого момента в виджете будут показываться старые данные. Этот метод позволяет безопасно выполнять ресурсоемкие задачи в синхронном режиме.
val appWidgetManager = AppWidgetManager.getInstance(context) appWidgetManager.notifyAppWidgetViewDataChanged(appWidgetId, R.id.widget_listview)
Вы можете вызывать эти методы из любого места в приложении, если у него тот же UID, что и у соответствующего класса AppWidgetProvider.
Как настроить частоту обновления виджета
Виджеты периодически обновляются в зависимости от значения, указанного для атрибута updatePeriodMillis. Виджет может обновляться в ответ на взаимодействие с пользователем, широковещательные обновления или и то, и другое.
Периодическое обновление
Вы можете управлять частотой периодического обновления, указав значение для AppWidgetProviderInfo.updatePeriodMillis в XML-файле appwidget-provider. Каждое обновление запускает метод AppWidgetProvider.onUpdate(), в который можно поместить код для обновления виджета. Однако если виджету требуется асинхронная загрузка данных или обновление занимает более 10 секунд, рассмотрите альтернативы обновлениям широковещательного приемника, описанные в следующем разделе. Это связано с тем, что через 10 секунд система считает BroadcastReceiver не отвечающим.
updatePeriodMillis не поддерживает значения менее 30 минут. Если вы хотите отключить периодические обновления, укажите значение 0.
Вы можете разрешить пользователям настраивать частоту обновлений в конфигурации. Например, биржевой тикер может обновляться каждые 15 минут или всего четыре раза в день. В этом случае задайте для updatePeriodMillis значение 0 и используйте WorkManager.
Обновление в ответ на действия пользователя
Вот несколько рекомендуемых способов обновления виджета на основе взаимодействия с пользователем:
Из действия приложения. Вызовите
AppWidgetManager.updateAppWidgetнапрямую в ответ на действие пользователя, например нажатие.При удаленном взаимодействии, например с уведомлением или виджетом приложения, создайте
PendingIntent, а затем обновите виджет из вызванногоActivity,BroadcastилиService. Вы можете выбрать приоритет самостоятельно. Например, если вы выберетеBroadcastдляPendingIntent, то можете выбрать активную трансляцию, чтобы предоставить приоритетBroadcastReceiver.
Обновление в ответ на широковещательное событие
Примером широковещательного события, требующего обновления виджета, является ситуация, когда пользователь делает фотографию. В этом случае вы хотите обновить виджет, когда будет обнаружена новая фотография.
Вы можете запланировать работу с помощью WorkManager и указать триггер URI контента с помощью метода Constraints.Builder.addContentUriTrigger.
Вы также можете зарегистрировать BroadcastReceiver для трансляции, например для прослушивания ACTION_LOCALE_CHANGED.
Однако, поскольку это потребляет ресурсы устройства, используйте эту возможность с осторожностью и слушайте только определенную трансляцию. В Android 7.0 (уровень API 24) и Android 8.0 (уровень API 26) были введены ограничения на широковещательную рассылку. Теперь приложения не могут регистрировать неявные широковещательные рассылки в своих манифестах, за некоторыми исключениями.
Considerations when updating a widget from a BroadcastReceiver
Если виджет обновляется из BroadcastReceiver, в том числе AppWidgetProvider, учитывайте следующие соображения относительно продолжительности и приоритета обновления виджета.
Продолжительность обновления.
Как правило, система позволяет широковещательным приемникам, которые обычно работают в основном потоке приложения, работать до 10 секунд, прежде чем посчитает их не отвечающими и вызовет ошибку Приложение не отвечает (ANR). Чтобы не блокировать основной поток при обработке трансляции, используйте метод goAsync. Если на обновление виджета требуется больше времени, запланируйте задачу с помощью WorkManager.
Caution: Any work you do here blocks further broadcasts until it completes,
so it can slow the receiving of later events.
Подробную информацию вы найдете в разделе Рекомендации по обеспечению безопасности.
Приоритет обновления.
По умолчанию трансляции, в том числе созданные с помощью AppWidgetProvider.onUpdate, выполняются как фоновые процессы. Это означает, что перегрузка системных ресурсов может привести к задержке вызова широковещательного приемника. Чтобы повысить приоритет трансляции, сделайте ее активным процессом.
Например, добавьте флаг Intent.FLAG_RECEIVER_FOREGROUND в Intent, передаваемый в PendingIntent.getBroadcast, когда пользователь нажимает на определенную часть виджета.