Java android создание виджета
Сегодня мы разберемся в том, как создать на Android устройство свой собственный виджет (Widget). Виджет — это всем знакомый элемент рабочего стола, с помощью которого можно получать доступ к некоторым функциям какого — нибудь приложения: просматривать новости в окне виджета, прогноз погоды, обновление новостей на разных сервисах, управлять разными функциями аппарата (блокировать экран, включать радио, Интернет и многое многое другое). На этот раз мы не будем создавать чего то грандиозного и очень полезного, типа там фонарика :), а сделаем простенький виджет, который будет реализован в виде кнопки, при нажатии на которую мы, с помощью стандартного браузера, попадаем на всеми любимый сайт http://learn-android.ru. Конечно, вы сможете настроить любой желаемый вами сайт.
Создаем новые проект, выбираем Blank Activity, минимальная версия Android 2.2+. При создании виджета, первое дело — создать объект AppWidgetProviderInfo, в котором мы укажем xml файл, из которого будет заполняться вид самого виджета. Для этого, создадим в проекте папку res/xml и в ней создаем новый xml файл по имени widget.xml со следующим содержимым:
Теперь перейдем в файл activity_main.xml и создадим интерфейс нашего виджета, он будет состоять из кнопки Button:
Как видите, мы создали обычную кнопочку, вот она и будет нашим виджетом:
То есть, можете потом сделать вместо этой кнопочки все, что вам угодно.
Перейдем к работе с кодом в файле MainActivity.java. Он должен наследоваться от класса AppWidgetProvider, для которого существует его основной метод onUpdate (). В этом методе нам нужно обязательно определить два объекта: PendingIntent и RemoteViews. В конце их использования нужно вызвать метод updateAppWidget(). Код файла MainActivity.java:
Чтобы наш виджет успешно заработал, нужно немного магии в файле манифеста AnroidManifest.xml. Он должен выглядеть вот так:
Как вы догадались, виджет определяется в теге receiver >.
Единственное, что осталось подправить — отредактировать файл strings.xml, добавив туда используемые нами строчки:
Внимание! Android Studio может заругаться на вас при запуске программы, требую указать default activity. Выберите строчку «Не запускать activity» (Do not launch Activity):
Теперь устанавливаем приложение на эмулятор либо устройство, добавляем виджет на рабочий стол:
Как видите, все отлично работает.
Итак, в этом уроке мы создали простенький Android Widget, состоящий из кнопки Button, при нажатии на наш виджет мы создаем простой http запрос и переход по заданной URL ссылке. Можете поупражняться с какими-нибудь другими элементами, а не кнопкой, и придумать им интересный функционал. Удачи!
Источник
Gentoo on the laptop
Блог о Gentoo и около-линуксовым штукам
10 июля 2017 г.
Пишем виджет для Android (с конфигуратором и профусктками)
Структурированно рассказать о том, как работает виджет сложновато, т. к. все составляющие очень тесно взаимосвязаны и всё это вызывает друг-друга туда-сюда как только хочет. Но давайте попробуем разобраться на живом примере. Полный код того, что получилось в конце страницы и на GitHub.
Виджеты бывают с «окном» конфигуратора и без него. Это «окно» является Activity, вызываемым при первом добавлении виджета на экран. Виджеты с ним и без него несколько отличаются в поведении. Такой конфигуратор нужен в основном для того, чтобы предопределить параметры для каждого нового добавляемого виджета. Это не значит, что добавляемые виджеты не могут быть одинаковыми, т.е. они могут, но без конфигуратора они будут одинаковыми гарантированно.
Итак конфигуратор, это обычная Activity которая получает параметры добавляемого виджета используя Intent, строго говоря она получает EXTRA_APPWIDGET_ID — ID добавляемого виджета и описывает какие параметры будут отображаться на виджете. По завершении, конфигуратор возвращает это значение назад и посылает RESULT_OK используя результирующий Intent. Как сказано ранее, конфигуратор должен не только вернуть эти данные, но и обновить объект RemoteViews, используемый для настройки отображаемых в виджете вещей, т. к. при добавлении виджета с помощью конфигуратора метод onUpdate() вызван не будет. Другими словами конфигуратор должен выставить необходимый текст в TextView виджета, добавить слушателей на кнопки виджета и т.п. Определяется Activity конфигуратора в файле настройки XML виджета (см.далее).
В случае, если конфигуратора нет, при добавлении виджета будет вызван метод onUpdate() в котором как правило и описывает большая часть того, что виджет должен делать. Подробнее о методах виджета поговорим чуть позже.
Задачу поставим так: сделать виджет с конфигуратором, который будет представлять собой текст и кнопку. По нажатии на кнопку будет вызываться конфигуратор. В конфигураторе будет EditText и кнопка для применения изменений. По нажатии на неё текст в виджете будет меняться на установленный в EditText конфигуратора.
Шаг 1 . Для начала создадим проект с пустой MainActivity (File → New Project → …). Создадим внутри нашего проекта (пусть это будет в пакете java/widgets/) два java класса:
MyWidget — сам будущий виджет
MyWidgetConfig — окно конфигурации для виджета
Вернёмся к ним позже.
Шаг 2 . Создаём XML файл в res/xml/example_info.xml (‘это наш AppWidget Provider) Это то, что будет описывать нюансы самого виджета и опишет связку будущего виджета с activity конфигуратора (то окно, которое будет запускаться при добавлении виджета на экран):
Установим ширину и высоту для layout в значения “wrap_content”.
Шаг 5. Вернёмся к MyWidget.java
Виджеты являются в определённом роде BroadcastReciever которые обрабатывают определённые события. Как и BroadcastReciever, обрабатывают действия они методом onRevieve() который в дальнейшем обрабатывает данные другими методами. Тем не менее, виджет является наследником класса AppWidgetProvider (в свою очередь, наследник того самого BroadcastReciever), который всё несколько упрощает.
Рассмотрим что нам предлагает AppWidgetProvider:
onEnabled — вызывается один раз, когда виджет создаётся (добавляется на экран).
onUpdate — вызывается при обновлении виджета в заданный в XML файле интервал. Основной функционал виджета находится именно здесь. Как уже было сказано, если вам нужно вызывать этот метод чаще чем раз в 30 минут, следует добавить таймер (используя класс AlarmManager).
onDeleted — вызывается, когда виджет удалён с экрана.
onDisabled — вызывается, когда все виджеты удалены с экрана. Т.е. можно добавлять сколько угодно экземпляров этого виджета, и когда последний из добавленных будет удалён, этот метод сработает. В этом и отличие от onDeleted
onRestored — вызывается при восстановлении AppWidget из бекапа. Откликается на ACTION_WIDGET_RESTORED. В обычном случае будет сразу вызван onUpdate. Даже не знаю как этот метод можно использовать.
OnAppWidgetOptionsChanged — вызывается при изменении размеров виджета (да, если такие изменения вообще разрешены в XML настройках).
onReceive — вызывается для обработки событий другими методами.
Наследуем наш класс от AppWidgetProvider (extends AppWidgetProvider).
Жмём правой кнопкой на классе, потом Generate -> Override Methods…
Выбираем onUpdate и onDelete. Первый будет вызываться при обновлении виджета, второй — при удалении.
Источник
Находки программиста
Решения конкретных задач программирования. Java, Android, JavaScript, Flex и прочее. Настройка софта под Linux, методики разработки и просто размышления.
вторник, 12 июля 2011 г.
Пишем виджет для Android
Во-первых, чем виджет отчается от Activity?
Виджет работает в рамках «рабочего стола» нашего смартфона и от этого имеет как плюсы так и минусы. Плюсы: можно настроить обновление средствами системы. Интервал обновления при этом не может быть меньше получаса (180000 ms). Приложение всегда на виду: клиенту можно что-то сообщать не дожидаясь его действий. Минусы: ограниченный набор компонентов, доступных для использования в интерфейсе (из компоновщиков можно использовать только «FrameLayout», «LinearLayout» и «RelativeLayout». Из View: «AnalogClock», «Button», «Chromometer», «ImageButton», «ImageView», «ProgressBar» и «TextView». ). Также ограничено время, которое отводится на исполнение запросов. Ну, и, само собой, ограниченный размер «рабочей площади». Также достаточно сложно реализовать обработку событий в виджете: onclickListener на кнопку в виджете «повесить» не получится.
Как регистрировать виджет?
Так же как и всё остальное в нашем приложении, виджет описывается в AndroidManifest.xml. В тег application добавляем структуру:
receiver android:name =».CourceWidget» android:label =»@string/app_label» >
intent-filter >
action android:name =»android.appwidget.action.APPWIDGET_UPDATE»/>
intent-filter >
meta-data android:name =»android.appwidget.provider» android:resource =»@xml/widget_cource»/>
receiver >
Тут .CourceWidget — класс, описывающий виджет, widget_cource — xml файл (фактически: res/xml/widget_cource.xml), описывающий параметры виджета.
Как описать параметры виджета?
Вот, например, так:
appwidget-provider xmlns:android =»http://schemas.android.com/apk/res/android»
android:minWidth =»146dip»
android:minHeight =»72dip»
android:updatePeriodMillis =»1800000″
android:initialLayout =»@layout/cource_message»
/>
Тут android:minWidth и android:minHeight соответственно ширина и высота виджета. Рекомендуется приводить размеры по формуле: число пикселей = (число ячеек * 74) – 2. Одну ячейку на «рабочем столе» занимает одна иконка. Значение android:updatePeriodMillis , как уже говорили, определяет период обновления виджета в миллисекундах. В атрибуте android:initialLayout указываем ссылку на xml файл (res/layout/cource_message.xml) с описанием интерфейса виджета.
Как описать интерфейс виджета?
Вот, например, так:
LinearLayout xmlns:android =»http://schemas.android.com/apk/res/android»
android:layout_width =»fill_parent»
android:layout_height =»wrap_content»
android:gravity =»center»
android:background =»@drawable/widget_bg» >
LinearLayout
android:orientation =»vertical»
android:gravity =»center»
android:layout_width =»wrap_content»
android:layout_height =»fill_parent» >
TextView
android:layout_marginTop =»10sp»
android:layout_width =»fill_parent»
android:layout_height =»wrap_content»
android:textColor =»#000000″
android:gravity =»center»
android:text =»@string/buy»/>
TextView
android:id =»@+id/message_b»
android:layout_width =»fill_parent»
android:layout_height =»wrap_content»
android:textColor =»#ff0000″
android:textSize =»16sp»
android:textStyle =»bold»
android:gravity =»center»
android:text =»@string/loading»/>
TextView
android:layout_width =»fill_parent»
android:layout_height =»wrap_content»
android:textColor =»#000000″
android:gravity =»center»
android:text =»@string/sell»/>
TextView
android:id =»@+id/message_s»
android:layout_width =»fill_parent»
android:layout_height =»wrap_content»
android:textColor =»#ff0000″
android:textSize =»16sp»
android:textStyle =»bold»
android:gravity =»center»
android:text =»@string/loading»/>
LinearLayout >
LinearLayout >
Это обычный LinearLayout с четырьмя TextView, два из которых содержат строковые константы («покупка» и «продажа») а другие два заполняются данными, полученными из API. Строковые константы для поддержки «мультиязычности» выносим в файл res/values/strings.xml (значения по умолчанию — английская локализация) и res/values-ru/strings.xml (русская локализация).
Как обеспечить локализацию виджета?
Как сказано выше: вынести все константы в xml-файл вида
resources >
string name =»app_name» > Exchange rate of Bitcoin string >
string name =»app_label» > Bitcoin:USD exchange rate string >
string name =»buy» > Buy: string >
string name =»sell» > Sell: string >
string name =»loading» > Loading string >
string name =»err_connect» > Connect error string >
resources >
и обращаться к ним как: @string/loading (вернёт «Loading»). Система сама выберет нужный файл с константами в зависимости от настроек языка в системе. В java-коде обращение к локализованным строковым константам будет выглядеть так: R.string.loading .
Как описать логику, которая должна выполняться при обновлении виджета?
Вот тут мы, наконец-то, начинаем писать java-код. Для описания логики обновления данных мы должны реализовать класс, имя которого указано в самом первом xml-конфиге, приведённом в этой статье. Это CourceWidget.java:
- public class CourceWidget extends AppWidgetProvider <
- @Override
- public void onUpdate(Context context, AppWidgetManager appWidgetManager, int [] appWidgetIds) <
- context.startService( new Intent(context, UpdateService. class ));
- >
- public static class UpdateService extends Service <
- @Override
- public void onStart(Intent intent, int startId) <
- RemoteViews updateViews = buildUpdate( this );
- AppWidgetManager.getInstance( this ).updateAppWidget( new ComponentName( this , CourceWidget. class ), updateViews);
- >
- /**
- * Build a widget update
- */
- public RemoteViews buildUpdate(Context context) <
- RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.cource_message);
- String buy = «» ;
- String sell = «» ;
- // get gata from JSON
- try <
- JSONObject resp = new JSONObject(Http.Request( «https://mtgox.com/code/data/ticker.php» ));
- buy = resp.getJSONObject( «ticker» ).getString( «buy» );
- sell = resp.getJSONObject( «ticker» ).getString( «sell» );
- > catch (Exception e) <
- buy = «. » ;
- sell = «. » ;
- e.printStackTrace(System.err);
- Toast.makeText( this , R. string .err_connect, Toast.LENGTH_SHORT).show();
- >
- views.setTextViewText(R.id.message_b, «$» + buy);
- views.setTextViewText(R.id.message_s, «$» + sell);
- return views;
- >
- @Override
- public IBinder onBind(Intent intent) <
- return null ;
- >
- >
- >
Наш класс расширяет AppWidgetProvider , переопределяя его метод onUpdate . В этом методе мы ничего не делаем, кроме одного: мы запускаем сервис UpdateService , описанный тут же, как вложенный класс.
Что такое сервис и зачем он нам нужен?
В контексте виджета мы не можем обращаться к сетевым ресурсам: время обновления «рабочего стола» должно быть минимальным. Сервис — это фоновый процесс, который Android исполняет в отдельном потоке настолько долго, насколько это нам нужно. Чтобы зарегистрировать сервис в AndroidManifest.xml внутри тега application добавим:
service android:name =».CourceWidget$UpdateService»/>
Как сервис получит данные из API?
Очень просто. Отправив get-запрос, мы получаем строку, которая на самом деле представляет собой JSON-структуру. Парсинг JSON выполняем при помощи классов org.json.* которые доступны без подключения всяких сторонних библиотек. Передаём полученную из API строку в конструктор объекта JSONObject. Методами этого объекта мы получаем вложенные объекты и их поля, т.е. значения из ответа (строки 28-30). В случае любой ошибки присваиваем переменным значения по умолчанию.
Как сервис передаёт данные в виджет?
У виджета нельзя обратиться к отдельному элементу View, чтобы изменить его свойства. Можно только заменить всю иерархию компонентов целиком. Для этого создаём объект RemoteViews (строка 21) и «вкладываем» в него полученные из API данные с помощью метода setTextViewText. Потом иерархию с установленными свойствами выдаём в виджет с помощью метода updateAppWidget (строка 13).
И напоследок: как обрабатывать нажатие на виджет?
Тут мы с сожалением вспомним удобные Listener-ы из Activity. В виджетах всё существенно сложнее. Добавим в наш класс CourceWidget константу:
public static String ACTION_WIDGET_RELOAD = «reload»;
Затем в нашем сервисе создадим событие:
Intent active = new Intent(context, CourceWidget.class);
active.setAction(ACTION_WIDGET_RELOAD);
PendingIntent actionPendingIntent = PendingIntent.getBroadcast(context, 0, active, 0);
. и зарегистрируем его (привязав к какому-нибудь id элемента из нашей иерархии RemoteViews):
views.setOnClickPendingIntent(R.id.reload, actionPendingIntent);
В данном случае мы «навешиваем» событие на элемент с id «reload».
Чтобы получить и обработать событие в классе CourceWidget переопределяем метод:
@Override
public void onReceive(Context context, Intent intent) <
// Receive event
final String action = intent.getAction();
if (ACTION_WIDGET_RELOAD.equals(action)) <
context.startService( new Intent(context, UpdateService. class ));
>
super.onReceive(context, intent);
>
Тут мы заново стартуем сервис прои нажатии на виджет, тем самым вызывая «внеочередное» обновление данных.
Источник