Android update all widgets

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

— настраиваем виджет при размещении
— работаем с 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.

Читайте также:  Android воспроизвести по сети

Создаем 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 (Home screen) Widgets — Tutorial

Developing Android Widgets. This article describes how to create home screen widgets in Android.

1. Prerequisites

The following description assume that you already have experience in building standard Android application. Please see https://www.vogella.com/tutorials/Android/article.html — Android Tutorial. It also partly uses Android services. You find an introduction into Android Services in https://www.vogella.com/tutorials/AndroidServices/article.html — Android Service Tutorial.

2. Android Widgets

2.1. Overview about AppWidgets

2.2. Home screen widgets

Home screen widgets are broadcast receivers which provide interactive components. They are primarily used on the Android home screen. They typically display some kind of data and allow the user to perform actions with them. For example, a widget can display a short summary of new emails and if the user selects an email, it could start the email application with the selected email.

To avoid confusion with views (which are also called widgets), this text uses the term home screen widgets, if it speaks about widgets.

A widget runs as part of the process of its host. This requires that the widget preserves the permissions of their application.

Widget use RemoteViews to create their user interface. A RemoteView can be executed by another process with the same permissions as the original application. This way the widget runs with the permissions of its defining application.

The user interface for a Widget is defined by a broadcast receiver. This receiver inflates its layout into an object of type RemoteViews . This object is delivered to Android, which hands it over the home screen application.

2.3. Steps to create a Widget

To create a widget, you:

Define a layout file

Create an XML file ( AppWidgetProviderInfo ) which describes the properties of the widget, e.g. size or the fixed update frequency.

Create a BroadcastReceiver which is used to build the user interface of the widget.

Enter the Widget configuration in the AndroidManifest.xml file.

Optional you can specify a configuration activity which is called once a new instance of the widget is added to the widget host.

2.4. Widget size

Before Android 3.1 a widget always took a fixed amount of cells on the home screen. A cell is usually used to display the icon of one application. As a calculation rule you should define the size of the widget with the formula: ((Number of columns / rows) * 74) — 2 . These are device independent pixels and the -2 is used to avoid rounding errors.

As of Android 3.1 a widget can be flexible in size, e.g., the user can make it larger or smaller. To enable this for widget, you can use the android:resizeMode=»horizontal|vertical» attribute in the XML configuration file for the widget.

3. Creating the Broadcast receiver for the widget

3.1. Create and configure widget

To register a widget, you create a broadcast receiver with an intent filter for the android.appwidget.action.APPWIDGET_UPDATE action.

The receiver can get a label and icon assigned. These are used in the list of available widgets in the Android launcher.

You also specify the meta-data for the widget via the android:name=»android.appwidget.provider attribute. The configuration file referred by this metadata contains the configuration settings for the widget. It contains, for example, the update interface, the size and the initial layout of the widget.

3.2. Available views and layouts

A widget is restricted in the View classes it can use. As layouts you can use the FrameLayout , LinearLayout and RelativeLayout classes. As views you can use AnalogClock , Button , Chromometer , ImageButton , ImageView , ProgressBar and TextView .

As of Android 3.0 more views are available: GridView , ListView , StackView , ViewFlipper and AdapterViewFlipper . These adapter views require that you define a collection view widget which is described later in this tutorial.

The only interaction that is possible with the views of a widget is via an OnClickListener event. This OnClickListener can be registered on a widget and is triggered by the user.

3.3. AppWidgetProvider

Your BroadcastReceiver implementation typically extends the AppWidgetProvider class.

The AppWidgetProvider class implements the onReceive() method, extracts the required information and calls the following widget life cycle methods.

As you can add several instances of a widget to the home screen, you have life cycle methods which are called only for the first instance added / removed to the home screen and others which are called for every instance of your widget.

Table 1. Life cycle method

Called the first time an instance of your widget is added to the home screen.

Called once the last instance of your widget is removed from the home screen.

Called for every update of the widget. Contains the ids of appWidgetIds for which an update is needed. Note that this may be all of the AppWidget instances for this provider, or just a subset of them, as stated in the method’s JavaDoc. For example, if more than one widget is added to the home screen, only the last one changes (until reinstall).

Widget instance is removed from the home screen.

3.4. Receiver and asynchronous processing

A widget has the same runtime restrictions as a normal broadcast receiver, i.e., it has only 5 seconds to finish its processing.

A receive (widget) should therefore perform time consuming operations in a service and perform the update of the widgets from the service.

4. Widget updates

A widget gets its data on a periodic timetable. There are two methods to update a widget, one is based on an XML configuration file and the other is based on the Android AlarmManager service.

In the widget configuration file you can specify a fixed update interval. The system will wake up after this time interval and call your broadcast receiver to update the widget. The smallest update interval is 1800000 milliseconds (30 minutes).

The AlarmManager allows you to be more resource efficient and to have a higher frequency of updates. To use this approach, you define a service and schedule this service via the AlarmManager regularly. This service updates the widget.

Please note that a higher update frequency will wake up the phone from the energy safe mode. As a result your widget consumes more energy.

5. Exercise: widget with fixed update interval

5.1. Target

In the following tutorial you create a widget which displays a random number. This random number is updated every 30 minutes. You also register an OnClickListener so that the widgets updates once the user clicks on it.

The resulting widget will look like the following.

5.2. Create project and widget implementation

Create a new Android project called de.vogella.android.widget.example with an activity in the package de.vogella.android.widget.example .

Create a new file myshape.xml in the /res/drawable_ folder. This file defines the drawable used as background in the widget.

Define the following widget_layout.xml file under the res/layout_ folder.

Create a new resource file called widget_info.xml via right click on the res folder and by selecting New Android resource file .

Create the following receiver class which is called during updates.

Open the AndroidManifest.xml and register your widget similar to the following listing.

This attribute specifies that the AppWidgetProvider accepts the ACTION_APPWIDGET_UPDATE broadcast and specifies the metadata for the widget.

5.3. Validate

Deploy your application on your Android device. Once your application has been deployed use the Android launcher to install your new widget on the home screen and test it.

6. Collection View Widgets

Collection view widgets add support for the usage of the ListView , StackView and GridView classes in widgets.

For collection view widgets you need two layout files, one for the widget and one for each item in the widget collection.

The widget items are filled by an instance of the RemoteViewsFactory factory class.

This factory class is provided by an Android service which extends the RemoteViewsService class. This service requires the android.permission.BIND_REMOTEVIEWS permission.

To connect your views with the service, you use your onUpdate() method in your widget implementation.

You define an intent pointing to the service and use the setRemoteAdapter method on the RemoteViews class.

7. Enabling a app widget for the lock Screen

Since Android 4.2, it is possible to add home screen app widgets to the lock screen of an Android device. To enable your widget for the look screen you need to add keyguard category in the android:widgetCategory attribute in the AppWidgetProviderInfo XML file. The following code shows an example.

In this example you declare a widget to support both — the home and the lock screens. If you recompile and launch your application now, you will be able to add the widget to the lock screen already.

You can also detect a widget category at runtime. For this, in the AppWidgetProvider.onUpdate() method, you can check for the category option of a widget with the following code.

Using this technique you can decide at runtime whether the widgets your application provides, will look differently, when they are hosted on the lock screen.

Similarly to how you used the android:initialLayout attribute for defining an initial layout for home screen widgets, you can use a new android:initialKeyguardLayout attribute for the lock screen in the AppWidgetProviderInfo XML file. This layout will appear immediately after a widget is added and will be replaced by the real layout once the widget is initialized.

8. Exercise: Update widget via a service

The following will demonstrate the usage of a service to update the widget.

Create the following UpdateWidgetService class in your project.

Add this class as a Service to your AndroidManifest.xml file.

Change MyWidgetProvider to the following. It will now only construct the service and start it.

Once called, this service will update all widgets. You can click on one of the widgets to update all widgets.

Источник

Читайте также:  Когда будет доступен андроид 6
Оцените статью
Method Description