Android 防止触发WidgetProvider的onUpdate

Android 防止触发WidgetProvider的onUpdate,android,android-widget,appwidgetprovider,Android,Android Widget,Appwidgetprovider,我正在实现一个具有ConfigurationActivity的小部件,它必须与Eclair(2.1)保持兼容 about AppWidgetProvidersonUpdate方法明确指出: 。但是,如果您声明了配置活动,则当用户添加应用程序小部件时,不会调用此方法,而是调用后续更新。配置活动负责在配置完成时执行第一次更新。(请参阅下面的创建应用程序小部件配置活动。) 不幸的是,这不是真的(至少对于我的NexusS和JellyBean)。事实上,onUpdate在我的ConfigurationAc

我正在实现一个具有ConfigurationActivity的小部件,它必须与Eclair(2.1)保持兼容

about AppWidgetProviders
onUpdate
方法明确指出:

。但是,如果您声明了配置活动,则当用户添加应用程序小部件时,不会调用此方法,而是调用后续更新。配置活动负责在配置完成时执行第一次更新。(请参阅下面的创建应用程序小部件配置活动。)

不幸的是,这不是真的(至少对于我的NexusS和JellyBean)。事实上,
onUpdate
在我的ConfigurationActivity触发器的
onCreate
之前被调用。我想知道,其他手机上是否有类似的行为,以及是否有可能阻止提供商内部的
onUpdate
呼叫

我的解决方法是在WidgetConfigurationActivity中的SharedReferences中使用特定的AppWidgetId存储一个标志。如果没有,我可以假设没有首先调用ConfigurationActivity。这是可行的,但在我看来真的很难看。如果我无法阻止触发onUpdate,是否有更好的解决方案?

是,当您在主屏幕上添加小部件时,会调用onUpdate()。 请看这里:

我不确定是否有办法在创建小部件时不触发它。但是您可以通过将Widget Info XML文件中的“updatePeriodMillis”字段设置为0或将其保留为空白来阻止它再次触发

另一种方法是将小部件ID存储在某处。现在,每当添加新的小部件时,在Receiver类中,检查ID是否已经存在。如果它不存在(意味着一个新的小部件),那么不要执行任何代码。此外,每当小部件被删除时,从记录中删除小部件ID。因为有可能您删除了一个小部件,然后添加了一个与旧部件ID相同的新部件

希望有帮助

编辑: 在Receiver类的onReceive()方法中,执行以下操作:

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

}

当第一次从窗口小部件列表中选择窗口小部件时,其appWidgetId将等于无效的APPWIDGET_ID,直到将其添加到主屏幕上。由于“super.onReceive()”在选择小部件时调用onUpdate()方法,因此不会第一次调用onUpdate()


甚至我也将updatePeriodMillis设置为0。在启动小部件活动配置之前,我的onUpdate正在运行。我认为这是android widget中的一个bug。

我解决了这个问题,在onUpdate中的意图中添加了一个操作,然后在接收时进行if检查,查看widget是否被单击:

我添加了
intentClick.setAction(WIDGET\u单击)仅在单击小部件时触发

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

我真的很想知道:更新文档:
这可能是为了响应已实例化此AppWidget提供程序的新实例、请求的更新间隔已过或系统启动而发送的。
VS
如果您已声明配置活动,当用户添加应用程序小部件时,不会调用此方法。
我已经将updateInterval设置为“0”,并且我已经按照您的建议执行了操作(将Id存储在SharedReferences中)。找到了一种不第一次调用onUpdate()的方法。检查我编辑的答案。工作正常,我只是在我的应用程序中实现了同样的功能。我没有获得
AppWidgetManager。在我的提供程序第一次触发时,无效的\u APPWIDGET\u ID
。事实上,我的
AppWidgetConfigActivity
将接收到的是正确的Id。(JellyBean Galaxy Nexus)无效的_APPWIDGET_ID始终给出一个值,该值永远不会用作小部件的有效ID。我检查时它的值是0。这是创建小部件时getIntExtra返回的。之后,无论何时为同一小部件调用onReceive(),它都会返回该小部件的有效ID。可能是因为我在用Android 2.3.3(API 10),而你在用Jelly Bean。我也在用Android 2.3.3,Rafael说的似乎是对的——我想我从来没有得到过widget ID 0。此外,将updatePeriodMillis留空并不能阻止每次屏幕解锁时调用onUpdate。这只是另一篇不正确的文档——甚至谷歌有时也会出错。我看到每次在创建配置活动之前都会调用onUpdate,无论Android版本、设备或模拟器如何