Hello World widget для Android

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

    Структуру проекта и как его создать описывать не буду. Предполагается, что Вы это уже умеете, а для тех, кто не умеет советую почитать вот эту статью. Для виджета нам потребуется создать 3 файла:
    1. Widget provider info
    2. Widget provider
    3. Layout

    Widget provider info – Это xml файл, описывающий метаданные виджета. К ним относятся размер виджета, частота его обновления, файл шаблона и класс конфигурации. Вот так будет выглядить наш файл (res/xml/hello_widget_provider.xml):
    1. <?xml version="1.0" encoding="utf-8"?>
    2. <appwidget-provider xmlns:android="schemas.android.com/apk/res/android"
    3.     android:minWidth="146dip"
    4.     android:minHeight="72dip"
    5.     android:updatePeriodMillis="86400000"
    6.     android:initialLayout="@layout/main" />

    Размер виджета можем указывать любой, но гугл рекомендует придерживаться формуле расчёта размера виджета (number of cells * 74) – 2. updatePeriodMillis — это частота обновления виджета, но не чаще чем раз в 30 минут, в целях экономии батарейки. initialLayout – это файл шаблона виджета.

    Widget provider — Это java файл, он должен наследоваться от класса AppWidgetProvider. В нашем случае он пока останется пустым (src/ru/example/android/widget/ HelloWidget.java).
    1. package ru.example.android.widget;
    2. import android.appwidget.AppWidgetProvider;
    3.  
    4. public class HelloWidget extends AppWidgetProvider {
    5. }


    Layout – Это шаблон виджета или слой View, кому как нравится. Выглядеть он будет так: (res/layout /main.xml).
    1. <?xml version="1.0" encoding="utf-8"?>
    2. <LinearLayout xmlns:android="schemas.android.com/apk/res/android"
    3.         android:layout_width="fill_parent"
    4.         android:orientation="vertical"
    5.         android:background="@android:color/white"
    6.         android:layout_gravity="center"
    7.         android:layout_height="wrap_content">
    8.  
    9. <TextView android:id="@+id/widget_textview"
    10.                 android:text="Hello Widget"
    11.                 android:layout_height="wrap_content"
    12.                 android:layout_width="wrap_content"
    13.                 android:layout_gravity="center_horizontal|center"
    14.                 android:textColor="@android:color/black"/>
    15. </LinearLayout>


    Всё основное мы сделали, осталось зарегистрировать виджет в AndroidManifest.xml. Для этого добавим в него следующий код в раздел <application>...</application>:
    1. <receiver android:name=".widget.HelloWidget" android:label="@string/app_name">
    2.         <intent-filter>
    3.                 <action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
    4.         </intent-filter>
    5.         <meta-data android:name="android.appwidget.provider"
    6.                 android:resource="@xml/hello_widget_provider" />
    7. </receiver>


    Теперь можем компилировать проект и смотреть результат в эмуляторе!


    Наш виджет хоть и работает, но абсолютно бесполезен. Давайте сделаем так, чтобы он реагировал на нажатие кнопки.

    В виджете невозможно повесить полноценное событие на нажатие кнопки или еще на какое-либо событие, как это Вы привыкли делать в Activity. На этом примере Вы увидите, как можно обработать событие от нажатия кнопки. Давайте для начала добавим в наш шаблон кнопку (res/layout /main.xml).
    1. <?xml version="1.0" encoding="utf-8"?>
    2. <LinearLayout xmlns:android="schemas.android.com/apk/res/android"
    3.         android:layout_width="fill_parent"
    4.         android:orientation="vertical"
    5.         android:background="@android:color/white"
    6.         android:layout_gravity="center"
    7.         android:layout_height="wrap_content">
    8.  
    9.         <TextView android:id="@+id/widget_textview"
    10.                 android:text="Hello Widget"
    11.                 android:layout_height="wrap_content"
    12.                 android:layout_width="wrap_content"
    13.                 android:layout_gravity="center_horizontal|center"
    14.                 android:textColor="@android:color/black"/>
    15.         <Button android:id="@+id/widget_button"
    16.                 android:text="click me"
    17.                 android:layout_height="wrap_content"
    18.                 android:layout_width="wrap_content"/>
    19.  
    20. </LinearLayout>


    Все взаимодействия с виджетом будем делать в классе provider (src/ru/example/android/widget/ HelloWidget.java). Вот как будет выглядеть простейшая обработка события:
    1. public class HelloWidget extends AppWidgetProvider {
    2.  
    3.         public static String ACTION_WIDGET_RECEIVER = "ActionReceiverWidget";
    4.  
    5.         @Override
    6.         public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
    7.              //Создаем новый RemoteViews
    8.              RemoteViews remoteViews = new RemoteViews(context.getPackageName(), R.layout.main);
    9.  
    10.              //Подготавливаем Intent для Broadcast
    11.              Intent active = new Intent(context, HelloWidget.class);
    12.              active.setAction(ACTION_WIDGET_RECEIVER);
    13.              active.putExtra("msg""Hello Habrahabr");
    14.  
    15.              //создаем наше событие
    16.              PendingIntent actionPendingIntent = PendingIntent.getBroadcast(context, 0, active, 0);
    17.  
    18.              //регистрируем наше событие
    19.              remoteViews.setOnClickPendingIntent(R.id.widget_button, actionPendingIntent);
    20.  
    21.              //обновляем виджет
    22.              appWidgetManager.updateAppWidget(appWidgetIds, remoteViews);
    23.         }
    24.  
    25.         @Override
    26.         public void onReceive(Context context, Intent intent) {
    27.  
    28.              //Ловим наш Broadcast, проверяем и выводим сообщение
    29.              final String action = intent.getAction();
    30.              if (ACTION_WIDGET_RECEIVER.equals(action)) {
    31.                   String msg = "null";
    32.                   try {
    33.                         msg = intent.getStringExtra("msg");
    34.                   } catch (NullPointerException e) {
    35.                         Log.e("Error""msg = null");
    36.                   }
    37.                   Toast.makeText(context, msg, Toast.LENGTH_SHORT).show();
    38.              } 
    39.              super.onReceive(context, intent);
    40.        }
    41.  
    42. }

    В классе есть 2 метода — onUpdate и onReceive. Метод onUpdate вызывается при обновлении виджета. Частоту обновления мы настроили в файле res/xml/hello_widget_provider.xml атрибутом android updatePeriodMillis=«86400000». Метод onReceive унаследован от класса BroadcastReceiver.
    В виджете нельзя обновить отдельный элемент, например текст, как в Activity. Всегда обновляется иерархия Views целиком. Для обновления виджета нам потребуется класс RemoteViews, с помощью которого мы и будем менять иерархию Views целиком. К сожалению, возможности этого класса скудные. Он позволяет нам изменять текст, картинки и вешать событие на клик. Событие в виджете событием можно назвать с натяжкой, api позволяет выполнять всего 3 дейстия:
    • Бросить Broadcast
    • Запустить Activity
    • Запустить Service
    В нашем случае мы будем рассылать Broadcast (Широковещательное сообщение). В результате получится что-то вроде обычной обработки события. С помощью класса PendingIntent создаём наше событие и регистрируем его в RemoteViews. Затем обновляем виджет. А в методе onReceive ловим наше «событие» и обрабатываем, выводя сообщение с помощью класса Toast.

    Добовляем изменения в файл AndroidManifest.xml:
    1. <receiver android:name=".widget.HelloWidget" android:label="@string/app_name">
    2.        <intent-filter>
    3.              <action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
    4.              <action android:name="ru.example.android.widget.ACTION_WIDGET_RECEIVER" />
    5.        </intent-filter>
    6.        <meta-data android:name="android.appwidget.provider"
    7.                                    android:resource="@xml/hello_widget_provider" />
    8. </receiver>


    Компилируем, и наслаждаемся резульатом.


    Ссылки по теме:


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

    Подробнее
    Реклама
    Комментарии 29
    • –7
      англо язычных, почему то, фиджета, резульатом. + Стилистические, пунктуационные ошибки + Никуда не годный язык статьи. Рускоязычные статьи по виджетам и тут есть:

      Плохо.
      • –6
        Несмотря на мои замечания, автор так и не исправил большинство ошибок в своей статье, что свидетельствует о том, что её качество его не ебёт.
        • +1
          Не материтесь пожалуйста сэр, его статью я не добавлю в индекс, которым пользуется полтысячи человек, пока не исправит.
          • 0
            Что за паника, лишняя статья никогда не лишняя. Автору +1
      • +3
        Теперь можем компилировать проект и смотреть результат в симуляторе!

        Добавьте пожалуйста картинку, чтобы можно было сразу увидеть результат.
        • +1
          Спасибо, добавил
        • +5
          я, конечно, извиняюсь, но ваша статья тоже сложна и тяжела для понимания применительно к новичкам. а более опытные разработчики поймут и те примеры, о которых вы нелестно отозвались. может вы не те сайты посещаете?
          Тут уже в первом комментарии дали ссылки — там на мой взгляд понятнее написано
          • 0
            Как правило первый пример делают простым копипастом, компилируют, запускают, а лишь потом вникают что как работает. Вот этой цели я и преследовал. В случае java и в частности android как правило примеры сложные и присутствует куча конфигов, классов и т.д. Например офф доке от гугла описано создание сложного, полноценного виджета. С оформлением, настройками, событиями и т.д. А из за огромного количества содержимого файлов они показывают только вырезки из них. И как тут новичку вникнуть?
            • 0
              Куда может быть проще:
              d.android.com/resources/samples/WiktionarySimple/index.html

              Всего два файла, один получает данные, второй виджет.

              Или вот действительно хеллоу ворлд для виджета:
              www.vogella.de/articles/AndroidWidgets/article.html
              • 0
                Охренеть, и за что заминусовали комент?
                • 0
                  Например я считаю, что различные начальные туториалы-сэмплы-экзамплы-гайды лучше брать с developer.android.com — там и по делу всё и несложно; так что с Вами согласен.
          • +1
            Спасибо. Сам виджет себе организовал, а вот как верно повесить обработку кнопки не знал. В итоге сделал через сервис, но работало через одно место. Попробую ваш пример.
            • НЛО прилетело и опубликовало эту надпись здесь
              • 0
                Теперь можем компилировать проект и смотреть результат в симуляторе!

                Наверное все же в эмуляторе :)
                • 0
                  Спасибо, исправил
                • 0
                  странная статья… «Hello World» и «описывать не буду. Предполагается, что Вы это уже умеете»
                  • +2
                    Ну по установке среды, созданию проекта по шагам, уже есть подробная статья Пишем своё первое приложение на Android (хотя многие меня ругали за слишком подробную инструкцию), поэтому уместно было бы сослаться просто на неё для тех, кто вообще не знаком с Development for Android.

                    Автору советую статью всё же еще дополнить подробностями и тогда ее вполне можно поместить в Хабраиндекс для статей по программированию под Android. Расскажите поподробнее про виджеты с точки зрения разработки под Android.

                    Также по виджетам есть статья Пишем виджет ХабраКармы
                    • 0
                      спасибо
                      • 0
                        >поэтому уместно было бы сослаться просто на неё для тех, кто вообще не знаком с Development for Android.

                        Спасибо, сделал. Вечером попробую дополнить подробностями.
                    • 0
                      В общем сделали еще сложнее, чем могло бы быть. Начнем:

                      > Для виджета нам потребуется создать 3 файла:
                      > Widget provider info
                      > Widget provider
                      > Layout
                      Мы хоть где нибудь создаем файл «Widget provider info»??? Зачем вводить свои еще определения по вверх тех что есть в андроиде?

                      > Всё основное мы сделали, осталось зарегистрировать виджет в AndroidManifest.xml. Для > этого добавим в него следующий код:
                      Куда, в какую секцию?

                      > Теперь можем компилировать проект и смотреть результат в эмуляторе!
                      Как на него смотреть? Где описание как добавить этот самый виджет, ведь пишем HelloWorld, значит должно быть подробно.

                      > Все взаимодействия с виджетом будем делать в классе provider
                      Класс называется HelloWidget, а не provider. Не пишите ерунды.

                      Зачем так сложно, зачем здесь вообще try/catch?
                      String msg = «null»;
                      try {
                      msg = intent.getStringExtra(«msg»);
                      } catch (NullPointerException e) {
                      Log.e(«Error», «msg = null»);
                      }
                      Toast.makeText(context, msg, Toast.LENGTH_SHORT).show();

                      Достаточно:
                      String msg = intent.getStringExtra(«msg»);
                      Toast.makeText(context, msg == null? "", msg, Toast.LENGTH_SHORT).show();
                      Ну или просто ничего не выводим.

                      > Компилируем, и наслаждаемся резульатом.
                      финиш

                      Где ссылка на исходники?
                      • +1
                        Конечно же
                        Toast.makeText(context, msg == null? "": msg, Toast.LENGTH_SHORT).show();
                      • –1
                        Кстати, есть ли возможность писать на Groovy под Android и отличия?
                        • 0
                          Нет.
                          • 0
                            Вот кстати почему, можете просто объяснить? Вроде ведь в тот же байт код под JVM собирается, да и легко можно использовать все имеющиеся jar файлы.
                        • 0
                          Мм, может кто подскажет? Сделал конфиг к виджету, передаю настройки в виджет через SharedPreferences, и вывожу в TextView на нем. Всё бы хорошо если бы не но — в TextView записывается предыдущее передаваемое значение из конфига. Добавляю ещё один — получаю то значение что хотел в прошлый раз, а то что хотел в этот опять не понятно где. С чем связано — как бы выйти из ситуации?
                          • 0
                            Может, стоит перечитывать конфиг перед самим выводом? Без кода тяжело сказать.
                          • 0
                            вот еще один хеловиджет, не уверен, что методологически правильно написан/описан, зато полезный (ибо пользы от вывода сообщения по клику на кнопке имхо не бывет :) ) fat-hamster.blogspot.com/2010/11/android-widget-part-0.html и еще неск. частей
                            • 0
                              Спасибо — урок в копилку. Читал урок для чайников в книге для чайников — не очень понял, здесь — наоборот все просто.
                              • 0
                                Давно уже не пишу на хабре.
                                И вы знаете что удивительно? Вроде не vk и не instagram,
                                и вроде публика не должна быть обделена интеллектом.
                                Я не говорю за всех, но большинство здесь редкостные засранцы.
                                Первая половина задротов-знатаков русского языка, которые по делу не могут ни чего сказать.
                                Вторая считает себя истинной в последней инстанции и только они все делают по феншую.

                                Ну да, допустил автор пару ошибок и что? Статья потеряла смысл?!
                                >Класс называется HelloWidget, а не provider
                                Ну и зачем это писать вообще? Да вы умный, вы нашли ошибку. Вот и напишите в личку автору.
                                Нет же надо носом ткнуть что бы потешить своё самолюбие. Вы ведь ошибок не совершаете. :)))
                                Все отлично расписано и автор описал рабочую схему:
                                setOnClickPendingIntent(PendingIntent.getBroadcast)->onReceive(здесь можно обновлять виджет)
                                //для умников выше не код а схема
                                catch тут вообще не пришей кобыле хвост и на смысл статьи никак не влияет.

                                Если так дальше дело пойдет, толковых статей на хабре поубавится.

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