Android: как принудительно обновить все виджеты определенного вида - PullRequest
13 голосов
/ 29 ноября 2011

Я видел много вопросов в этом направлении, и я продолжаю видеть один и тот же ответ снова и снова.Я не хочу иметь Службу для каждого вида виджетов, которые есть в моем приложении, особенно учитывая, что у моего приложения уже есть 2 постоянных службы.

В частности, если одна из моих существующих служб видит, что данные изменилисьЯ хочу обновить свои виджеты.Делать это по таймеру раздражает, так как между обновлениями могут быть дни, или несколько в течение одного часа.Я хочу, чтобы мои виджеты ВСЕГДА отображали актуальную информацию.

Кажется, что дизайн виджета Android работает на основе того, что ваш виджет извлекает информацию, когда он этого хочет, я думаю, что есть много разумных сценариев, когда действие может пожелатьотправка данных в виджет.

Прочтите ответ ниже, чтобы узнать, как я это сделал.Насколько я понимаю, нет никаких неблагоприятных последствий, если все сделано правильно.

Ответы [ 3 ]

37 голосов
/ 29 ноября 2011

Чтобы принудительно обновить наши виджеты для определенного поставщика виджетов, нам необходимо сделать следующее:

  • Настройка нашего провайдера для получения специализированной трансляции
  • Отправкаспециализированная трансляция с:
    1. Все текущие идентификаторы виджетов, связанные с провайдером
    2. Данные для отправки
    3. Ключи, на которые отвечает только наш провайдер (Важно!)
  • Получение нашего виджета для обновления по клику (без услуги!)

Шаг 1 - Настройте наш AppWidgetProvider

Iне будет подробно рассказывать о создании XML-файла info или изменениях в манифесте Android - если вы не знаете, как правильно создать виджет, то есть множество руководств, которые вы должны прочитать в первую очередь.

Вот пример AppWidgetProvider Класс:

public class MyWidgetProvider extends AppWidgetProvider {

public static final String WIDGET_IDS_KEY ="mywidgetproviderwidgetids";
public static final String WIDGET_DATA_KEY ="mywidgetproviderwidgetdata";

}

@Override
public void onReceive(Context context, Intent intent) {
    if (intent.hasExtra(WIDGET_IDS_KEY)) {
        int[] ids = intent.getExtras().getIntArray(WIDGET_IDS_KEY);
        if (intent.hasExtra(WIDGET_DATA_KEY)) {
           Object data = intent.getExtras().getParcelable(WIDGET_DATA_KEY);
           this.update(context, AppWidgetManager.getInstance(context), ids, data);
        } else {
            this.onUpdate(context, AppWidgetManager.getInstance(context), ids);
        }
    } else super.onReceive(context, intent);
}

@Override
public void onUpdate(Context context, AppWidgetManager appWidgetManager,
        int[] appWidgetIds) {
    update(context, appWidgetManager, appWidgetIds, null);
}

//This is where we do the actual updating
public void update(Context context, AppWidgetmanager manager, int[] ids, Object data) {

    //data will contain some predetermined data, but it may be null
   for (int widgetId : ids) {
        .
        .
        //Update Widget here
        .
        .
        manager.updateAppWidget(widgetId, remoteViews);
    }
}

Шаг 2 - Отправка трансляции

Здесь мы можем создать статический метод, который получит наши виджетыОбновить.Важно, чтобы мы использовали наши собственные ключи с действием обновления виджета, если мы используем AppWidgetmanager.EXTRA_WIDGET_IDS, мы не только сломаем наш собственный виджет, но и другие.

public static void updateMyWidgets(Context context, Parcelable data) {
    AppWidgetManager man = AppWidgetManager.getInstance(context);
    int[] ids = man.getAppWidgetIds(
            new ComponentName(context,MyWidgetProvider.class));
    Intent updateIntent = new Intent();
    updateIntent.setAction(AppWidgetManager.ACTION_APPWIDGET_UPDATE);
    updateIntent.putExtra(MyWidgetProvider.WIDGET_ID_KEY, ids);
    updateIntent.putExtra(MyWidgetProvider.WIDGET_DATA_KEY, data);
    context.sendBroadcast(updateIntent);
}

Если использовать этот метод с несколькимипровайдеры убедитесь, что они используют разные ключи.В противном случае вы можете найти виджет обновления кода виджета b, что может иметь некоторые странные последствия.

Шаг 3 - обновление по щелчку

Еще одна приятная вещь - это получитьнаш виджет обновляется волшебно при каждом нажатии.Чтобы получить это, добавьте следующий код в метод обновления:

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

Intent updateIntent = new Intent();
updateIntent.setAction(AppWidgetManager.ACTION_APPWIDGET_UPDATE);
updateIntent.putExtra(myWidgetProvider.WIDGET_IDS_KEY, ids);
PendingIntent pendingIntent = PendingIntent.getBroadcast(
      context, 0, updateIntent, PendingIntent.FLAG_UPDATE_CURRENT);

views.setOnClickPendingIntent(R.id.view_container, pendingIntent);

Этот код будет вызывать метод onUpdate при каждом нажатии на виджет.

Примечания

  • Любой вызов updateWidgets () приведет к обновлению всех экземпляров нашего виджета.
  • Нажатие на виджет приведет к обновлению всех экземпляров нашего виджета
  • НЕ ТРЕБУЕТСЯ ОБСЛУЖИВАНИЕ
  • Конечно, будьте осторожны, чтобы не обновлять часто - обновления виджетов расходуют заряд батареи.
  • Имейте в виду, что широковещательная рассылка принимается ВСЕМИ поставщиками виджетов, и нашаспециальные ключи, обеспечивающие обновление только наших виджетов.
4 голосов
/ 24 апреля 2013

Извините за OP за поздний ответ, но для любого другого вы можете использовать такой метод, чтобы обновить все виджеты вашего приложения определенного вида (макет и класс):

public static void updateAllWidgets(final Context context,
                                    final int layoutResourceId,
                                    final Class< ? extends AppWidgetProvider> appWidgetClass)
{
    RemoteViews remoteViews = new RemoteViews(context.getPackageName(), layoutResourceId);

    AppWidgetManager manager = AppWidgetManager.getInstance(context);
    final int[] appWidgetIds = manager.getAppWidgetIds(new ComponentName(context, appWidgetClass));

    for (int i = 0; i < appWidgetIds.length; ++i)
    {
        manager.updateAppWidget(appWidgetIds[i], remoteViews);
    }
}

Чтоон создает RemoteViews для вашего макета, а затем захватывает AppWidgetManager и находит все виджеты приложений для предоставленного вами класса, перебирает их и обновляет.

0 голосов
/ 29 ноября 2011

Каждый раз, когда вы имеете дело с типами, довольно просто работать со статикой. И если вы хотите, чтобы определенные вещи происходили на основе «триггера», я бы всегда рекомендовал программирование на основе событий ... По сути, в Android это «событие» по умолчанию (для передачи данных в вашем событии убедитесь, что объект реализует Parcelable интерфейс).

Существует множество примеров этих концепций на различных форумах и в документации SDK.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...