Question

I'm implementing a Widget that has a ConfigurationActivity, and must stay compatible to Eclair(2.1).

The documentation about AppWidgetProviders onUpdate method states clearly that:

... .However, if you have declared a configuration Activity, this method is not called when the user adds the App Widget, but is called for the subsequent updates. It is the responsibility of the configuration Activity to perform the first update when configuration is done. (See Creating an App Widget Configuration Activity below.)

Unfortunately this isn't true (at least for my Nexus S with JellyBean). In Fact onUpdate gets called before onCreate of my ConfigurationActivity triggers. I want to know, if there is similar behavior on other phones, and if it is possible to prevent the onUpdate call inside my Provider?

My Workaround is to store a flag in SharedPreferences inside my WidgetConfigurationActivity with that particular AppWidgetId. If it isn't there, I can assume that the ConfigurationActivity wasn't called first. This works, but is in my point of View really ugly. If I cannot prevent onUpdate from triggering, is there a better solution?

Was it helpful?

Solution

Yes, onUpdate() gets called when you add a widget on the homescreen. See here:

http://developer.android.com/reference/android/appwidget/AppWidgetProvider.html

http://developer.android.com/reference/android/appwidget/AppWidgetManager.html#ACTION_APPWIDGET_UPDATE

I'm not sure if there is a way to not trigger it when a widget is created. But you can stop it from triggering again by setting the "updatePeriodMillis" field in Widget Info XML file to 0 or just leaving it blank.

Another way would be to store the widget IDs somewhere. Now whenever a new widget is added, in your Receiver class, check if the ID already exists or not. If it does not exist (meaning a new widget), then dont execute any code. Also, remove widget ID from your records whenever a widget is deleted. Since there is a possibility that you removed a widget, then later added a new widget which has the same ID as the old one.

Hope that helps!

EDIT: In the onReceive() method in your Receiver class, do this:

public void onReceive(Context context, Intent intent) {
    // TODO Auto-generated method stub

    int appWidgetId = intent.getIntExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, AppWidgetManager.INVALID_APPWIDGET_ID);
    if( appWidgetId != AppWidgetManager.INVALID_APPWIDGET_ID )
    {
        super.onReceive(context, intent);
    }

}

When a widget is first selected from the Widgets list, its appWidgetId will be equal to INVALID_APPWIDGET_ID until it is added on the home screen. Since "super.onReceive()" calls the onUpdate() method when a widget is selected, onUpdate() will not be called the first time.

OTHER TIPS

I have got this error too.

Even i set updatePeriodMillis to 0. My onUpdate is running before i start Widget activity configuration. I think this is a bug in android widget.

I solved this problem by adding an action to the intent in onUpdate then making an if check onReceive to see if widget was clicked:

I added intentClick.setAction(WIDGET_CLICKED); which only gets triggered when clicking the widget.

public class WidgetProvider extends AppWidgetProvider {

    private static final String TAG = WidgetProvider.class.getSimpleName();
    private static String WIDGET_CLICKED = "widget_clicked";

public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
    Log.e(TAG, "onUpdate()");

    remoteViews = new RemoteViews(context.getPackageName(), R.layout.main);
    watchWidget = new ComponentName(context, WidgetProvider.class);

    Intent intentClick = new Intent(context, WidgetProvider.class);
    intentClick.setAction(WIDGET_CLICKED);
    intentClick.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, "" + appWidgetIds[0]);

    PendingIntent pendingIntent = PendingIntent.getBroadcast(context, appWidgetIds[0], intentClick, 0);
    remoteViews.setOnClickPendingIntent(R.id.img_btn, pendingIntent);
    remoteViews.setInt(R.id.img_btn, "setBackgroundResource", R.drawable.play);

    appWidgetManager.updateAppWidget(watchWidget, remoteViews);
}

@Override
public void onReceive(Context context, Intent intent) {
    super.onReceive(context, intent);

    Log.e(TAG, "onReceive()");
    Bundle extras = intent.getExtras();

    //If AND ONLY IF WIDGET_CLICKED
    if (extras != null && intent.getAction().equals(WIDGET_CLICKED)) {
        remoteViews = new RemoteViews(context.getPackageName(), R.layout.main);

        //If isPlaying
        if (isPlaying) {
            //setBackground as PLAY
            remoteViews.setInt(R.id.img_btn, "setBackgroundResource", R.drawable.play);
            isPlaying = false;

            Intent i = new Intent(context, MediaPlayerService.class);
            i.putExtra("command", "stopSong");
            context.startService(i);

            //If NOT playing
        } else {
            //setBackground as STOP
            remoteViews.setInt(R.id.img_btn, "setBackgroundResource", R.drawable.stop);
            isPlaying = true;

            Intent i = new Intent(context, MediaPlayerService.class);
            i.putExtra("command", "playRandomSong");
            context.startService(i);
        }

        watchWidget = new ComponentName(context, WidgetProvider.class);

        (AppWidgetManager.getInstance(context)).updateAppWidget(watchWidget, remoteViews);
    }
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top