Widget Service Example

This example shows how to update a home screen widget using a service.

A screenshot of the widget.

See the following guides in Android's documentation for information about implementing App Widgets:

from java.lang import Class, Runnable
from java.text import SimpleDateFormat
from java.util import Date
from android.app import Service
from android.appwidget import AppWidgetManager, AppWidgetProvider
from android.content import ComponentName, Intent
from android.os import Handler
from android.widget import RemoteViews

from app_resources import R

The WidgetProvider class is derived from the standard AppWidgetProvider class and represents the application. Android will create an instance of this class when the user runs it.

class WidgetProvider(AppWidgetProvider):

    def __init__(self):
    
        AppWidgetProvider.__init__(self)

The onUpdate method starts a service by sending an intent with the class name of the service class.

    def onUpdate(self, context, manager, ids):
    
        context.startService(Intent(context, Class.forName("com.example.widgetservice.UpdateService")))

The service class runs in the background and can be used to perform tasks that cannot be performed by the widget. It cannot access the widget directly, but instead uses an RemoteViews instance to update the widget.

In this example, we make the service implement the Runnable interface so that we can use a Handler to periodically perform some work: every 30 seconds we update the widget to show the current time.

class UpdateService(Service):

    __interfaces__ = [Runnable]
    
    DELAY = 30000 # ms
    
    def __init__(self):
        Service.__init__(self)

When the service is started, this method is called. We update the widget immediately by calling the updateWidget method. Then we create a handler and post a delayed message to the service itself so that further updates can occur.

    def onStartCommand(self, intent, flags, startId):
    
        self.updateWidget()
        
        self.handler = Handler()
        self.handler.postDelayed(self, long(self.DELAY))
        
        return Service.onStartCommand(self, intent, flags, startId)

When the message arrives, we update the widget and post a new event so that this method will be called again.

    def run(self):
    
        self.updateWidget()
        self.handler.postDelayed(self, long(self.DELAY))

This method first uses a reference to the widget layout to obtain a collection of remote views in the widget. It uses this to change the text of a TextView with an associated ID.

    def updateWidget(self):
    
        views = RemoteViews(self.getPackageName(), R.layout.main)
        dateString = SimpleDateFormat("HH:mm").format(Date())
        views.setTextViewText(R.id.widget_text, dateString)
        
        widget = ComponentName("com.example.widgetservice", "com.example.widgetservice.WidgetProvider")
        manager = AppWidgetManager.getInstance(self)
        manager.updateAppWidget(widget, views)

After updating the TextView, we obtain information about the widget itself and acquire an AppWidgetManager instance that we use to update it.

Files