How To Properly Update A Widget In Android 8.0 - Oreo - API 26 How To Properly Update A Widget In Android 8.0 - Oreo - API 26 multithreading multithreading

How To Properly Update A Widget In Android 8.0 - Oreo - API 26


You don't indicate what the update trigger mechanism is. You seem concerned about latency ("Your widget may or may not get updated for a while"), so I am going to assume that your concern is tied to user interaction with the app widget, such as tapping a button.

Use JobScheduler to schedule a job as quickly as possible. Your widget may or may not get updated for a while.

This is a variation on "use JobIntentService", which AFAIK is the recommended solution for this sort of scenario.

Other options include:

  • Use getForegroundService() with PendingIntent. With this, you effectively "pinky swear" that your service will call startForeground() within the ANR timeframe. If the work takes longer than a few seconds, call startForeground() to ensure that Android doesn't get cranky. This should minimize the number of time the foreground notification appears. And, if the user tapped a button and you are still busy doing work a few seconds later, you probably want to show a notification or otherwise do something to let the user know that what they asked for is still in progress.

  • Use goAsync() on BroadcastReceiver, to do work in the context of the receiver while not tying up the main application thread. I haven't tried this with Android 8.0+, so YMMV.


You can use WorkManager to update a widget. Uses WorkManager on devices with API 14+. You need to override fun onReceive(context: Context?, intent: Intent?) like this:

val ACTION_AUTO_UPDATE : String = "AUTO_UPDATE";override fun onReceive(context: Context?, intent: Intent?) {    super.onReceive(context, intent)    if(intent?.action.equals(ACTION_AUTO_UPDATE))    {        val appWidgetManager = AppWidgetManager.getInstance(context)        val thisAppWidgetComponentName = ComponentName(context!!.getPackageName(), javaClass.name)        val appWidgetIds = appWidgetManager.getAppWidgetIds(thisAppWidgetComponentName)        for (appWidgetId in appWidgetIds) {            // update widget        }    }}

And you should create PeriodicWorkRequest. You have to use for repeating work. Periodic work has a minimum interval of 15 minutes. We enqueue the periodicWork when widget is enabled:

override fun onEnabled(context: Context) {    val periodicWorkRequest = PeriodicWorkRequest.Builder(YourWorker::class.java, 15, TimeUnit.MINUTES).build()    WorkManager.getInstance(context).enqueueUniquePeriodicWork("YourWorker", ExistingPeriodicWorkPolicy.REPLACE,periodicWorkRequest)}

And cancel it when widget is disabled:

override fun onDisabled(context: Context) {    WorkManager.getInstance(context).cancelAllWork()}

Finally we create worker class:

class YourWorker(ctx: Context, params: WorkerParameters) : Worker(ctx, params) {var context : Context? = nullinit {    context = ctx}override fun doWork(): Result {    val alarmIntent = Intent(context, YourWidget::class.java)    alarmIntent.action = YourWidget().ACTION_AUTO_UPDATE    context?.sendBroadcast(alarmIntent)    return Result.success()}

If you want to use WorkerManager you add to build.gradle implementation 'androidx.work:work-runtime:2.3.1'

You can find the sample here.