【问题标题】:onAppWidgetOptionsChanged() called on screen awake. How to prevent this?onAppWidgetOptionsChanged() 在屏幕唤醒时调用。如何防止这种情况?
【发布时间】:2018-09-02 23:50:51
【问题描述】:

我有一个日历小部件,我会在每天凌晨 12:01 自己更新它,当大小发生变化时,我不需要自动更新。我还将updatePeriodMillis 设置为0。我遇到的问题是App Widget 调用onAppWidgetOptionsChanged()

  • 每次屏幕解锁时
  • 每次回家

这对我来说不是问题,但问题是您可以在一瞬间看到 App Widget 正在更新。有谁知道我有什么方法可以防止这种情况发生?

这里的参考是我的 WidgetProvider 类的一部分

@Override
public void onReceive(Context context, Intent intent) {
    String action = intent.getAction();

    if (action != null) {
        if (action.equals(ACTION_REFRESH) || action.equals(ACTION_NEXT) || action.equals(ACTION_PREVIOUS)) {
            context.sendBroadcast(new Intent(action));
        }
    }

    Bundle extra = intent.getExtras();
    if (extra != null && extra.containsKey(KEY_APP_WIDGET_ID)) {
        updateAppWidget(context, AppWidgetManager.getInstance(context), extra.getInt(KEY_APP_WIDGET_ID));
    }
    super.onReceive(context, intent);
}


@Override
public void onAppWidgetOptionsChanged(Context context, AppWidgetManager appWidgetManager, int appWidgetId, Bundle newOptions) {
    int width = Util.dp2px(newOptions.getInt(AppWidgetManager.OPTION_APPWIDGET_MIN_WIDTH));
    Intent broadcastIntent = new Intent(ACTION_REFRESH);
    broadcastIntent.putExtra(KEY_SIZE_CHANGE, width);
    context.sendBroadcast(broadcastIntent);
    updateAppWidget(context, appWidgetManager, appWidgetId);
    super.onAppWidgetOptionsChanged(context, appWidgetManager, appWidgetId, newOptions);
}

private static void updateAppWidget(Context context, AppWidgetManager appWidgetManager,
        int appWidgetId) {

    RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.widget);

    Intent intent = new Intent(context, WidgetService.class);
    views.setRemoteAdapter(R.id.widget_calendar_container, intent);

    // Buttons on widget click handlers
    views.setOnClickPendingIntent(R.id.widget_refresh, getPendingSelfIntent(context, ACTION_REFRESH, appWidgetId));
    views.setOnClickPendingIntent(R.id.widget_next, getPendingSelfIntent(context, ACTION_NEXT, appWidgetId));
    views.setOnClickPendingIntent(R.id.widget_previous, getPendingSelfIntent(context, ACTION_PREVIOUS, appWidgetId));

    // Widget Container click handler
    Intent homeIntent = new Intent(Intent.ACTION_MAIN);
    homeIntent.addCategory(Intent.CATEGORY_LAUNCHER);
    homeIntent.addFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION);
    homeIntent.setComponent(new ComponentName(context.getPackageName(), Home.class.getName()));
    PendingIntent homePendingIntent = PendingIntent.getActivity(context, 0, homeIntent, 0);
    views.setPendingIntentTemplate(R.id.widget_calendar_container, homePendingIntent);


    // Instruct the widget manager to update the widget
    appWidgetManager.updateAppWidget(appWidgetId, views);
    appWidgetManager.notifyAppWidgetViewDataChanged(appWidgetId, R.id.widget_calendar_container);
}

【问题讨论】:

  • 覆盖 onUpdate 使其不执行任何操作。如果您包括整个班级进行测试会有所帮助
  • @Kwright02 谢谢。我进一步调试它,我看到onAppWidgetOptionsChanged() 在屏幕唤醒或用户回家时被调用...
  • 很高兴我能帮上忙。如果还有其他问题或没有解决问题,请在此处重新评论。如果确实解决了问题,请提供您自己问题的答案,以便其他人知道如何解决此问题。
  • 不,它没有解决它,但我现在知道问题实际在哪里。 @Kwright02
  • 请注意,您的代码可能存在无限循环。您有一个 BroadcastReceiver 重新广播刚刚收到的 Intent 操作,当该操作是三个值之一时(例如,ACTION_REFRESH)。您的接收器显然可以接收此类操作,因此它将接收广播,发送广播,接收它刚刚发送的广播,再次发送该广播,等等,AFAICT。这对性能没有帮助。除此之外,看看你是否可以提升WidgetService 的性能。

标签: java android


【解决方案1】:

我更喜欢另一个答案,但这是我目前得到的。

@Override
    public void onAppWidgetOptionsChanged(Context context, AppWidgetManager appWidgetManager, int appWidgetId, Bundle newOptions) {
        int width = Util.dp2px(newOptions.getInt(AppWidgetManager.OPTION_APPWIDGET_MIN_WIDTH));
        if (width != WidgetRemoteViewsFactory.width) {
            Intent broadcastIntent = new Intent(ACTION_REFRESH);
            broadcastIntent.putExtra(KEY_SIZE_CHANGE, width);
            LocalBroadcastManager.getInstance(context).sendBroadcast(broadcastIntent);
            updateAppWidget(context, appWidgetManager, appWidgetId);
            super.onAppWidgetOptionsChanged(context, appWidgetManager, appWidgetId, newOptions);
        }
    }

我在 WidgetRemoteViewsFactory 上将我感兴趣的字段 width 设为静态,并且仅在该字段更改时才进行广播。我似乎无法阻止 onAppWidgetOptionsChanged() 被调用,因为每次唤醒屏幕时都会广播和接收AppWidgetManager.ACTION_APPWIDGET_OPTIONS_CHANGED

Android 文档说

当此小部件以新尺寸布局时,响应 AppWidgetManager.ACTION_APPWIDGET_OPTIONS_CHANGED 广播而调用。 - AppWidgetProvider#onAppWidgetOptionsChanged

但每次屏幕唤醒时都会广播该动作。

如果有人有更好的解决方案,请随时发布。必须有更好的解决方案,否则这是 Android 方面的错误。

【讨论】:

  • “我在 WidgetRemoteViewsFactory 上将我感兴趣的字段宽度设为静态,并且我只在该字段更改时才广播”——大多数情况下,width 将是 0,正如您将有一个新的过程,所以static 值将恢复为默认值。 “我似乎无法阻止 onAppWidgetOptionsChanged() 被调用”——调用的时间和频率取决于主屏幕实现、Google(通过 Android 源代码)以及可能的设备制造商的组合。您的性能问题似乎出现在WidgetService
  • @CommonsWare 那你有什么推荐的呢?我已通过仅在本地使用LocalBroadcastManager 广播将性能修复到了最佳状态,仅在必要时才查询数据库onDataSetChanged,但我仍然看到 App Widget 一瞬间刷新了四个。
  • “我仍然会在瞬间看到四个 App Widget 刷新”到底是什么意思?
  • 我能想象到的另一个性能问题是渲染小部件本身。这是一个自定义视图,我在其中加载到这样的 Imageview stackoverflow.com/a/4138451/6003161
  • @CommonsWare 屏幕唤醒时,App Widget 会在几分之一秒内为空白,然后正确加载。可能持续 100 毫秒。
猜你喜欢
  • 1970-01-01
  • 2021-12-30
  • 2023-04-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-10-16
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多