24

I have a WidgetProvider and an Configure Activity

When the Widget is started it starts with the configure activity and I set it up by making a custom call to the widgetprovider

(which you will notice is from the sdk tutorial examples)

 // Push widget update to surface with newly set prefix
              AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(context);
              AwarenessWidget.updateAppWidget(context, appWidgetManager,
                      mAppWidgetId, position);

            // Make sure we pass back the original appWidgetId
            Intent resultValue = new Intent();
            resultValue.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, mAppWidgetId);
            setResult(RESULT_OK, resultValue);
            finish();

I pass the Widget ID to the function.... inside the widget I create a Intent like this:

  Intent configIntent = new Intent(context, Configure.class);
    configIntent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId);

    PendingIntent pendingIntent = PendingIntent.getActivity
    (context, 0, configIntent,
    PendingIntent.FLAG_UPDATE_CURRENT);

    views.setOnClickPendingIntent(R.id.MainImage,pendingIntent);

    views.setImageViewResource(R.id.MainImage, lv_images[version]);

    appWidgetManager.updateAppWidget(appWidgetId, views);

I am always referencing the widget ID and even add it as a extra on the intent but when I get two of these widgets on the home screen the widget ID is always referencing the last placed widget ID

GregM
  • 3,624
  • 3
  • 35
  • 51

3 Answers3

54

I had a similar problem. Just add this to your config activity, where you set your PendingIntent:

Uri data = Uri.withAppendedPath(
    Uri.parse(URI_SCHEME + "://widget/id/")
    ,String.valueOf(appWidgetId));
intent.setData(data);

The variable URI_SCHEME is a String, and can be whatever you'd like.. ie - "ABCD" This causes each widget to have a unique PendingIntent.

Snailer
  • 3,777
  • 3
  • 35
  • 46
  • I don't set a pendingintent in my config activity, only in the widget function that the activity calls – GregM Oct 25 '10 at 02:25
  • 2
    This works but I don't understand why. Can someone please explain this answer a bit further? – Mike Jun 25 '12 at 08:47
  • 1
    @Mike After a bit of research I discovered an explanation of why this answer works. Please see my alternate answer below. – Code Commander Nov 21 '12 at 06:35
  • In my case I had a problem with Collection widget. So when I've added my second widget on the home screen, the RemoteViewFactory didn't call. So I pasted this for the intent, which launches the RemoteViewService. `intent.data = Uri.parse(intent.toUri(Intent.URI_INTENT_SCHEME))` Working great. – Hayk Mkrtchyan Mar 31 '21 at 08:10
40

Here is a more in-depth explanation of why your code doesn't work and how to fix it. From the Android SDK Documentation:

A PendingIntent itself is simply a reference to a token maintained by the system describing the original data used to retrieve it. This means that, even if its owning application's process is killed, the PendingIntent itself will remain usable from other processes that have been given it. If the creating application later re-retrieves the same kind of PendingIntent (same operation, same Intent action, data, categories, and components, and same flags), it will receive a PendingIntent representing the same token if that is still valid, and can thus call cancel() to remove it.

Because of this behavior, it is important to know when two Intents are considered to be the same for purposes of retrieving a PendingIntent. A common mistake people make is to create multiple PendingIntent objects with Intents that only vary in their "extra" contents, expecting to get a different PendingIntent each time. This does not happen. The parts of the Intent that are used for matching are the same ones defined by Intent.filterEquals. If you use two Intent objects that are equivalent as per Intent.filterEquals, then you will get the same PendingIntent for both of them.

Note that specifying differing "extra" contents isn't enough for the PendingIntents to be considered unique, but setting a unique URI with setData is. That is why Snailer's URI solution "magically" fixes the problem.

The documentation also offers a different (arguably simpler) solution to the problem. Instead of creating a custom URI just set a unique requestCode when you call getActivity:

PendingIntent pendingIntent = PendingIntent.getActivity(context, appWidgetId, configIntent, PendingIntent.FLAG_UPDATE_CURRENT);

Source: http://developer.android.com/reference/android/app/PendingIntent.html

Code Commander
  • 16,771
  • 8
  • 64
  • 65
  • 2
    requestCode is not currently used by the SDK but it does cause the Intent to be considered unique. The documentation suggests this is a valid use of requestCode: "or different request code integers supplied to getActivity" – Code Commander Jan 25 '13 at 21:09
13

In my testing, using the setData(...) on the PendingIntent doesn't fix the issue on a Verizon Thunderbolt running Android 4.0.4. It works on my other test devices and emulator.

I tested the use of the requestCode instead, and it works in all cases. I just set the requestCode to be the widget ID:

pendingIntent = PendingIntent.getService(context, appWidgetId, intent, PendingIntent.FLAG_UPDATE_CURRENT);
Sean Aitken
  • 1,177
  • 1
  • 11
  • 23