Android widget, click event, multiple instancesAndroid widget, click event, multiple instances

July 9, 2010

Ok… I started to do some Android devel… And I started to like it, even if it is based on Java, works in Eclipse and has a ton of classes.

Now, the first project is a widget (weather widget). For this, there’s this “AppWidgetProvider” class that implements the design and functions for data retrieval (using threads), and also a configuration Activity. When the configuration activity finishes (a “Save” button is pressed), a static function of the AppWidgetProvider class is called. This static function updates the settings of the widget and also does something of interest: it sets the event handler for “onClick” – so that when I click (touch) the widget, to be able to modify the layout somehow (to rotate a needle).

This is a part of the static function that updates the widget:

...
RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.widget_layout);
Intent clickIntent = new Intent(context, DigiStation.class);
clickIntent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId);
PendingIntent pendingIntent = PendingIntent.getBroadcast(context, appWidgetId, clickIntent, 0);
views.setOnClickPendingIntent(R.id.widget_normal_relativelayout, pendingIntent);
appWidgetManager.updateAppWidget(appWidgetId, views);
...

The AppWidgetProvider class is called “DigiStation” – we’re using it for creating an intent that targets it.

Ok. For handling the events, the DigiStation class (which is of type AppWidgetProvider) implements the function “onReceive”. The function is called with two parameters: the context and the intent.

Now, the issue was to be able to distinguish between multiple instances of the same AppWidgetProvider class. To be able to do that, I had to put some extra information in the intent (clickIntent.putExtra). The field contains the appWidgetId – the widget ID – of the instance.

The onReceive function looks like this:

@Override
public void onReceive(Context context, Intent intent) {
    if (intent.getAction()==null) {
        Bundle extras = intent.getExtras();
        if(extras!=null) {
            int widgetId = extras.getInt(AppWidgetManager.EXTRA_APPWIDGET_ID, AppWidgetManager.INVALID_APPWIDGET_ID);
            // do something for the widget that has appWidgetId = widgetId
        }
    }
    else {
        super.onReceive(context, intent);
    }
 }

All looks simple enough, but there are some little details that I must underline, because I spend a few days with them:

1. To be able to distinguish between multiple instances of the same AppWidgetProvider, when registering the “onClick” event (intent) you must add an extra value with the widget ID (appWidgetId)

2. Update only the views of the current instance! – appWidgetManager.updateAppWidget(appWidgetId, views);

3. Android reuses intents, so when you create an intent, make sure you put an unique ID, or else the same intent used before will be triggered for all instances! Only with this detail I spent half a day! ( PendingIntent pendingIntent = PendingIntent.getBroadcast(context, appWidgetId, clickIntent, 0); )

4. When handling the click event, get the appWidgetId from the “extras” payload of the intent.

Hope this helps people not spending so much time for little undocumented details! ๐Ÿ™‚

Enjoy!

Be Sociable, Share!

37 Responses to “Android widget, click event, multiple instances”

  1. Dude, you rock! Saved me hours of work, I was stuck on this a while.

  2. I spent more than half a day finding out how to reference pending intents to multiple widgets (step 3). Nice site. Thanks alot.

  3. You saved my life! Adding an ID to the Intent solved the problem! Thank you very much! ๐Ÿ˜€

  4. Thank you!!! I was stuck on this as well, and I did not know about step 3! You saved me a ton of work!

  5. Glad I could be helpful ๐Ÿ™‚

  6. I spent many hours(and billions of brain cells), but failed to find out how to let multiple widget responds to their own click events.
    Thank you very much for such a great work!

  7. Yeah ! I spend at least one day on that stupid
    PendingIntent actionPendingIntent = PendingIntent.getBroadcast(context,
    appWidgetId, active, 0);

    i thought of adding the appWidgetId here but the Documentation says
    “requestCode – Private request code for the sender (currently not used). ”
    It does not say it is essential when working with different instances!!

    thanx alot

  8. Never write comments, but have to thank you – Step 3 has saved me!

  9. WOHOOO!!!
    You saved me!

    Android development is full of small tricks you need to do in order to make your app do as you like.

    Thanks a lot!

  10. Hi frinds, thanks to u for sharing your knowledge :

    I am creating an chat widget in which info update using background(Service)thread, here when i delete instance of widget then I have to stop all these thread.

    So here suggest me how can I stop my all thread on delete of last instance of widget.

  11. Contrary to some notions, well explored articles still fetch in reviewers like me. You confirmed clear understanding of the topic issue and my ideas are actually total after reading publish. Be sure to maintain up the sound work and iโ€™ll sign up for your rss nourish to be knowledgeable of any emerging postings.

  12. Great piece youโ€™ve produced right! The internet is stuffed with horrid penning and I used to be grabbed by your limpidity. Your decisions are exact and I will straightaway subscribe to your rss or atom nourish to stay day utilizing your up emerging postings. Indeed! I admit it, your composition fashion is unbelievable and that i is fine much more concentrated on mine.

  13. THANK YOU – your insight into PendingIntent unique ids has made my widget finally work – You are a life saver.

  14. This post is one of a kind. Sharing this is a great help for the readers in order for them to widen their knowledge about the subject. More power to the author.

  15. Where do i get full source code?

    Thanks.

  16. I didn’t make a downloadable version, not yet anyway ๐Ÿ™‚

  17. Excellent post, thanks for the information.

  18. Great! Thanks! I was able to put this into my code directly and it works without any problems!!!!

    Again thank you!

  19. Really helpful. Thanks a lot. Especially opion 3.
    Not mentioned in ofical javadoc (insead of real meaning smth like ‘Private request code for the sender (currently not used).’ is provided)

  20. nice work ! I found this on end of the day .. but no problem solved my prob ! thx

  21. Thanks a lot for the Post.
    Didn’t get the right Extras on my activity called by the widgets till i read your Post.

  22. Hi

    Can u please help to make clear what is the problem in my code:

    Let explain the scenario

    There is two buttons (next and previous) in my appwidget onReceive()

    Intent intentNext = new Intent(context, EcommerceWidget.class);
    intentNext.putExtra(“page”, nextpage);
    PendingIntent pNext = PendingIntent.getBroadcast(context,appWidgetId, intentNext, PendingIntent.FLAG_UPDATE_CURRENT);
    remoteViews.setOnClickPendingIntent(R.id.next, pNext);

    Intent intentPrev = new Intent(context,EcommerceWidget.class);
    intentNext.putExtra(“page”, nextpage); PendingIntent pPrevious = PendingIntent.getBroadcast(context, appWidgetId, intentPrev,PendingIntent.FLAG_UPDATE_CURRENT);
    remoteViews.setOnClickPendingIntent(R.id.previous, pPrevious);

    When i click on next button im getting previous button value

    can u please help me

  23. Thank you so much. You saved my life with #3!

  24. I never write comments but step 3 saved my life so I thought I might thak you for that! ๐Ÿ˜‰

  25. Way to go! Thanks for share.

  26. i love u!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

  27. Fantastic!!! Much appreciated. The documentation seems some what lacking when it comes to strategies on managing multiple widgets instances. Great little article. You saved the day.

  28. The STEP 3….. Thank you!

  29. Thanks I also spent nearly a day on issue 3 before coming across this.

  30. Thanks for clearing this up. Especially point 3 saves my day ๐Ÿ˜‰

  31. Tack sรฅ mycket! (3 days wasted already :-))

  32. Thanks a lot!! This poast is really helpful ๐Ÿ™‚

  33. Thanks for this!
    One question, say I wanted to change a textview on the widget with corresponding ID
    What code do I use? Remoteviews?

    So an example of what to put under
    // do something for the widget that has appWidgetId = widgetId

  34. Not necessarily

    I am using AppWidgetManager there, and I am obtaining a handler for the instance of the widget with
    int[] widgetIDs = appWidgetManager.getAppWidgetIds(...);

  35. You made my day dude. Thanks ๐Ÿ™‚ Your code spark in my mind for my way.

  36. Hi,
    I tried to achieve something similar.
    Basically I just want to make a widget that displays 0, then after the first tap 1, after the first tap 2 then back to 0.
    I have some problems.
    Basically it only works the first time and only after tapping 3 times, then it stops working all toghether.
    I made a question on stackoverflow
    http://stackoverflow.com/questions/29402921/taping-an-android-home-screen-widget-doesnt-work-the-second-time
    I would really appreciate it if you could take a look. You seem to have more experience than me(I only started learning to code for android yesterday :)).
    Thanks a lot.

  37. Step 3 rocks, easy to miss, much time to waste…

Leave a Reply




*