0

I have a widget that is using a collection. What I need is to pass an id, from the widget, to an activity in my app when one of the rows of the widget ListView is selected.

For some reason, when I debug activity, the wrong id is being sent. I've narrowed it down to something with the position. If I pass the position to my activity when I debug, it is the wrong position It may just be my misunderstanding of how a widget with a collection works, since it's my first one.

Widget Service

public class WidgetService extends RemoteViewsService {
    @Override
    public RemoteViewsFactory onGetViewFactory(Intent intent) {
        return new StackRemoteViewsFactory(this.getApplicationContext(), intent);
    }
}

class StackRemoteViewsFactory implements RemoteViewsService.RemoteViewsFactory  {

        private List<Integer> mIds = new ArrayList<Integer>();
        private Context mContext;
        private int mAppWidgetId;

        public StackRemoteViewsFactory(Context context, Intent intent) {
            mContext = context;
            mAppWidgetId = intent.getIntExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, AppWidgetManager.INVALID_APPWIDGET_ID);
        }

        public void onCreate() {
        }

        public int getCount() {
            // TODO Auto-generated method stub
            return mIds.size();
        }

        public long getItemId(int position) {
            // TODO Auto-generated method stub
            return position;
        }

        public RemoteViews getLoadingView() {
            // TODO Auto-generated method stub
            return null;
        }

        public RemoteViews getViewAt(int position) {
            RemoteViews rv = new RemoteViews(mContext.getPackageName(), R.layout.widget_item);
            final Intent mi = new Intent(mContext, MyActivity.class);
            final Bundle bun = new Bundle();
            bun.putInt("id", mIds.get(position));
            mi.putExtras(bun);

            final PendingIntent piMain = PendingIntent.getActivity(mContext, mAppWidgetId, mi, PendingIntent.FLAG_UPDATE_CURRENT);

            rv.setOnClickPendingIntent(R.id.widget_text, piMain);
            rv.setTextViewText(R.id.widget_text, mIds.get(position));

            return rv;
        }

        public int getViewTypeCount() {
            // TODO Auto-generated method stub
            return 1;
        }

        public boolean hasStableIds() {
            // TODO Auto-generated method stub
            return true;
        }

        public void onDataSetChanged() {
            mIds = Utilities.GetIds();
        }

        public void onDestroy() {
            // TODO Auto-generated method stub

        }
}

My Activity

public class Activity extends SherlockFragmentActivity {

    @Override
    public void onCreate(final Bundle icicle)
    {    
        super.onCreate(icicle);

        setContentView(R.layout.browser_pager);

        if (getIntent().getExtras() != null)
        {
            final Bundle extras = getIntent().getExtras();

            int id = extras.getInt("id"); //this id is wrong
        }
    }
}
Kris B
  • 3,436
  • 9
  • 64
  • 106
  • At `getActivity()` do not use `mAppWidgetId` as a request code: widget ID is constant for an instance of a widget. Instead, use an ID that's unique for each row, maybe `position`. – ozbek Oct 16 '13 at 01:14
  • @KrisB how are you populating mIds? – Ogen Oct 16 '13 at 03:54
  • @shoerat changing the request code to using `position` fixed my issue. Thanks. If you want to leave a proper response I can give you credit. – Kris B Oct 17 '13 at 02:17
  • @KrisB you can check my demo example [here](http://stackoverflow.com/a/12907825/726863) – Lalit Poptani Oct 17 '13 at 04:54

1 Answers1

3
final PendingIntent piMain = PendingIntent.getActivity(mContext, mAppWidgetId, mi, PendingIntent.FLAG_UPDATE_CURRENT);

At getActivity() do not use mAppWidgetId as a request code: widget ID is constant for an instance of a widget. As a result the platform fails to recognize new Intent as a "new" and will deliver the same PendingIntent all the time. Quoting from docs:

... 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.

There are two typical ways to deal with this.

If you truly need multiple distinct PendingIntent objects active at the same time (such as to use as two notifications that are both shown at the same time), then you will need to ensure there is something that is different about them to associate them with different PendingIntents. This may be any of the Intent attributes considered by Intent.filterEquals, or different request code integers supplied to getActivity(Context, int, Intent, int), getActivities(Context, int, Intent[], int), getBroadcast(Context, int, Intent, int), or getService(Context, int, Intent, int).

So, instead, use an ID that's unique for each row: position is a good candidate.

Community
  • 1
  • 1
ozbek
  • 20,955
  • 5
  • 61
  • 84