android – Multiple Instances Of Widget Only Updating Last widget-ThrowExceptions

Exception or error:

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

How to solve:

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.

###

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

###

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);

Leave a Reply

Your email address will not be published. Required fields are marked *