Creating widgets in android

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

— создаем простой виджет
— разбираемся в его Lifecycle

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

Для понимания темы виджетов желательно знать, что такое BroadcastReceiver. Я о нем упоминал в Уроках 96 и 100. Это просто слушатель, который регистрируется в системе, ловит с помощью настроенного Intent Filter сообщения (Intent) и выполняет какой-либо код. Почему-то не сделал я отдельного урока по нему. Но, думаю, еще сделаю. Есть там свои интересные особенности, о которых можно поговорить.

Думаю, нет особой необходимости подробно объяснять, что такое виджеты. Все их видели на своих девайсах. Это что-то типа мини-приложений расположенных на рабочем столе (Home). Они позволяют просмотреть какую-либо информацию из основных приложений, либо повлиять на поведение этих приложений. В качестве примера можно привести – прогноз погоды, текущее время, баланс какого-либо счета, список сообщений в различных мессенджерах, управление состоянием WiFi/3G/GPS/Bluetooth, яркость экрана и т.д. и т.п. В этом уроке сделаем простейший виджет, который отобразит статичный текст.

Чтобы создать простейший виджет нам понадобятся три детали:

В нем мы формируем внешний вид виджета. Все аналогично layout-файлам для Activity и фрагментов, только набор доступных компонентов здесь ограничен следующим списком:

2) XML-файл c метаданными

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

— layout-файл (из п.1.), чтобы виджет знал, как он будет выглядеть
— размер виджета, чтобы виджет знал, сколько места он должен занять на экране
— интервал обновления, чтобы система знала, как часто ей надо будет обновлять виджет

3) Класс, наследующий AppWidgetProvider. В этом классе нам надо будет реализовать Lifecycle методы виджета.

Давайте создадим три этих детали. Activity нам не понадобится, поэтому не забудьте убрать галку Create Activity в визарде создания нового проекта

Создадим проект без Activity:

Project name: P1171_SimpleWidget
Build Target: Android 2.3.3
Application name: SimpleWidget
Package name: ru.startandroid.develop.p1171simplewidget

Добавим строки в strings.xml:

Создаем layout-файл widget.xml:

RelativeLayout, а внутри зеленый TextView с текстом по центру. Т.е. виджет просто будет показывать текст на зеленом фоне.

Создаем файл метаданных res/xml/widget_metadata.xml:

В атрибуте initialLayout указываем layout-файл для виджета.

Атрибуты minHeight и minWidth содержат минимальные размеры виджета по высоте и ширине.

Есть определенный алгоритм расчета этих цифр. Как вы наверняка замечали, при размещении виджета, экран делится на ячейки, и виджет занимает одну или несколько из этих ячеек по ширине и высоте. Чтобы конвертнуть ячейки в dp, используется формула 70 * n – 30, где n – это количество ячеек. Т.е. если мы, например, хотим, чтобы наш виджет занимал 2 ячейки в ширину и 1 в высоту, мы высчитываем ширину = 70 * 2 – 30 = 110 и высоту = 70 * 1 – 30 = 40. Эти полученные значения и будем использовать в атрибутах minWidth и minHeight.

Атрибут updatePeriodMillis содержит количество миллисекунд. Это интервал обновления виджета. Насколько я понял хелп, указать мы тут можем хоть 5 секунд, но чаще, чем раз в 30 минут (1 800 000) виджет обновляться все равно не будет — это системное ограничение. Давайте пока что поставим интервал 40 минут (2 400 000). В следующих уроках мы разберемся, как самим обновлять виджет с необходимым интервалом.

Осталось создать класс, наследующий AppWidgetProvider.

onEnabled вызывается системой при создании первого экземпляра виджета (мы ведь можем добавить в Home несколько экземпляров одного и того же виджета).

onUpdate вызывается при обновлении виджета. На вход, кроме контекста, метод получает объект AppWidgetManager и список ID экземпляров виджетов, которые обновляются. Именно этот метод обычно содержит код, который обновляет содержимое виджета. Для этого нам нужен будет AppWidgetManager, который мы получаем на вход.

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

onDisabled вызывается при удалении последнего экземпляра виджета.

Во всех методах выводим в лог одноименный текст и список ID для onUpdate и onDeleted.

Повторюсь — в onUpdate мы, по идее, должны накодить какое-то обновление виджета. Т.е. если наш виджет отображает, например, текущее время, то при очередном обновлении (вызове onUpdate) надо получать текущее время и передавать эту инфу в виджет для отображения. В этом уроке мы пока не будем с этим возиться.

Читайте также:  Убрать фокус с элемента android

Осталось немного подрисовать манифест. Добавьте туда ваш класс как Receiver

— укажите для него свои label и icon. Этот текст и эту иконку вы увидите в списке выбираемых виджетов, когда будете добавлять виджет на экран.

— настройте для него фильтр с action = android.appwidget.action.APPWIDGET_UPDATE

— добавьте метаданные с именем android.appwidget.provider и указанием файла метаданных xml/widget_metadata.xml в качестве ресурса

После этого секция receiver в манифесте должна получиться примерно такая:

Виджет готов. Все сохраняем и запускаем. Никаких Activity, разумеется, не всплывет. В консоли должен появиться текст:

\P1171_SimpleWidget\bin\P1171_SimpleWidget.apk installed on device
Done!

Открываем диалог создания виджета и видим в списке наш виджет с иконкой и текстом, которые мы указывали в манифесте для receiver.

Выбираем его и добавляем на экран.

Виджет появился, смотрим логи.

onEnabled
onUpdate [8]

Сработал onEnabled, т.к. мы добавили первый экземпляр виджета. И сразу после добавления, сработал метод onUpdate для этого экземпляра. Видим, что ему назначен (У вас, скорее всего, будет другой ID). Т.е. система добавила экземпляр виджета на экран и вызвала метод обновления с указанием ID экземпляра.

Добавим еще один экземпляр

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

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

Сработал onDeleted и получил на вход ID удаляемого экземпляра виджета.

Удаляем первый экземпляр. В логах:

onDeleted [8]
onDisabled

Снова сработал onDeleted — нас оповестили, что экземпляр виджета с был удален. И сработал onDisabled, т.е. был удален последний экземпляр виджета, больше работающих экземпляров не осталось.

Наш виджет обновляется (получает вызов метода onUpdate) раз в 40 минут. Если кому не лень, добавьте снова пару виджетов на экран и подождите. Когда они снова обновятся, в логах это отразится.

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

BroadcastReceiver

Класс AppWidgetProvider является расширением класса BroadcastReceiver (в манифесте мы его и прописали как Receiver). Он просто получает от системы сообщение в onReceive, определяет по значениям из Intent, какое именно событие произошло (добавление, удаление или обновление виджета), и вызывает соответствующий метод (onEnabled, onUpdate и пр.).

В манифесте мы для нашего Receiver-класса настроили фильтр с action, который ловит события update. Каким же образом этот Receiver ловит остальные события (например, удаление)? Хелп пишет об этом так:

Т.е. ACTION_APPWIDGET_UPDATE – это единственный action, который необходимо прописать явно. Остальные события AppWidgetManager каким-то образом сам доставит до нашего AppWidgetProvider-наследника.

Отступы

Если мы расположим рядом несколько экземпляров виджета, увидим следующую картину

Не очень приятное зрелище. Надо бы сделать отступ.

Добавим android:padding=»8dp» к RelativeLayout в нашем layout-файле

Виджеты на экране поменялись автоматически и теперь выглядят более пристойно.

Кстати, для них сработал onUpdate, смотрите логи. В метод был передан массив ID всех работающих экземпляров виджета.

В Android 4.0 (API Level 14) и выше этот недостаток с отступами был устранен, и вручную делать отступы больше не надо. Давайте проверим. Уберите ранее добавленный в RelativeLayout отступ. И укажите в манифесте android:targetSdkVersion версию 14 (или выше), чтобы система знала, что можно использовать стандартные возможности, а не режим совместимости.

Все сохраняем, запускаем наш виджет на эмуляторе с 4.1. Добавим три экземпляра.

Система сама делает отступы между виджетами.

Получается для версий, ниже 4 надо делать отступ в layout, а для старших версий не надо. Хелп дает подсказку, как сделать так, чтобы ваш виджет корректно работал на всех версиях. Для этого используются квалификаторы версий.

В layout для RelativeLayuot указываете:

И создаете два файла.

res/values/dimens.xml с записью:

и res/values-v14/dimens.xml с записью:

В манифесте android:targetSdkVersion должен быть 14 или выше.

Таким образом, на старых версиях (без системного отступа) отступ будет 8dp, а на новых – 0dp и останется только системный отступ.

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

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

Присоединяйтесь к нам в 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.

Читайте также:  Код java для android

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.

Источник

Читайте также:  Живые обои для всех android
Оцените статью
Method Description