Создайте расширенный виджет

Попробуйте способ создания композиций.
Jetpack Compose — рекомендуемый набор инструментов для создания пользовательского интерфейса для Android. Узнайте, как создавать виджеты, используя API в стиле Compose.

На этой странице изложены рекомендуемые методы создания более продвинутого виджета для улучшения пользовательского опыта.

Оптимизация обновления содержимого виджета.

Обновление содержимого виджета может быть ресурсоемким процессом. Для экономии заряда батареи оптимизируйте тип, частоту и время обновления.

Типы обновлений виджетов

Существует три способа обновления виджета: полное обновление, частичное обновление и, в случае виджета-коллекции, обновление данных. Каждый из них имеет разные вычислительные затраты и последствия.

Ниже приведено описание каждого типа обновления и фрагменты кода для каждого из них.

  • Полное обновление: вызовите AppWidgetManager.updateAppWidget(int, android.widget.RemoteViews) , чтобы полностью обновить виджет. Это заменит ранее предоставленные RemoteViews на новые RemoteViews . Это наиболее ресурсоемкое обновление.

    Котлин

    val appWidgetManager = AppWidgetManager.getInstance(context)
    val remoteViews = RemoteViews(context.getPackageName(), R.layout.widgetlayout).also {
    setTextViewText(R.id.textview_widget_layout1, "Updated text1")
    setTextViewText(R.id.textview_widget_layout2, "Updated text2")
    }
    appWidgetManager.updateAppWidget(appWidgetId, remoteViews)

    Java

    AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(context);
    RemoteViews remoteViews = new RemoteViews(context.getPackageName(), R.layout.widgetlayout);
    remoteViews.setTextViewText(R.id.textview_widget_layout1, "Updated text1");
    remoteViews.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.getPackageName(), R.layout.widgetlayout).also {
    setTextViewText(R.id.textview_widget_layout, "Updated text")
    }
    appWidgetManager.partiallyUpdateAppWidget(appWidgetId, remoteViews)

    Java

    AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(context);
    RemoteViews remoteViews = new RemoteViews(context.getPackageName(), R.layout.widgetlayout);
    remoteViews.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)

    Java

    AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(context);
    appWidgetManager.notifyAppWidgetViewDataChanged(appWidgetId, R.id.widget_listview);

Эти методы можно вызывать из любого места в вашем приложении, при условии, что приложение имеет тот же UID, что и соответствующий класс AppWidgetProvider .

Определите, как часто следует обновлять виджет.

Виджеты обновляются периодически в зависимости от значения атрибута updatePeriodMillis . Обновление виджета может происходить в ответ на действия пользователя, трансляцию обновлений или и то, и другое.

Периодически обновлять

Вы можете управлять частотой периодического обновления, указав значение для AppWidgetProviderInfo.updatePeriodMillis в XML-файле appwidget-provider . Каждое обновление запускает метод AppWidgetProvider.onUpdate() , в котором вы можете разместить код для обновления виджета. Однако, если вашему виджету необходимо асинхронно загружать данные или обновление занимает более 10 секунд, рассмотрите альтернативные варианты обновления BroadcastReceiver, описанные в следующем разделе, поскольку по истечении 10 секунд система считает BroadcastReceiver не отвечающим на запросы.

updatePeriodMillis не поддерживает значения меньше 30 минут. Однако, если вы хотите отключить периодические обновления, вы можете указать 0.

В настройках можно указать частоту обновлений для пользователей. Например, они могут захотеть, чтобы биржевой тикер обновлялся каждые 15 минут или только четыре раза в день. В этом случае установите параметр updatePeriodMillis равным 0 и используйте WorkManager .

Обновление в ответ на взаимодействие с пользователем.

Вот несколько рекомендуемых способов обновления виджета в зависимости от взаимодействия с пользователем:

  • В активности приложения: напрямую вызовите метод AppWidgetManager.updateAppWidget в ответ на взаимодействие пользователя, например, на касание экрана.

  • При удаленном взаимодействии, например, с уведомлением или виджетом приложения: создайте объект PendingIntent , а затем обновите виджет из вызванной Activity , Broadcast или Service . Вы можете выбрать собственный приоритет. Например, если вы выберете Broadcast для PendingIntent , вы можете выбрать широковещательную рассылку в фоновом режиме , чтобы присвоить приоритет BroadcastReceiver .

Обновление в связи с трансляцией события.

Примером широковещательного события, требующего обновления виджета, является момент, когда пользователь делает фотографию. В этом случае необходимо обновлять виджет при обнаружении новой фотографии.

Вы можете запланировать задание с помощью JobScheduler и указать широковещательную рассылку в качестве триггера, используя метод JobInfo.Builder.addTriggerContentUri .

Вы также можете зарегистрировать BroadcastReceiver для широковещательной рассылки — например, для прослушивания события ACTION_LOCALE_CHANGED . Однако, поскольку это потребляет ресурсы устройства, используйте это с осторожностью и прослушивайте только конкретную широковещательную рассылку. С введением ограничений на широковещательную рассылку в Android 7.0 (уровень API 24) и Android 8.0 (уровень API 26) приложения не могут регистрировать неявные широковещательные рассылки в своих манифестах, за некоторыми исключениями .

Рекомендации при обновлении виджета из 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 когда пользователь нажимает на определенную часть виджета.