Hello World widget для Android
Размер виджета можем указывать любой, но гугл рекомендует придерживаться формуле расчёта размера виджета (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).
- version = «1.0» encoding = «utf-8» ?>
- 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» >
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»/> >
Всё основное мы сделали, осталось зарегистрировать виджет в AndroidManifest.xml. Для этого добавим в него следующий код в раздел . :
Теперь можем компилировать проект и смотреть результат в эмуляторе!
Наш виджет хоть и работает, но абсолютно бесполезен. Давайте сделаем так, чтобы он реагировал на нажатие кнопки.
В виджете невозможно повесить полноценное событие на нажатие кнопки или еще на какое-либо событие, как это Вы привыкли делать в Activity. На этом примере Вы увидите, как можно обработать событие от нажатия кнопки. Давайте для начала добавим в наш шаблон кнопку (res/layout /main.xml).
- version = «1.0» encoding = «utf-8» ?>
- 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» >
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»/> android:id = «@+id/widget_button» android:text = «click me» android:layout_height = «wrap_content» android:layout_width = «wrap_content»/> >
Все взаимодействия с виджетом будем делать в классе 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
В нашем случае мы будем рассылать Broadcast (Широковещательное сообщение). В результате получится что-то вроде обычной обработки события. С помощью класса PendingIntent создаём наше событие и регистрируем его в RemoteViews. Затем обновляем виджет. А в методе onReceive ловим наше «событие» и обрабатываем, выводя сообщение с помощью класса Toast.
Добовляем изменения в файл AndroidManifest.xml:
Компилируем, и наслаждаемся резульатом.
Источник
Android — Виджеты
Виджет — это небольшой гаджет или элемент управления вашего Android-приложения, размещенный на главном экране. Виджеты могут быть очень удобными, поскольку они позволяют размещать ваши любимые приложения на главном экране для быстрого доступа к ним. Вы, вероятно, видели некоторые распространенные виджеты, такие как виджет музыки, виджет погоды, виджет часов и т. Д.
Виджеты могут быть разных типов, таких как информационные виджеты, виджеты коллекции, виджеты управления и гибридные виджеты. Android предоставляет нам полную основу для разработки наших собственных виджетов.
Виджет — XML-файл
Для создания виджета приложения первым делом вам нужен объект AppWidgetProviderInfo, который вы определите в отдельном XML-файле виджета. Для этого щелкните правой кнопкой мыши свой проект и создайте новую папку с именем xml . Теперь щелкните правой кнопкой мыши по вновь созданной папке и создайте новый файл XML. Тип ресурса файла XML должен быть установлен на AppWidgetProvider . В файле XML определите некоторые свойства, которые следующие:
Виджет — файл макета
Теперь вы должны определить макет вашего виджета в XML-файле по умолчанию. Вы можете перетащить компоненты для генерации автоматического XML.
Виджет — файл Java
После определения макета теперь создайте новый файл JAVA или используйте существующий, расширьте его классом AppWidgetProvider и переопределите его метод обновления следующим образом.
В методе обновления вы должны определить объект двух классов: PendingIntent и RemoteViews. Его синтаксис —
В конце вы должны вызвать метод update updateAppWidget () класса AppWidgetManager. Его синтаксис —
Являясь частью метода updateAppWidget, в этом классе определены другие методы для работы с виджетами. Они заключаются в следующем —
Sr.No | Метод и описание | |||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
1 |
меры | Описание |
---|---|
1 | Вы будете использовать Android studio для создания приложения Android в пакете com.example.sairamkrishna.myapplication. |
2 | Измените файл src / MainActivity.java, чтобы добавить код виджета. |
3 | Измените res / layout / activity_main, чтобы добавить соответствующие компоненты XML |
4 | Создайте новую папку и XML-файл в res / xml / mywidget.xml, чтобы добавить соответствующие компоненты XML |
5 | Измените AndroidManifest.xml, чтобы добавить необходимые разрешения |
6 | Запустите приложение и выберите работающее устройство Android, установите на него приложение и проверьте результаты. |
Ниже приводится содержание измененного MainActivity.java .
Ниже приводится измененное содержимое файла xml res / layout / activity_main.xml .
Ниже приводится содержимое файла res / xml / mywidget.xml .
Ниже приводится содержимое файла res / values / string.xml .
Ниже приводится содержимое файла AndroidManifest.xml .
Давайте попробуем запустить ваше приложение. Я предполагаю, что вы подключили свое фактическое мобильное устройство Android к компьютеру. Чтобы запустить приложение из студии Android, откройте один из файлов деятельности вашего проекта и нажмите «Выполнить». значок из панели инструментов. Перед запуском приложения Android Studio отобразит следующее окно, чтобы выбрать опцию, в которой вы хотите запустить приложение Android.
Выберите мобильное устройство в качестве опции, а затем проверьте свое мобильное устройство, на котором будет отображаться экран по умолчанию —
Перейдите в раздел виджетов и добавьте созданный виджет на рабочий стол или домашний экран. Это будет выглядеть примерно так —
Теперь просто нажмите на кнопку виджета, которая появляется, чтобы запустить браузер. Но перед этим, пожалуйста, убедитесь, что вы подключены к Интернету. После нажатия кнопки появится следующий экран —
Заметка. Просто изменив URL в файле Java, ваш виджет откроет нужный веб-сайт в браузере.
Источник
Полный список
— создаем простой виджет
— разбираемся в его 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) надо получать текущее время и передавать эту инфу в виджет для отображения. В этом уроке мы пока не будем с этим возиться.
Осталось немного подрисовать манифест. Добавьте туда ваш класс как 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 для обсуждения проблем производительности и для ваших пожеланий по содержанию курса по этой теме
Источник