На сегодняшний день уже опубликовано большое количество учебного материала, в котором подробно, по шагам описывается процесс создания простого App Widget в стиле "HelloWorld". Под App Widget-ами подразумеваются приложения, которые можно поместить на основной экран в ОС Android. Как правило это различные индикаторы (состояние батареи, яркость экрана, погода, твитты, пробки и т.д.). На мой взгляд лучшим руководством является статья, размещенная непосредственно на сайте гугл.

Здесь мне хотелось больше уделить внимание общей схеме работы с AppWidget-ами и некоторым особым моментам работы с ними. Публикация сделана на основе моего собственного опыта и актуальна на момент написания публикации, но поскольку платформа Android очень быстро развивается, при изучении этой статьи в будущем прошу сверяться с текущей официальной документацией.

Почему виджеты.

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

1. Рождественская ёлка, на игрушках которой загораются различные индикаторы (громкость, включен ли WiFi, заряд батареи и т.д.)

widget_tree
Сhristmas Tree Widget

2. Робот. Тоже пять-в-одном виджет - показывает уровень громкости, заряд батареи, включен ли Wi-Fi, 3G, вибро-режим.

widget_robot
Face Widget

Приложения сейчас не только бесплатные, но и без рекламы. Я просто еще не начинал разбираться с работой AdMob SDK. Возможно, если все-таки разберусь, напишу об этом позже.

Итак.

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


При работе с виджетами самое главное - нужно понимать, что виджеты обновляются в специальном отдельном процессе. Например, если вы работаете внутри обычного активити, то поменять содержимое текстового поля можно просто вызвав метод setText в UI нитке.
Если говорить про AppWidget-ы, то для того, чтобы изменить состояние графического элемента (TextView, ImageView и т. д.), из которого он состоит, нужно использовать специальные классы и методы.

Упрощенно изменения осуществляются в два шага:
1. Вначале нужно воспользоваться объектом RemoteViews, чтобы указать, что именно вы планируете поменять (например, метод setTextViewText).
2. Затем с помощью AppWidgetManager применить изменения, передав созданный объект RemoteViews в метод update.

Если вы хотите обрабатывать событие нажатия на виджет, то это также можно сделать через объект класса RemoteViews с помощью метода setOnClickPendingIntent

Объект класса AppWidgetManager можно получить либо с помощью статического фабричного метода AppWidgetManager.getInstance(context). Также ссылка на менеджер виджетов передается в виде аргумента в методе onUpdate класса AppWidgetProvider.

Класс AppWidgetProvider наследуется от BroadcastReceiver. Поэтому желательно не забыть добавить его в файл AndroidManifest.xml и указать, где расположено xml-описание виджета:

<receiver android:name="ExampleAppWidgetProvider" > 
... 
<meta-data android:name="android.appwidget.provider" android:resource="@xml/example_appwidget_info" /> 
 
</receiver>

Подробное XML-описание виджета находится в XML-файле в папке res/xml/ и содержит в себе разные свойства и настройки виджета (размеры, активити для настройки, layout и т.д.).

 
 
<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android" 
 
android:minWidth="294dp" 
android:minHeight="72dp"   
android:updatePeriodMillis="86400000" и т.д. >
 
</appwidget-provider>

Этому XML-файлу соответствует класс AppWidgetProviderInfo (еще раз повторюсь, подробные примеры и пошаговое описание создание виджета нужно смотреть на сайте гугла).

В целом, диаграмма класса может быть описана грубо следующем образом:
Android App Widget Class Diagram

Анимация.

AnimationDrawable может работать, а может не работать. Зависит от конкретной модели телефона/планшета. Поэтому анимация – это больная тема для многих программистов, которые пытаются сделать анимированный виджет.
Стабильного универсального способа, который бы обеспечивал полноценную работу анимации на всех телефонах пока нет.

Есть два подхода:
1. Делать анимацию самому. Например, с определенной частотой меняя картинку у ImageView.

Здесь есть один нюанс, поскольку виджет работает в отдельном процессе, то при определенной частоте обновлений bitmap-ы перестанут "пролезать" через межпроцессорную связывалку. Как вариант можно передавать не сами картинки, а идентификаторы их ресурсов, но тогда ограничиваемся только существующим набором изображений.

2. Использовать неопределенный прогресс бар, установив для него свой ресурс для отрисовки indeterminateDrawable.

История изменений

API по работе с App Widget-ами наращивалось следующими образом:

  1. Появление виджетов. Level 3 (Android 1.5)
  2. Изменения размера пользователем. Коллекции. Level 11 (Android 3)
  3. Возможность добавления на экран блокировки. Level 17 (Android 4.2)

Итоги

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

Благодарности.

В первую очередь огромное спасибо супер-программистке Татьяне за совместную работу и разработку активити.
За бета-тестирование и замечания - Вове (Московскому), Нику (Лондонскому), Даниэлю (Балийскому), Беке, Гарику, Артуру и Валерии (Ива Виннер). Если кого забыл, прошу прощения, не специально.

Отдельно хочу поблагодарить художника Гришу за суперский дизайн и графику!