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)  
![](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

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

  ```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);
  ```
- **Partial update:** call[`AppWidgetManager.partiallyUpdateAppWidget`](https://developer.android.com/reference/android/appwidget/AppWidgetManager#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)).

  ### Kotlin

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

  ```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);
  ```
- **Collection data refresh:** call[`AppWidgetManager.notifyAppWidgetViewDataChanged`](https://developer.android.com/reference/android/appwidget/AppWidgetManager#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#onDataSetChanged()). In the interim, the old data is displayed in the widget. You can safely perform expensive tasks synchronously with this method.

  ### Kotlin

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

  ### Java

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

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)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#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:** 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#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 a job with`JobScheduler`and specify a broadcast as the trigger using the[`JobInfo.Builder.addTriggerContentUri`](https://developer.android.com/reference/android/app/job/JobInfo.Builder#addTriggerContentUri(android.app.job.JobInfo.TriggerContentUri))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#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/vitals/anr)(ANR) error. To avoid blocking the main thread while handling the broadcast, use the[`goAsync`](https://developer.android.com/reference/android/content/BroadcastReceiver#goAsync())method. If it takes longer to update the widget, consider scheduling a task using[`WorkManager`](https://developer.android.com/reference/androidx/work/WorkManager).  

    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#FLAG_RECEIVER_FOREGROUND)flag to the`Intent`passed to the`PendingIntent.getBroadcast`when the user taps on a certain part of the widget.