Как ни странно, но на русском почти нет нормальных статей по виджетам для Android. Да и на англо язычных ресурсах почти нет простых примеров для старта, все примеры почему-то сложные и тяжелые для понимания. Спешу это исправить.
Структуру проекта и как его создать описывать не буду. Предполагается, что Вы это уже умеете, а для тех, кто не умеет советую почитать вот эту статью. Для виджета нам потребуется создать 3 файла:
Widget provider info – Это xml файл, описывающий метаданные виджета. К ним относятся размер виджета, частота его обновления, файл шаблона и класс конфигурации. Вот так будет выглядить наш файл (res/xml/hello_widget_provider.xml):
Размер виджета можем указывать любой, но гугл рекомендует придерживаться формуле расчёта размера виджета (number of cells * 74) – 2. updatePeriodMillis — это частота обновления виджета, но не чаще чем раз в 30 минут, в целях экономии батарейки. initialLayout – это файл шаблона виджета.
Widget provider — Это java файл, он должен наследоваться от класса AppWidgetProvider. В нашем случае он пока останется пустым (src/ru/example/android/widget/ HelloWidget.java).
Layout – Это шаблон виджета или слой View, кому как нравится. Выглядеть он будет так: (res/layout /main.xml).
Всё основное мы сделали, осталось зарегистрировать виджет в AndroidManifest.xml. Для этого добавим в него следующий код в раздел <application>...</application>:
Теперь можем компилировать проект и смотреть результат в эмуляторе!

Наш виджет хоть и работает, но абсолютно бесполезен. Давайте сделаем так, чтобы он реагировал на нажатие кнопки.
В виджете невозможно повесить полноценное событие на нажатие кнопки или еще на какое-либо событие, как это Вы привыкли делать в Activity. На этом примере Вы увидите, как можно обработать событие от нажатия кнопки. Давайте для начала добавим в наш шаблон кнопку (res/layout /main.xml).
Все взаимодействия с виджетом будем делать в классе provider (src/ru/example/android/widget/ HelloWidget.java). Вот как будет выглядеть простейшая обработка события:
В классе есть 2 метода — onUpdate и onReceive. Метод onUpdate вызывается при обновлении виджета. Частоту обновления мы настроили в файле res/xml/hello_widget_provider.xml атрибутом android updatePeriodMillis=«86400000». Метод onReceive унаследован от класса BroadcastReceiver.
В виджете нельзя обновить отдельный элемент, например текст, как в Activity. Всегда обновляется иерархия Views целиком. Для обновления виджета нам потребуется класс RemoteViews, с помощью которого мы и будем менять иерархию Views целиком. К сожалению, возможности этого класса скудные. Он позволяет нам изменять текст, картинки и вешать событие на клик. Событие в виджете событием можно назвать с натяжкой, api позволяет выполнять всего 3 дейстия:
Добовляем изменения в файл AndroidManifest.xml:
Компилируем, и наслаждаемся резульатом.

Ссылки по теме:
P.S. Попытался описать все максимально просто, чтобы не забить голову, а получить работающий пример. В следующих статьях буду углубляться в тему.
Структуру проекта и как его создать описывать не буду. Предполагается, что Вы это уже умеете, а для тех, кто не умеет советую почитать вот эту статью. Для виджета нам потребуется создать 3 файла:
- Widget provider info
- Widget provider
- Layout
Widget provider info – Это xml файл, описывающий метаданные виджета. К ним относятся размер виджета, частота его обновления, файл шаблона и класс конфигурации. Вот так будет выглядить наш файл (res/xml/hello_widget_provider.xml):
- <?xml version="1.0" encoding="utf-8"?>
- <appwidget-provider xmlns:android="schemas.android.com/apk/res/android"
- android:minWidth="146dip"
- android:minHeight="72dip"
- android:updatePeriodMillis="86400000"
- android:initialLayout="@layout/main" />
Размер виджета можем указывать любой, но гугл рекомендует придерживаться формуле расчёта размера виджета (number of cells * 74) – 2. updatePeriodMillis — это частота обновления виджета, но не чаще чем раз в 30 минут, в целях экономии батарейки. initialLayout – это файл шаблона виджета.
Widget provider — Это java файл, он должен наследоваться от класса AppWidgetProvider. В нашем случае он пока останется пустым (src/ru/example/android/widget/ HelloWidget.java).
- package ru.example.android.widget;
- import android.appwidget.AppWidgetProvider;
- public class HelloWidget extends AppWidgetProvider {
- }
Layout – Это шаблон виджета или слой View, кому как нравится. Выглядеть он будет так: (res/layout /main.xml).
- <?xml version="1.0" encoding="utf-8"?>
- <LinearLayout xmlns:android="schemas.android.com/apk/res/android"
- android:layout_width="fill_parent"
- android:orientation="vertical"
- android:background="@android:color/white"
- android:layout_gravity="center"
- android:layout_height="wrap_content">
- <TextView android:id="@+id/widget_textview"
- android:text="Hello Widget"
- android:layout_height="wrap_content"
- android:layout_width="wrap_content"
- android:layout_gravity="center_horizontal|center"
- android:textColor="@android:color/black"/>
- </LinearLayout>
Всё основное мы сделали, осталось зарегистрировать виджет в AndroidManifest.xml. Для этого добавим в него следующий код в раздел <application>...</application>:
- <receiver android:name=".widget.HelloWidget" android:label="@string/app_name">
- <intent-filter>
- <action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
- </intent-filter>
- <meta-data android:name="android.appwidget.provider"
- android:resource="@xml/hello_widget_provider" />
- </receiver>
Теперь можем компилировать проект и смотреть результат в эмуляторе!

Наш виджет хоть и работает, но абсолютно бесполезен. Давайте сделаем так, чтобы он реагировал на нажатие кнопки.
В виджете невозможно повесить полноценное событие на нажатие кнопки или еще на какое-либо событие, как это Вы привыкли делать в Activity. На этом примере Вы увидите, как можно обработать событие от нажатия кнопки. Давайте для начала добавим в наш шаблон кнопку (res/layout /main.xml).
- <?xml version="1.0" encoding="utf-8"?>
- <LinearLayout xmlns:android="schemas.android.com/apk/res/android"
- android:layout_width="fill_parent"
- android:orientation="vertical"
- android:background="@android:color/white"
- android:layout_gravity="center"
- android:layout_height="wrap_content">
- <TextView android:id="@+id/widget_textview"
- android:text="Hello Widget"
- android:layout_height="wrap_content"
- android:layout_width="wrap_content"
- android:layout_gravity="center_horizontal|center"
- android:textColor="@android:color/black"/>
- <Button android:id="@+id/widget_button"
- android:text="click me"
- android:layout_height="wrap_content"
- android:layout_width="wrap_content"/>
- </LinearLayout>
Все взаимодействия с виджетом будем делать в классе provider (src/ru/example/android/widget/ HelloWidget.java). Вот как будет выглядеть простейшая обработка события:
- public class HelloWidget extends AppWidgetProvider {
- public static String ACTION_WIDGET_RECEIVER = "ActionReceiverWidget";
- @Override
- public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
- //Создаем новый RemoteViews
- RemoteViews remoteViews = new RemoteViews(context.getPackageName(), R.layout.main);
- //Подготавливаем Intent для Broadcast
- Intent active = new Intent(context, HelloWidget.class);
- active.setAction(ACTION_WIDGET_RECEIVER);
- active.putExtra("msg", "Hello Habrahabr");
- //создаем наше событие
- PendingIntent actionPendingIntent = PendingIntent.getBroadcast(context, 0, active, 0);
- //регистрируем наше событие
- remoteViews.setOnClickPendingIntent(R.id.widget_button, actionPendingIntent);
- //обновляем виджет
- appWidgetManager.updateAppWidget(appWidgetIds, remoteViews);
- }
- @Override
- public void onReceive(Context context, Intent intent) {
- //Ловим наш Broadcast, проверяем и выводим сообщение
- final String action = intent.getAction();
- if (ACTION_WIDGET_RECEIVER.equals(action)) {
- String msg = "null";
- try {
- msg = intent.getStringExtra("msg");
- } catch (NullPointerException e) {
- Log.e("Error", "msg = null");
- }
- Toast.makeText(context, msg, Toast.LENGTH_SHORT).show();
- }
- super.onReceive(context, intent);
- }
- }
В классе есть 2 метода — onUpdate и onReceive. Метод onUpdate вызывается при обновлении виджета. Частоту обновления мы настроили в файле res/xml/hello_widget_provider.xml атрибутом android updatePeriodMillis=«86400000». Метод onReceive унаследован от класса BroadcastReceiver.
В виджете нельзя обновить отдельный элемент, например текст, как в Activity. Всегда обновляется иерархия Views целиком. Для обновления виджета нам потребуется класс RemoteViews, с помощью которого мы и будем менять иерархию Views целиком. К сожалению, возможности этого класса скудные. Он позволяет нам изменять текст, картинки и вешать событие на клик. Событие в виджете событием можно назвать с натяжкой, api позволяет выполнять всего 3 дейстия:
- Бросить Broadcast
- Запустить Activity
- Запустить Service
Добовляем изменения в файл AndroidManifest.xml:
- <receiver android:name=".widget.HelloWidget" android:label="@string/app_name">
- <intent-filter>
- <action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
- <action android:name="ru.example.android.widget.ACTION_WIDGET_RECEIVER" />
- </intent-filter>
- <meta-data android:name="android.appwidget.provider"
- android:resource="@xml/hello_widget_provider" />
- </receiver>
Компилируем, и наслаждаемся резульатом.

Ссылки по теме:
- Пишем своё первое приложение на Android
- Подсвечиваемый виджет в Android
- Пишем виджет ХабраКарма ex-CarmaWidget для Android
P.S. Попытался описать все максимально просто, чтобы не забить голову, а получить работающий пример. В следующих статьях буду углубляться в тему.