Widgets updating service что означает

Полный список

— настраиваем виджет при размещении
— работаем с view-компонентами виджета при обновлении

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

Для этих целей и существует конфигурационный экран (конфигурационное Activity). Он предложит пользователю поля для ввода и сохранит куда-либо (БД, Preferences, …) введенные данные, а при обновлении виджета эти данные будут считаны и использованы для отображения актуальной информации.

Либо, например, мы хотим настроить внешний вид виджета при размещении. Давайте реализуем такой функционал в этом уроке. Возьмем проект из прошлого урока и добавим к нему возможность конфигурирования. Будем настраивать цвет фона виджета и отображаемый текст.

Создадим приложение с виджетом аналогично предыдущему уроку.

Параметры нового проекта:

Project name: P1181_CustomWidget
Build Target: Android 2.3.3
Application name: CustomWidget
Package name: ru.startandroid.develop.p1181customwidget

Я не буду дублировать все исходники прошлого урока, чтобы не загромождать этот. Напомню только, что надо будет создать layout-файл, файл метаданных, класс-наследник AppWidgetProvider и настроить манифест. Ну и про файл strings.xml не забывайте.

В strings.xml давайте поменяем параметр widget_name (чтобы виджеты прошлого и этого урока отличались друг от друга в списке виджетов):

и добавим строки:

Теперь будем добавлять возможность конфигурирования. Для этого нам надо создать Activity. Это Activity будет запускаться системой при добавлении нового экземпляра виджета и на вход получать ID этого экземпляра.

Конфигурационное Activity — совершенно обычное Activity, состоящее из layout-файла и класса.

Начнем с создания layout-файла config.xml:

Три радиокнопки для задания цвета и текстовое поле для текста. Этими настройками будем задавать фон и текст TextView виджета. По нажатию кнопки Ok будем закрывать экран настроек.

Создаем класс для Activity

Для начала озвучу пару фактов из жизни конфигурационного Activity.

1) При вызове оно получает Intent, в котором содержится ID создаваемого экземпляра виджета.

2) При закрытии оно должно формировать результат методом setResult. И в этом ответе передавать Intent с ID экземпляра. Этот механизм мы рассматривали в Уроке 29. Хелп рекомендует при создании Activity сразу формировать отрицательный результат. В этом случае, если пользователь нажмет Назад, система получит ответ, что виджет создавать не надо.

В onCreate мы из Intent (параметр EXTRA_APPWIDGET_ID) извлекаем ID экземпляра виджета, который будет конфигурироваться этим экраном. Если видим, что получен некорректный ID, выходим. Если все ок, то формируем Intent с ID для метода setResult и говорим, что результат отрицательный. Теперь, если пользователь передумает создавать виджет и нажмет в конфигурационном экране Назад, то система будет знать, что виджет создавать не надо.

В onClick мы читаем выбранный цвет и введенный в поле текст и пишем эти значения в Preferences. В имени записываемого параметра мы используем ID, чтобы можно было отличать параметры разных экземпляров друг от друга. Далее мы говорим системе, что результат работы положительный, и виджет можно создавать. Закрываем Activity.

Добавим Activity в манифест и настроим ему фильтр с action = android.appwidget.action.APPWIDGET_CONFIGURE.

Также необходимо добавить в файл метаданных (xml/widget_metadata.xml) параметр android:configure и указать в нем полный путь к классу Activity

Теперь система будет знать, что ей надо вызвать Activity (указанное в метаданных) при добавлении очередного экземпляра виджета. А т.к. при вызове она использует action android.appwidget.action.APPWIDGET_CONFIGURE, поэтому мы прописали его в манифесте.

Итак, мы в Activity получили ID экземпляра виджета и записали настройки с экрана в Preferences. Теперь нам надо при обновлении виджета эти настройки читать и применять к внешнему виду.

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

onDeleted у нас вызывается, когда виджет удаляется с экрана. Если виджет удален, то логично будет удалить и все настройки для него из Preferences. Это и делаем.

Метод updateWidget обновляет конкретный экземпляр виджета, получая на вход его ID. Здесь мы читаем настройки (и сразу выходим, если нет настройки WIDGET_TEXT), которые записало нам конфигурационное Activity для этого экземпляра виджета. Нам надо применить эти параметры к view-компонентам нашего виджета. Но (насколько я это понимаю) за отображение виджета отвечает один процесс (какой-нибудь Home), а наш код из MyWidget будет выполняться в другом, своем собственном процессе. Поэтому у нас нет прямого доступа к view-компонентам виджета. И мы не можем вызывать метода типа setText и setBackgroundColor напрямую. Поэтому используется класс RemoteViews, он предназначен для межпроцессной работы с view.

Создаем RemoteViews. На вход он принимает имя пакета нашего приложения и ID layout-файла виджета. Теперь RemoteViews знает view-структуру нашего виджета. Осталось понять, как настраивать конкретные view. Это немного отличается от привычной нам работы с view-компонентами.

RemoteViews имеет несколько методов работы с view, где мы указываем ID нужного нам view-компонента и значение, которое хотим передать. Из названия этих методов понятно, что они делают. В нашем случае мы используем метод setTextViewText. По названию понятно, что этот метод вставит текст в TextView. Мы вызываем его и передаем ID нашего TextView (из layout-файла виджета) и текст, который хотим в него поместить. Система потом найдет в виджете view с указанным ID (R.id.tv), и вызовет для него метод setText с указанным текстом (widgetText).

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

В названии общего метода содержится тип данных, которые вы хотите передать. А на вход методу кроме ID view и значения, необходимо будет указать имя метода. В нашем случае мы хотим присвоить цвет фону TextView. Цвет у нас типа int, поэтому мы вызываем метод setInt и передаем ему ID view, имя метода (который бы вызывали в случае доступа к view – setBackgroundColor) и значение цвета. Система найдет в виджете view с указанным ID (R.id.tv) и вызовет для него указанный метод (setBackgroundColor) с указанным значением (widgetColor).

RemoteViews сформирован. Используем AppWidgetManager, чтобы применить к виджету наши сформированные view-настройки. Для этого используется метод updateAppWidget, который на вход берет ID экземпляра виджета и объект RemoteViews. Система найдет указанный экземпляр виджета и настроит его так, как мы только что накодили.

В итоге у нас получилось, что Activity настройки пишет, а MyWidget читает и применяет при обновлении виджета.

Все сохраняем и запускаем (инсталлим) приложение.

В списке виджетов выбираем наш My second widget (не перепутайте с виджетом с прошлого урока)

и видим наше Activity. Давайте цвет сделаем синий, и введем какой-нибудь текст.

Жмем Ok. Виджет не изменился.

Давайте смотреть логи, чтобы понять причину.

onEnabled
onUpdate [28]
updateWidget 28
onCreate config
finish config 28

onEnabled – размещение первого экземпляра.

Затем вызвался onUpdate и попытался обновить (updateWidget) экземпляр с ID 28 (у вас может быть другой). Но т.к. никаких Preferences для него мы еще на тот момент не настроили, то обновление не произошло. Напомню, что такое поведение мы накодили в методе updateWidget. Если он не находит текст в WIDGET_TEXT, то он завершается.

А вот уже после этого запустилось Activity (onCreate). В нем мы сделали необходимые настройки и нажали Ок, отработал finish.

Т.е. что получилось? onUpdate вызвался ПЕРЕД конфигурированием (когда настройки виджета еще не были сохранены), но не вызвался ПОСЛЕ завершения работы конфигурационного экрана (когда настройки сохранены и их можно использовать для обновления). Т.е. настройки мы в Activity сохранили, но виджет их пока не прочел. Теперь эти настройки применятся только при следующем обновлении, т.е. через 40 минут, как мы указывали в файле метаданных.

Зачем делается onUpdate перед вызовом Activity – непонятно. К тому же хелп английским по белому цинично и жирным шрифтом заявляет, что не может такого быть:

«… when you implement the Activity: … The onUpdate() method will not be called when the App Widget is created.«

В общем, это известный баг, смиримся с ним. К тому же у нас в методе updateWidget стоит защита от этого – мы проверяем, что в Preferences записан WIDGET_TEXT. Если его нет, то мы ничего не делаем.

Нам осталось придумать, как сделать так, чтобы наш виджет сразу подхватывал изменения после закрытия конфигурационного экрана, а не ожидал следующего обновления по расписанию. Для этого мы можем обновлять виджет вручную при успешном закрытии Activity, ведь мы знаем ID экземпляра. Будем вызывать метод updateWidget из класса MyWidget. Именно для этого мы и сделали его static.

В ConfigActivity в метод onClick надо добавить пару строк:

В этих строках мы вызываем метод updateWidget и передаем туда context, AppWidgetManager, SharedPreferences и ID экземпляра. Они должны сработать после того, как мы сохраним Preferences, поэтому поместите их в методе onClick после строки

В результате виджет обновится при закрытии Activity.

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

Добавим второй экземпляр. Настроим его

Жмем Ок. Видим, что обновление сработало.

onUpdate [29]
updateWidget 29
onCreate config
updateWidget 29
finish config 29

Видим, что сработал updateWidget примерно в одно время с закрытием Activity (очередность зависит от того, куда вы поместили две строки обновления виджета).

Напоследок попробуйте добавить еще один экземпляр виджета, но нажмите Назад в конфигурационном Activity. Виджет не должен появиться. А логи покажут следующее:

onUpdate [30]
updateWidget 30
onCreate config
onDeleted [30]

Т.е. виджет таки создался, но после закрытия Activity был удален системой, т.к. мы передали RESULT_CANCELED в setResult.

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

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

На следующем уроке:

— подробно разбираемся с PendingIntent
— используем AlarmManager

Присоединяйтесь к нам в Telegram:

— в канале StartAndroid публикуются ссылки на новые статьи с сайта startandroid.ru и интересные материалы с хабра, medium.com и т.п.

— в чатах решаем возникающие вопросы и проблемы по различным темам: Android, Kotlin, RxJava, Dagger, Тестирование

— ну и если просто хочется поговорить с коллегами по разработке, то есть чат Флудильня

— новый чат Performance для обсуждения проблем производительности и для ваших пожеланий по содержанию курса по этой теме

Обновление виджетов для Android 12. Часть 1

Виджеты уже давно являются важной частью возможностей Android, и многие приложения эффективно используют виджеты для повышения вовлеченности пользователей. Пользователи любят виджеты за возможность использовать функции приложения без его запуска и настраивать домашний экран своего устройства. В Android 12 обновлены существующие API виджетов и изменен дизайн виджетов в соответствии с языком дизайна «Material You». Эти изменения позволяют создавать более привлекательные виджеты, использующие цвета темы устройства и закругленные углы, а также улучшают открываемость и визуальные возможности поиска и размещения виджетов.

До изменений (Android 11) и после изменений со светлой и темной темой (Android 12)

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

Визуальные изменения

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

Добавьте динамические цвета

Material You нацелен на более персонализированный пользовательский опыт. В Android 12 динамические цвета позволяют вашему виджету смотреться более гармонично с другими виджетами и системой. Виджеты могут использовать тему системы по умолчанию Theme.DeviceDefault.DayNight и использовать атрибуты цвета темы в элементах пользовательского интерфейса виджета. Для этого необходимо создать пользовательскую тему из родительской DeviceDefault для версий ниже 31.

Если ваш minTargetSDK ниже версии 21, вам необходимо предоставить стили для версии 21, поскольку android:attr/colorBackground, используемый в чертежах, требует уровня API 21.

Теперь, создавая тему, вы можете установить стиль для layout-a виджета.

Как было раньше и автоматическая маскировка углов против закругленных углов и примененных отступов

Переходы

Android 12 предлагает улучшенные переходы при запуске приложения из виджета. Этот переход обрабатывается системой автоматически и не будет отображаться на старых версиях Android. Чтобы включить его, необходимо указать id и установить его значение в android:id/background на корневом элементе макета виджета.

Замедленный переход

Если ваш виджет использует broadcast trampolines, что означает, что ваш виджет создает PendingIntent по клику пользователя, чтобы запустить событие из броадкаста или сервиса, эта анимация не будет использоваться.

Новые улучшения предпросмотра виджетов

Превью

В Android 12 есть новый улучшенный инструмент выбора виджетов. Вместо использования статичного ресурса drawable, новый виджет-пикер использует XML-layout для динамического создания масштабированного предварительного просмотра вашего виджета. Если ваш виджет не содержит динамических элементов, таких как ListView или GridView, вы можете просто использовать layout виджета для предварительного просмотра. Чтобы это работало, необходимо установить значения по умолчанию непосредственно в исходный макет.

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

Когда у вас есть тема предварительного просмотра, вы можете применить ее к элементу предварительного просмотра в layout.

Наконец, вам нужно настроить layout виджета, чтобы он был указан в качестве атрибута previewLayout для appwidget-provider.

Статический предварительный просмотр и предварительный просмотр с масштабированием

Установка значений по умолчанию непосредственно на макете невозможна для нескольких элементов, отображаемых в ListView, GridView или Stack. В таких случаях можно создать другой layout для предварительного просмотра виджета и установить несколько жестко закодированных элементов в этом макете. При этом рекомендуется не дублировать весь layout, а использовать тег для повторного использования тех частей макета, которые работают со значениями по умолчанию. Вы можете установить этот новый layout в качестве атрибута previewLayout в appwidget-provider.

Описание

Вы также можете установить атрибут description, чтобы предоставить описание, которое будет отображаться в виджет-пикере. Хотя это необязательно, предоставление описания может помочь пользователям лучше понять, что может делать ваш виджет.

Описание виджета

Резюмируя

Это было не слишком сложно, не так ли? В этом посте вы увидели, как обновить дизайн виджета и предложить лучший пользовательский опыт в виджет-пикере. Это действительно просто, чтобы начать обновлять ваши виджеты для Android 12, и ваши пользователи сразу же заметят визуальную разницу. Но это еще не все. В следующей статье мы рассмотрим новые API, которые сделают ваши виджеты более персонализированными, более отзывчивыми и более интерактивными.

Обновление виджета для домашнего экрана Android по таймеру

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

Android предоставляет в распоряжение разработчика как собственные средства обновления виджета через заданный интервал времени (по таймеру), так и стандартные средства языка Java из пакета java.util.

Допустим, есть некий виджет, который отображает время.

Функция, которая возвращает текущее время в строковом формате:

Стандартный способ Android

Для управления обновлением по таймеру используется атрибут updatePeriodMillis, который указывается в описании виджета и задаёт интервал обновления в миллисекундах. Например, такой виджет должен обновляться каждые 30 минут:

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

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

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

  • В значении атрибута updatePeriodMillis можно указать любой интервал обновления, но система будет обновлять виджет не чаще чем один раз в 30 минут (документация);
  • Обновление виджета вручную при помощи отправки через Intent стандартного действия ACTION_APPWIDGET_UPDATE на практике также не всегда даёт удовлетворительный результат и, по сути, сводится к использованию таймера (см. ниже).

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

Использование таймера

Для работы с более часто обновляющимися данными необходимо использовать иные способы.

Один из таких способов предоставляет само ядро Java в пакете java.util. А, именно использование классов Timer и TimerTask.

Создаём член класса виджета – экземпляр класса Timer.

Далее вызываем вышеописанную функцию обновления виджета в качестве задания таймера.

Последний параметр метода schedule – интервал выполнения задания таймера в миллисекундах.

После этого просто запускаем таймер из метода onUpdate:

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

Данный способ не совсем корректный с точки зрения документации, но за то надёжный и универсальный.

Что касается того какой способ наиболее предпочтителен.

Здесь необходимо исходить из конкретной задачи, а точнее из того насколько часто требуется обновлять виджет.

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

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

В тоже время данный способ имеет один существенный недостаток, который перечёркивает почти все его достоинства – когда устройство переходит в спящий режим (экран «гаснет»), все таймеры останавливаются. Поэтому, если предполагается обновление виджета и в спящем режиме или автоматическое обновление после выхода из него, данный способ также не подходит.

Использование AlarmManager

Объект AlarmManager служит для доступа к службе AlarmService, которая предназначена для отправки пользователю различных сообщений или выполнения тех или иных действий в заданное время, как единовременно, так и периодически с определённым временным интервалом.

По сути AlarmService это ни что иное, как планировщик задач в Android.

AlarmService – системная служба Android и работает даже в спящем режиме. Поэтому сообщения отправленные посредством этой службы будут доставлены в требуемое время.

Механизм обновления виджета при помощи AlarmManager включает две основные части:

  • Создание задачи и установка момента обновления виджета в его коде.
  • Вспомогательная служба, которая собственно и осуществляет обновление виджета.

Для начала создадим вспомогательную службу.


источники:

http://habr.com/ru/post/573806/

http://streletzcoder.ru/obnovlenie-vidzheta-dlya-domashnego-ekrana-android-po-taymeru/