Search code examples
androidandroid-contextandroid-appwidgetintentserviceappwidgetprovider

Android App Widget - which context to use


I have an app widget that starts an intentService on receive update.

I am not sure which context to use in order to update Widget, should I use one of the followings:

  1. Application context
  2. Context received in AppWidgetProvider
  3. IntentService context

Sometimes I have troubles, the update Widget instruction (through RemoteViews) is ignored.

Other times all the content is erased and won't paint again unless I remove widget and add it again.

I am trying to understand why this kind of problems happen.

Widget is started through:

@Override
    public void onUpdate(Context context, AppWidgetManager appWidgetManager,int[] appWidgetIds) {
        Log.d(TAG_PROCESS, " onUpdate ");

        Intent intent = new Intent(context, UpdateService.class);
        intent.setData(Uri.parse(intent.toUri(Intent.URI_INTENT_SCHEME))); // embed extras so they don't get ignored
        intent.setAction(AppWidgetManager.ACTION_APPWIDGET_UPDATE);

        context.startService(intent);

    }

I update widget in the IntentService through these methods:

/** Updates all widgets with the given remoteViews instructions */
    protected static void updateAllWidgets(Context context, RemoteViews remoteView){
        ComponentName thisWidget = new ComponentName(context, WidgetActivity.class);
        AppWidgetManager manager = AppWidgetManager.getInstance(context);
        manager.updateAppWidget(thisWidget, remoteView);
    }

    /** Update a given widget (id) with the given remoteViews instructions */
    protected static void updateWidget(Context context, RemoteViews remoteView, int widgetId){
        AppWidgetManager manager = AppWidgetManager.getInstance(context);
        manager.updateAppWidget(widgetId, remoteView);
    }

Solution

  • Well it seems that the context wasn't the problem.

    I used the service context.

    The issue was because using manager.updateAppWidget(thisWidget, remoteView); sometimes repainted all the widget because as doc says, it specifies the whole Widget description.

    The solution was to use the partial update, because my app widget manages several partial updates to only some displayed views:

    /** Updates all widgets with the given remoteViews instructions */
        protected static void updateAllWidgets(Context context, RemoteViews remoteView){    
            ComponentName thisWidget = new ComponentName(context, WidgetActivity.class);
            AppWidgetManager manager = AppWidgetManager.getInstance(context);
            int[] allWidgetIds = manager.getAppWidgetIds(thisWidget);
            manager.partiallyUpdateAppWidget(allWidgetIds, remoteView);
        }
    
        /** Update a given widget (id) with the given remoteViews instructions */
        protected static void updateWidget(Context context, RemoteViews remoteView, int widgetId){
            AppWidgetManager manager = AppWidgetManager.getInstance(context);
            manager.partiallyUpdateAppWidget(widgetId, remoteView);
        }