Try the Compose way Jetpack Compose is the recommended UI toolkit for Android. Learn how to build widgets using Compose-style APIs. [Jetpack Glance →](https://developer.android.com/develop/ui/compose/glance.md.txt) ![](https://developer.android.com/static/images/android-compose-ui-logo.png)

<br />

This page explains recommended practices for creating a more advanced widget for
a better user experience.

## Optimizations for updating widget content

Updating widget content can be computationally expensive. To save battery
consumption, optimize the update type, frequency, and timing.

### Types of widget updates

There are three ways to update a widget: a full update, a partial update, and,
in the case of a collection widget, a data refresh. Each has different
computational costs and ramifications.

The following describes each update type and provides code snippets for each.

- **Full update:** call [`AppWidgetManager.updateAppWidget(int,
  android.widget.RemoteViews)`](https://developer.android.com/reference/android/appwidget/AppWidgetManager#updateAppWidget(int,%20android.widget.RemoteViews)) to fully update the widget. This replaces the previously provided [`RemoteViews`](https://developer.android.com/reference/android/widget/RemoteViews) with a new `RemoteViews`. This is the most computationally expensive update.


```kotlin
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)
```

<br />

- **Partial update:** call
  [`AppWidgetManager.partiallyUpdateAppWidget`](https://developer.android.com/reference/android/appwidget/AppWidgetManager.md.txt#partiallyUpdateAppWidget(int,%20android.widget.RemoteViews))
  to update parts of the widget. This merges the new `RemoteViews` with the
  previously provided `RemoteViews`. This method is ignored if a widget
  doesn't receive at least one full update through [`updateAppWidget(int[],
  RemoteViews)`](https://developer.android.com/reference/android/appwidget/AppWidgetManager#updateAppWidget(android.content.ComponentName,%20android.widget.RemoteViews)).

  > [!WARNING]
  > **Warning:** Reserve `partiallyUpdateAppWidget` for lightweight text or visibility updates. Don't use `partiallyUpdateAppWidget` to replace `Bitmap` or `Icon` images (`setImageViewBitmap`, `setImageViewIcon`, or `setImageViewUri`). Because `system_server` merges partial `RemoteViews` actions into the previously cached `RemoteViews` instance, prior image allocations remain retained in memory until the next full `updateAppWidget` call and can cause your widget to exceed the system bitmap memory limit on Android 17 (API level 37) and higher.


```kotlin
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)
```

<br />

- **Collection data refresh:** call [`AppWidgetManager.notifyAppWidgetViewDataChanged`](https://developer.android.com/reference/android/appwidget/AppWidgetManager.md.txt#notifyAppWidgetViewDataChanged(int,%20int)) to invalidate the data of a collection view in your widget. This triggers [`RemoteViewsFactory.onDataSetChanged`](https://developer.android.com/reference/android/widget/RemoteViewsService.RemoteViewsFactory.md.txt#onDataSetChanged()). In the interim, the old data is displayed in the widget. You can safely perform expensive tasks synchronously with this method.


```kotlin
val appWidgetManager = AppWidgetManager.getInstance(context)
appWidgetManager.notifyAppWidgetViewDataChanged(appWidgetId, R.id.widget_listview)
```

<br />

You can call these methods from anywhere in your app, as long as the app has the
same UID as the corresponding
[`AppWidgetProvider`](https://developer.android.com/reference/android/appwidget/AppWidgetProvider.md.txt) class.

### Determine how often to update a widget

Widgets are updated periodically depending on the value provided for the
[`updatePeriodMillis`](https://developer.android.com/reference/android/appwidget/AppWidgetProviderInfo.md.txt#updatePeriodMillis)
attribute. The widget can update in response to user interaction, broadcast
updates, or both.

#### Update periodically

You can control the frequency of the periodic update by specifying a value for
`AppWidgetProviderInfo.updatePeriodMillis` in the `appwidget-provider` XML. Each
update triggers the `AppWidgetProvider.onUpdate()` method, which is where you
can place the code to update the widget. However, consider the [alternatives for
broadcast receiver updates](https://developer.android.com/develop/ui/views/appwidgets/advanced#broadcastreceiver-duration) described in a
following section if your widget needs to load data asynchronously or takes more
than 10 seconds to update, because after 10 seconds, the system considers a
`BroadcastReceiver` to be non-responsive.

`updatePeriodMillis` doesn't support values of less than 30 minutes. However, if
you want to disable periodic updates, you can specify 0.

You can let users adjust the frequency of updates in a configuration. For
example, they might want a stock ticker to update every 15 minutes or only four
times a day. In this case, set the `updatePeriodMillis` to 0 and use
[`WorkManager`](https://developer.android.com/topic/libraries/architecture/workmanager) instead.

> [!NOTE]
> **Note:** Using repeating tasks with `WorkManager` is a good option, but similar power restrictions apply. See [App Standby
> Buckets](https://developer.android.com/about/versions/pie/power#buckets) for more information.

#### Update in response to a user interaction

Here are some recommended ways to update the widget based on user interaction:

- **From an activity of the app:** directly call
  `AppWidgetManager.updateAppWidget` in response to a user interaction, such
  as a user's tap.

- **From remote interactions, such as a notification or an app widget:**
  construct a `PendingIntent`, then update the widget from the invoked
  `Activity`, `Broadcast`, or `Service`. You can choose your own priority. For
  example, if you select a `Broadcast` for the `PendingIntent`, you can choose
  a [foreground broadcast](https://developer.android.com/develop/ui/views/appwidgets/advanced.md.txt#broadcastreceiver-priority) to give the
  `BroadcastReceiver` priority.

#### Update in response to a broadcast event

An example of a broadcast event that requires a widget to update is when the
user takes a photo. In this case, you want to update the widget when a new photo
is detected.

You can schedule work with [`WorkManager`](https://developer.android.com/topic/libraries/architecture/workmanager) and specify a content URI
trigger using the
[`Constraints.Builder.addContentUriTrigger`](https://developer.android.com/reference/androidx/work/Constraints.Builder.md.txt#addContentUriTrigger(android.net.Uri,%20boolean))
method.

You can also register a `BroadcastReceiver` for the broadcast---for example,
listening for [`ACTION_LOCALE_CHANGED`](https://developer.android.com/reference/android/content/Intent.md.txt#ACTION_LOCALE_CHANGED).
However, because this consumes device resources, use this with care and listen
only to the specific broadcast. With the introduction of [broadcast
limitations](https://developer.android.com/about/versions/oreo/background#broadcasts) in Android
7.0 (API level 24) and Android 8.0 (API level 26), apps can't register implicit
broadcasts in their manifests, with certain
[exceptions](https://developer.android.com/guide/components/broadcast-exceptions).

### Considerations when updating a widget from a BroadcastReceiver

If the widget is updated from a `BroadcastReceiver`, including
`AppWidgetProvider`, be aware of the following considerations regarding the
duration and priority of a widget update.

#### Duration of the update

As a rule, the system lets broadcast receivers, which usually run in the app's
main thread, run for up to 10 seconds before considering them non-responsive and
triggering an [Application Not
Responding](https://developer.android.com/topic/performance/issues/anr) (ANR) error. To avoid blocking the
main thread while handling the broadcast, use the
[`goAsync`](https://developer.android.com/reference/android/content/BroadcastReceiver.md.txt#goAsync()) method. If it takes longer to update the widget, consider
scheduling a task using [`WorkManager`](https://developer.android.com/reference/androidx/work/WorkManager.md.txt).

    Caution: Any work you do here blocks further broadcasts until it completes,
    so it can slow the receiving of later events.

See [Security considerations and best practices](https://developer.android.com/guide/components/broadcasts#security-and-best-practices) for more information.

#### Priority of the update

By default, broadcasts---including those made using
`AppWidgetProvider.onUpdate`---run as background processes. This means
overloaded system resources can cause a delay in the invocation of the broadcast
receiver. To prioritize the broadcast, make it a foreground process.

For example, add the [`Intent.FLAG_RECEIVER_FOREGROUND`](https://developer.android.com/reference/android/content/Intent.md.txt#FLAG_RECEIVER_FOREGROUND)
flag to the `Intent` passed to the `PendingIntent.getBroadcast` when the user
taps on a certain part of the widget.