Home > android, ui > Processing Widget events with PendingIntents

Processing Widget events with PendingIntents

Widgets are not just for displaying data. As simple as they are supposed to be, basic interaction with the user is still commonplace – initiated by the user’s click on the widget or one of its elements.

The normal way of responding to clicks is by using setOnClickListener, like this:

protected void onCreate(Bundle savedInstanceState) {
.....
    final Button buttonStartScan = (Button) findViewById(R.id.button_start_scan);
    buttonStartScan.setOnClickListener(new OnClickListener() {
        public void onClick(View v) {
            ....
    }
});

However, in a Widget (a subclass of AppWidgetProvider), event handling can’t be done the same way.

First of all, a widget’s views exist in a separate process from its AppWidgetProvider subclass, therefore it’s not possible to obtain widget’s view objects by calling findViewById, not to mention connecting that object with an event handler in our process.

Secondly, a widget’s AppWidgetProvider is stateless – its instances are not guaranteed to be kept around for as long as the widget appears on screen. These objects can be destroyed to save memory and re-created later as necessary.

This is where PendingIntent can be useful. According to the documentation:

… instances of this class are created in a certain way, and can be handed to other applications so that they can perform the action you described on your behalf at a later time. A PendingIntent itself is simply a reference to a token maintained by the system. If its owning application’s process is killed, the PendingIntent itself will remain usable from other processes that have been given it.

So PendingIntent solves two problems described above: cross-process notifications, and AppWidgetProvider‘s transient nature.

Now some examples:

  • Launching an activity in response to a click
  • public RemoteViews buildUpdate(Context context) {
        RemoteViews updateViews = new RemoteViews(context.getPackageName(), R.layout.widget_id);
    
        // create an intent that describes activity launch
        Intent appIntent = new Intent(context, MyWidgetActivity.class);
    
        // convert to PendingActivity which can be pushed to the actual view inside the widget
        PendingIntent pendingAppIntent = PendingIntent.getActivity(
                                       context, 0, appIntent, PendingIntent.FLAG_UPDATE_CURRENT);
        updateViews.setOnClickPendingIntent(R.id.desired_view_id, pendingAppIntent);
    
        return updateViews;
    }
    

    An instance of PendingIntent is created with the FLAG_UPDATE_CURRENT. This is so Android maintains just one instance of this intent.

  • Getting arbitrary view click notifications
  • This is just a little more involved. We’ll be broadcasting an intent from the widget, and receiving notifications in its provider.
    First, we need to come up with a string name for the broadcast intent. Let’s choose one: “org.myname.widget.MYCLICK_ACTION”.

    Second, mark our AppWidgetProvider as a receiver of this intent:

    <receiver android:name=".MyWidget" android:label="@string/widget_name">
        <intent-filter>
            <action android:name="org.myname.widget.MYCLICK_ACTION" />
    ................
    

    Third, create a PendingIntent and register it with a view.

    public RemoteViews buildUpdate(Context context) {
        RemoteViews updateViews = new RemoteViews(context.getPackageName(), R.layout.widget_id);
    
        Intent actionIntent = new Intent("org.myname.widget.MYCLICK_ACTION");
        PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 0,
            actionIntent, PendingIntent.FLAG_UPDATE_CURRENT);
        updateViews.setOnClickPendingIntent(R.id.a_certain_view, pendingIntent);
    

    Finally, add code to respond to the broadcast:

    public void onReceive(Context context, Intent intent) {
        String action = intent.getAction();
        if (action.equals("org.myname.widget.MYCLICK_ACTION")) {
            // do something
        }
    }
    

    That’s about it. As can be seen, by using a PendingIntent it’s possible to create widgets that allow simple user interaction.

    Advertisements
    Categories: android, ui
    1. September 9, 2014 at 2:28 pm

      thanks for this tuto.. cheers

    1. No trackbacks yet.

    Leave a Reply

    Fill in your details below or click an icon to log in:

    WordPress.com Logo

    You are commenting using your WordPress.com account. Log Out / Change )

    Twitter picture

    You are commenting using your Twitter account. Log Out / Change )

    Facebook photo

    You are commenting using your Facebook account. Log Out / Change )

    Google+ photo

    You are commenting using your Google+ account. Log Out / Change )

    Connecting to %s