Голощапов А. Л. - Google Android программирование для...

440
IEKCI rOOnOB nроrраммирование дnя мо6иnьных " устроиств АРХИТЕКТУРА ANDROID КОМПОНЕНТЫ ПРИЛОЖЕНИЙ ANDROID РАЗРАБОТКА ПОЛЬЗОВАТЕЛЬСКОГО ИНТЕРФЕЙСА И СЛУЖБ РАБОТА С ДАННЫМИ ГРАФИКА И АНИМАЦИЯ +Ос о

description

android programming

Transcript of Голощапов А. Л. - Google Android программирование для...

Page 1: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

AIIEKCIIi rOJIOIIIAnOB

nроrраммирование дnя мо6иnьных

"

устроиств АРХИТЕКТУРА ANDROID

КОМПОНЕНТЫ ПРИЛОЖЕНИЙ

ANDROID

РАЗРАБОТКА

ПОЛЬЗОВАТЕЛЬСКОГО

ИНТЕРФЕЙСА И СЛУЖБ

РАБОТА С ДАННЫМИ

ГРАФИКА И АНИМАЦИЯ

+Ос о

Page 2: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

Алексей Голощапов

nроrра�ирование дn11 мо6иnьных

"'

усrроиств

Санкт-Петербург «БХВ-Петербург»

2011

Page 3: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

УДК ББК

681.3.068 32.973.26-018.1 Г61

Голощапов А. Л. Г61 Google Android: nрограм мирование для мобильных устройств. -

СПб.: БХВ-Петербург, 2011.-448 с.: ил. + CD-ROM­

(Профессиональное программирование)

ISBN 978-5-9775-0562-8

Рассмотрена разработка программ для мобильных устройств под управ­лением операционной системы Google A ndroid. Приведены базовые сведе­ния о платформе Android. Описано программ ное обеспечение, необходимое для разработки А ndrоid-приложений. Рассмотрены основн ые компоненты приложений, использование базовых виджетов и виджетов-списков, созда­ние и вызов уведомлений из приложения, работа с файлами, способы хранения и обработки данн ых, создание служб в A ndroid и др. Показано применение графических ресурсов и создание анимации в приложениях с использованием возможностей Android SDK. На компакт-диске приведе­ны примеры из книги.

Для программистов

Группа подготовки издания:

УДК 681.3.068 ББК 32.973.26-018.1

Главный редактор

Зам. главного редактора

Зав. редакцией

Редактор

Компьютерная верстка

Корректор Дизайн серии

Оформление обложки

Зав. производством

Екатерина Кондукова

Игорь Шишигин

Григорий Добин

Владимир Красовский

Ольги Сергиенко

Зинаида Дмитриева

Инны Тачиной

Елены Беляевой

Николай Тверских

Лицензия ИД N2 02429 от 24.07.00. Подписано в nечать 27 10.10. Формат 70х1001/16• Печать офсетная. Уел. nеч. л. 36,12.

Доn. тираж 2000 экз. Заказ N2 546 "БХВ-Петербург'', 190005, Санкт-Петербург, Измайловекий пр., 29.

Санитарно-эnидемиологическое заключение на nродукцию N2 77.99.60.953.Д.ОО5770.05.09 от 26.05.2009 г. выдано Федеральной службой

по надзору в сфере защиты nрав nотребителей и благоnолучия человека.

Отnечатано с готовых диаnозитивов в ГУП "Тиnография "Наука"

199034, Санкт-Петербург, 9 линия, 12

ISBN 978-5-9775-0562-8 © Голощапов А. Л., 2010 ©Оформление, издательство "БХВ-Петербурr", 2010

Page 4: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

Оглавление

Введение .................................................................................................................. l На кого рассчитана эта книга .............................................................................................. 1

Краткое описание глав ...................... ................................................................................... 2

Исходные коды примеров ................................................................................................... 6

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

Глава 1. Базовые сведения о платформе Android ........................................... 7

1.1. Уровень ядра ............................................. .................................................................... 7

1.1.1. Драйвер IPC ......................................................................................................... 8

1.1.2. Управление энергопотреблением .................................................. ........... ......... 9

1.1.3. Драйверы оборудования ..................................................................................... 9

1.2. Уровень библиотек .. ......................................... . . ......................... ............... . ... . . . . . ....... 1 О 1.2.1. Системная библиотека libc ......................................................................... . ..... 1 О 1.2.2. Менеджер поверхностей ......................................... ......................................... 1 О 1.2.3. Функциональные библиотеки . . .... .............................. ...................................... 11

1.3. Среда выполнения ....................................................................................................... 12

1.3.1. Dalvik Virtual Machine .............. ........................................................................ 12

1.3.2. Core Libraries ............ ............... ... ................. ............................... . ...................... 13

1.4. Уровень каркаса приложений ..... . ....................................................................... . ...... 13

1.5. Уровень приложений ................................................................... . . ............. . ............... 14

Глава 2. Среда разработки ................................................................................ 15

2.1. Создание среды разработки ........................................................ . .............................. 15

2.1.1. Системные требования ..................................................................................... 15

2.1.2. У станов ка JDK ................ .................................................................................. 16

2.1.3. Установка Eclipse ............. ................................................................................. l7

2.1.4. Установка Android SDK ................................................................................... 17

2.1.5. У станов ка Andr·:>id Development Tools ............................................................ 18

Page 5: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

IV Оглавление

2.2. Обзор Andгoid SDK .......... : .......................................................................................... 2 1

2.2.1. Версии SDK и Android АР! Level .................................................................... 21

2.2.2. Инструменты для разработки и отладки приложений ................................... 22

2.2.3. Android Virtual Device ................ ....................................................................... 23

Глава 3. Первое приложение для Android ...................................................... 31

3.1. Создание проекта в Eclipse ......................................................................................... 31

3.2. Структура проекта .............................................................................................. ......... 35

3 .2.1. Каталог ресурсов ................. . ........................................ . ......................... ........... 36

Подкаталог res/layout/ ........................ ......................... ...................................... 37

Подкаталог res/drawaЬie/ .......................................... ........................................ 37

Подкаталог res/values/ .......... ................. . ................................ ........................... 37

3.2.2. Файл R.java ........................................................................................................ 38

3.2.3. Файл HelloAndroidActivityjava .................................... .................................... 39

3 .2.4. Файл AndroidManifest.xml .... . ........................................................................... 40

Г лава 4. Компоненты Аndrоid-приложения .................................................. 43

4.1. Деятельность .......................................... .......................... .... ....................................... 43

4.2. Службы ...................................................... .................................................................. 44

4.3. Приемники широковещательных намерений ........................................................... 44

4.4. Контент-провайдеры .. ................................................. ................................................ 45

4.5. Процессы и потоки ............................... . .............................. . . . .................................... 45

4.5.1. Жизненный цикл процессов ............................................................................. 45

4.5.2. Приоритет и статус процессов . .................................... . . ............ ...................... 46

4.6. Жизненный цикл компонентов приложения ............................................................. 48

4.6.1. Активация компонентов ................................................................................... 49

4.6.2. Завершение работы компонентов .................................................................... 49

4.7. Файл AndroidManifest.xml .......................................................................................... 49

4.7. 1. Общая структура манифеста ............................................................................ 51

<manifest> .......... ................................................................. .............................. 52

<permission> ................................ . ....................................... .............................. 52

<uses-permission> ....................... ...................................................................... 53

<permission-tree> ...................................................................... ........................ 53

<permission-group> ................................................................... ........................ 53

<instrumentation> .............................................................................................. 53

<uses-sdk> .......................................................................................................... 54

<uses-configuration> ....................................................................... .................. 54

<uses-feature> ........................... . .. ...................................................................... 54

<supports-screens> ................... ............................... . .............................. ........... 54

4. 7 .2. Структура элемента <application> .................. ............... ......................... ........ 55

<activity> ........................................................................................................... 56

<intent-jilter> ................................................. .................................................... 56

<action> .......................... .................................... . .... . . ........................................ 56

Page 6: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

Оглавление v

<category> ......................................................................................................... 57 <data> ................................. , .............................................................................. 57

<meta-data> ...................................... ....................................... .......................... 57

<activity-alias> ... .................................................................... ........................... 57

<service> ............................................................................................................ 58

<receiver> ................................................................. ......................................... 58

<provider> ......................................................................................................... 58

<grant-uri-permission> ...................................................................................... 58

<path-permission> ..................... ........................................................................ 59

<uses-library> .................................................................................................... 59

Глава 5. Графический интерфейс пользователя ........................................... 61

5.1. Деревья представлений ............................................................................................... 62 5.2. Разметка .............................................. . ........................................................................ 62

5 .2.1. Объявление в XML ........................................................................................... 64

5 .2.2. ХМL-элементы и атрибуты .......................................... ...... . ............................. 65 5.3. Инициализация представлений ........................................... . ...................................... 67

5.4. Стандартные разметки .......................................................................................... . ..... 68

5.4.1. FrameLayout ............................................. ..................................... . . .................. 68

5.4.2. LinearLayout 70

5.4.3. TaЬleLayout ...................... . ................................................................................. 74

5.4.4. RelativeLayout .................................................................................................... 78

5.5. Отладка интерфейса с помощью Hierarchy Viewer ............................................ ...... 81 5.5.1. Layout View ........................................................................................................ 82

5.5.2. Pixel Perfect View ............................................................................................... 83

Глава 6. Базовые виджеты ................................................................................ 85

6.1. Текстовые поля ............................................. . . . . ........................................................... 85 6.1.1. TextView ............................................................................................................. 86

6.1.2. EditText ............................................................................................................... 90

6.2. Добавление полос прокрутки ..................................................................................... 92

6.3. Отображение графики ................................. ............................................................... 95

6.4. Обработка событий ..................................................................................................... 97

6.5. Кнопки и флажки ........................................................................................................ 98

6.5.1. Button ................................................................................................................. 99 6.5.2. RadioButton и RadioGroup .............................................................................. 106 6.5.3. CheckBox .......................................................................................................... 109

6.5.4. ToggleButton 112 6.5.5. lmageButton .......................................................... ............................................ 115

6.6. Закладки ........................ . ......................................... ......................... .................... ...... 117

6.7. Индикаторы и слайдеры ................................................................ ........................... 120

6.7.1. ProgressBar ...................................................................... . ..... .......................... 121

6.7.2. SeekBar ..................................... . .............................................. . . ....................... 125

6.7.3. RatingBar ............................................... . . .................................................... . .... 129

Page 7: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

Vl Оглавление

6.8. Компоненты отображения времени ......................................................................... 133 6.8.1. AnalogClock и Digita/Clock ............................................................................. 134 6.8.2. Chronometer ..................................................................................................... 135

Глава 7. Виджеты-списки и привязка данных ............................................ 139

7.1. Адаптеры данных ...................................................................................................... 139 7.2. Текстовые поля с автозаполнением ......................................................................... 140

7.2.1. AutoCompleteTextView ..................................................................................... 140 7.2.2. MultiAutoCompleteTextView ............................................................................ 143

7.3. Отображение данных в списках ............................................................................... 146 7.3.1. ListView ............................................................................................................ 147

7.3.2. Spinner .............................................................................................................. 149 7.3.3. GridView .................................... ....................................................................... 153

7.4. Отображение графики в списках ............................................................................. 157 7.4.1. Отображение графики в GridView ........... , ..................................................... 157

7.4.2. Gallery .............................................................................................................. 161 7.4.3. SlidingDrawer ................................................................................................... 164

7.5. Создание списка с собственной разметкой ............................................................. 170

Глава 8. Уведомления ...................................................................................... 175

8.1. Всплывающие уведомления ..................................................................................... 17 5 8.2. Создание собственных всплывающих уведомлений .............................................. 179

8.3. Уведомления в строке состояния ........................................ . .................................... 182

8.4. Создание собственных уведомлений для строки состояния ......................... . ....... 187

Глава 9. Диалоговые окна ............................................................................... 191

9.1. Создание диалоговых окон ...................................................................................... 192

9.2. AlertDialog ................................................................................................................. 193 9.2.1. AlertDialog с кнопками ................................................................................... 193 9.2.2. A/ertDia/og СО СПИСКОМ ................................................................................... 197 9.2.3. AlertDialog с радиокнопками ......................................................................... 200 9.2.4. AlertDialog с флажками .................................................................................. 203

9.3. ProgressDialog ........................................................................................................... 206 9.4. DatePickerDialog ........................................................................................... . . ......... . 211

9.5. TimePickerDialog ....................................................................................................... 216 9.6. Создание собственных диалогов .................................................... . ........................ 219

Глава 10. Меню .................................................................................................. 225

1 0.1. Меню выбора опций ............................................................................................... 226 1 0.1.1. Меню со значками ...................................................................................... 230 10.1.2. Расширенное меню ..................................................................................... 233

10.2. Контекстное меню ................................................................................................... 237

Page 8: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

Оглавление V/1

1 0.3. Подменю .................................................................................................................. 240 1 0.4. Добавление флажков и переключателей в меню .................................................. 244

Глава 11. Управление деятельноетими ........................................................ 249

11.1. Жизненный цикл деятельности .............................................................................. 249 11.1.1. Сохранение состояния деятельности ........................................................ 253 11.1.2. Стек деятельностей ........................ ............................................................. 254

11.2. Намерения ......... ................................................................................. ...................... 254 11.3. Группы намерений ................................................. ......... ........................................ 257 11.4. Запуск деятельностей и обмен данными между деятельностями ....................... 257 11.5. Фильтры намерений и запуск заданий .................................................................. 271

Г лава 12. Службы .............................................................................................. 275

12.1. Жизненный цикл служб .......................................................................................... 275 12.2. Создание службы ................................. ......................................... . ......................... 277

Глава 13. Приемники широковещательных намерений ........................... 285

13.1. Жизненный цикл Приемников широковещательных намерений ............... ......... 286 13.2. Приемники системных событий ................. . .......................................................... 287 13.3. Использование широковещательных намерений ...... ........................... ...... . ......... 288

13.3.1. Передача событий через намерения . ................... ................... . .................. 288 13.3.2. Проелушивание событий Приемниками широковещательных намерений ................................................................................................................ 289 13.3.3. Пример приложения-приемника намерений .................................... ........ 290 13.3.4. Пример приложения-передатчика намерений ..................... . . . .................. 292

Глава 14. Работа с файлами и сохранение пользовательских

настроек .............................................................................................................. 295

14.1. Чтение и запись файлов .......................................................................................... 295 14.2. Предпочтения .......................................................................................................... 301

14.2.1. Использование предпочтений .................................................................... 302 14.2.2. CheckBoxPreference ..................................................................................... 303 14.2.3. EditTextPreference ................... . .. . ................................................................ 310 14.2.4. ListPreference .................................. . ............................................................ 312 14.2.5. RingtonePreference .......... . ........................................................................... 315 14.2.6. PreferenceCategory ...................................................................................... 316 14.2. 7. PreferenceScreen ..................................................................... ..................... 317

Г лава 15. База данных SQLite и контент-провайдеры .............................. 323

15.1. База данных SQLite ................................................................................................. 323 15.1.1. Создание базы данных: класс SQLiteOpenHelper ..................................... 323 15.1.2. Управление базой данных: класс SQLiteDatabase .................... ............... 325

Page 9: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

V/11 Оглавление

15.2. Контент-nровайдеры ............................................................................................... 326 15.2.1. Модель данных ........................................................................................... 327 15.2.2. URI ............................................................................................................... 327

15.3. Создание контент-nровайдера ............................................................................... 328 15.3.1. Расширение класса ContentProvider .......................................................... 329 15.3.2. Декларирование контент-nровайдера в файле манифеста ...................... 331

15 .4. Заnросы к конtент-nровайдеру .............................................................................. 331 15.4.1. Чтение возвращаемых значений ................................................................ 332 15.4.2. Позиционирование курсора ....................................................................... 333 15.4.3. Добавление заnисей .................................................................................... 334 15.4.4. Изменение заnиси ....................................................................................... 334

15.4.5. Удаление заnисей ........................................................................................ 334 15.5. Практическое nриложение для работы с базой данных ....................................... 335

Глава 16. Ресурсы, активы и локализация приложений .......................... 349

1 6.1. Достуnные тиnы ресурсов ........ ............................................................. .... ............. 349 16.2. Создание ресурсов .............. . ................................................. ................................ .. 350 16.3. Ссылки на ресурсы ... ........... . ................... ................................................................ 351 16.4. Исnользование ресурсов в коде программы ......................................................... 352

16.4.1. Загрузка простых тиnов из ресурсов ......................................................... 353

16.4.2. Загрузка файлов nроизвольнаго типа ....................................................... . 358 16.4.3. Создание меню в XML ................ ............................................................... 360 16.4.4. Загрузка ХМL-документов ......................................................................... 364

16.5. Стили и темы .................. ..................................................................... .................... 368

16.5.1. Стили .............................................................. .............................................. 368

16.5.2. Темы ............................................................................................................. 369

16.5.3. Оnределение собственных стилей и тем ................................................... 370

16.6. Активы ..................................................................................................................... 373

16.7. Локализация приложений ................ . ...................................................................... 377

16.7.1. Ресурсы, заданные no умолчанию ............................................................. 377

16.7 .2. Создание локализованных ресурсов ........................................... . ............. 378

Глава 17. Графика ............................................................................................. 381

17.1. Объект DrawaЬ!e ..................................................................................................... 381

17.2. Создание объектов DrawaЬ!e в коде nрограммы .................................................. 383

17.2.1. Класс TransitionDrawaЬ!e ................... ........................................................ 384

17.2.2. Класс ShapeDrawaЬ!e .................................................................................. 386

17.3. Рисование на канве ...... . .......................................... ...... ............................. ............. 393

Глава 18. Создание анимации ......................................................................... 401

18.1. Анимация nреобразований ..................................................................................... 401

18.1.1. Создание анимации в ХМL-файле ............................................................. 402

Общие атрибуты ......................................................................................... 403

Элемент <set> ................... . ...... ................................................................... 404

Page 10: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

Оглавление IX

Элемент <alpha> .......... . . ......................... . . . . .... ......... . . .......... . ..... ....... ......... 404

Элемент <scale> ......................................... . . ...... ..... . .................................. 404

Элемент <translate> ... . ............................... ........ ............... . .... . . . . ........ . ... . . . . 405

Элемент <rotate> ........................................................ ...... . . . . . . ......... ........... 405

18.1.2. Анимация графических nримитивов ............ ....... . . .......... ........ . . ............ . . .. 405

18.1.3. Анимация графических файлов ............................ . .. . . . .... . ...... ............. . ...... 413

18.1.4. Анимация группы представлений ................................... . .... . .................... 417

18.2. Кадровая анимация ..................... .................................................. ........... . . . . . . . ........ 421

18.2.1. Создание кадровой анимации в XML ..................... . . . . ... . . . . ......... . . ............ 422

18.2.2. Создание анимации в коде nрограммы ........................... . .... . .. . . . ........... . . . . 425

Приложение. Описание комиакт-диска и установка примеров .............. 429

Описание комnакт-диска ....... . . . . ...... . ............................................. . .. . . . .................. ..... ..... 429

Установка примеров ........................................................................................................ 429

Предметный указатель .................................................................................... 433

Page 11: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

Введение

На момент написания этой книги платформа Goog\e Android уже представля­ет собой заметное явление в области программнога обеспечения для мобиль­ных устройств. Новой платформой заинтересовались ведущие мировые про­изводители мобильной электроники и сотовые операторы, а некоторые из них уже выпустили на рынок устройства, работающие под управлением Android.

В чем же заключается уникальность платформы Android? Основная идея Goog\e состоит в том, что компания предлагает в открытый доступ исходные коды своей операционной системы, предлагает набор удобных инструментов для разработки и хорошо документированное SDK, что должно со временем привести к появлению большого количества программнаго обеспечения для этой платформы. В дальнейшем у Android есть все шансы стать самым успешным проектом для мобильных телефонов.

Аналитики и эксперты ИТ -рынка прогнозируют для платформы Google Aпdroid хорошие коммерческие перспективы . Android захватывает рынок мо­бильных телефонов, постепенно вытесняя с него общепризнанных лидеров. Google Android устанавливается не только на смартфоны, данная платформа подходит и для нетбуков.

Еще одним шагом в развитии Goog\e Android стало открытие в октябре 2008 года онлайн-магазина приложений - Android Market, в котором можно приобрести программы и другой софт для устройств на базе новой платфор­мы. Кроме того, теперь для разработчиков программнаго обеспечения появи­лась возможность брать плату за свои приложения в Android Market, что де­лает разработку приложений под эту платформу еще более привлекательной.

На кого рассчитана эта книга Поскольку эта книга о программировании приложений для мобильных уст­ройств на платформе Android, необходимое условие для работы с книгой -

Page 12: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

2 Введение

наличие базовых навыков программ ирования на языке Java, который нужен для написания приложений с использованием Android SDK.

Для тех ч итателей, которые не работали до этого момента на Java, но исполь­зовал и другие объектно-ориентированные языки (типа C#.NET), переход на платформу Android также не вызовет больших затруднений . Сила Android и особенности программ ирования приложений для этой платформы заключены в АРI-библиотеках, которые предоставляет Android SDK. Таким образом, от­сутствие опыта программирования в Java не будет большим недостатком при работе с книгой и освоении платформы Androi ·d. Необходимые навыки для программирования на Java можно приобретать постепенно, параллельно с изучением платформы Android.

В целом эта книга предназначена для двух разных групп программистов:

D традиционных разработчиков программ ного обеспечения, которые имеют опыт работы на языках Java или C#.NET и желают перейти на разработку приложений для мобильных телефонов на базе ОС Android;

D разработчиков, уже имеющих опыт программирования мобильных уст­ройств на iPhone, Windows MoЬi le, SymЬian и JavaME, которые хотят про­граммировать на платформе Android .

Желательно, чтобы эта книга была полезной и цен ной любому человеку, за­интересованному в разработке приложений для Android. Люди, увлеченные программ ированием, найдут здесь основу для своих будущих приложений . Прикладные программисты изучат основные функциональные возможности платформы, которые смогут использовать в своих профессиональных разра­ботках. Короче говоря, эта книга содержит м ного информации, которая при­годится вам независимо от вашего опыта и профессиональных интересов .

Краткое описа ние глав Книга состоит из 1 8 глав и одного приложения . Далее приводится краткое описание каждой из глав .

D Глава 1. Базовые сведения о платформе Android

Описывается архитектура и программный интерфейс операционной сис­темы Android . Приводится информация о составе и функционал ьных воз­можностях библиотек Android, базовых классах и интерфейсах, входящих в состав библиотек и пакетов Android SDK. Дается понятие программного стека Android, принципы работы Dalvik V irtual Mach ine.

D Глава 2. Среда разработки

Глава посвящена установке на компьютер необходимого программ ного обеспечения, требуемого для разработки приложений под Android : Java

Page 13: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

Введение 3

Development Kit, Ecl ipse, Android SDK, Android Development Tools, и на­стройке среды разработки для наnисания nрограмм для Android.

Оnисывается инструментарий, входящий в состав Aпdroid SDK, - раз­личные инструменты для отладки, комnоновки, уnаковки и инсталляции ваших nриложений на эмулятор и мобильное устройство. Приводятся ин­струкции no конфигурации и работе с Android Virtua\ Device - эмулято­ром мобильного устройства.

О Глава 3. Первое приложение для Aпdroid

Рассматривается создание nервой nрограммы nод Android, заnуск и работа nрограммы в эмуляторе мобильного устройства. Будет детально изучена структура nроекта, содержимое файлов nроекта и работа с ними в интегрированной среде разработки Ecl ipse.

О Глава 4. Компоненты Апdrоid-приложения

Приводятся базовые понятия об основных компонентах Аndrоid­приложений - деятельности, службах, Приемниках широковещательных намерений и контент-nровайдерах. Рассматривается внутренняя архитек­тура файла манифеста Аndrоid-nриложения, который предоставляет ос­новную информацию о компонентах nриложения и разрешениях системе.

О Глава 5. Графический интерфейс пользователя

Эта глава дает базовые понятия о графическом интерфейсе Android и зна­комит с nринциnами экранной иерархии элементов графического интер­фейса - Представлениях и гpynnax nредставлений . Рассматриваются во­просы комnоновки экранных элементов и создания разметки для окон nриложений, которые читатель будет разрабатывать и использовать в сле­дуК)щих главах для создания профессионального пользовательского ин­терфейса в своих приложениях.

О Глава 6. Базовые виджеты

Глава знакомит читателя с различными элементами графического интер­фейса пользователя (виджетами). Виджеты в Android - это кноnки, флажки, радиокнопки, списки, сетки, элементы управления датой и време­нем и многие другие элементы . Приводятся примеры по созданиИ) и использованию виджетов в Приложениях для Android .

О Глава 7. Виджеты-списки и привязка данных

Рассматриваются виджеты-сnиски, отображающие текстовую и графиче­скую информацию, которая может быть связана с внутренним или внеш­ним источником данных, и адаnтеры данных - компоненты-посредники между набором данных и элементом nользовательского интерфейса для их отображения .

Page 14: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

4 Введение

D Глава 8. Уведомления

Рассматривается создание и вызов уведомлений из приложения . При рабо­те пользователя с приложеннем могут возникать различные ситуации, о которых необходимо уведомить пользователя . Некоторые ситуации тре­буют, чтобы пользователь обязательно среагировал на них, другие не тре­буют реакции и выполняют чисто информативную функцию.

Читатель познакомится с созданием механизма оповещения пользователя приложения. Будут рассмотрены различные типы уведомлений - всплы­вающие уведомления и уведомления в строке состояния.

D Глава 9. Диалоговые окна

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

D Глава 1 О . Меню

Android SDK предлагает обширную поддержку меню в приложениях. Чи­татель научится работать с несколькими типами меню, поддерживаемых Android, включая контекстные меню, меню с иконками, всплывающие ме­ню и альтернативные меню, и встраивать меню в свои приложения.

D Глава 11 . Управление деятельностями

Рассматривается управление и взаимодействие деятельностей - окон приложения. Дается представление о жизненном цикле деятельностей в Аndrоid-приложении и стеке деятельностей . Обсуждаются способы обме­на данными между деятельностями .

Также рассматривается одна из интересных функциональностей And­roid - намерения . Смысл использования намерени й - обеспечить дина­мическое связывание между ком понентами приложений. Вместо статиче­ского соединения программ нога кода в Android используется система об­мена сообщениями, которая выполняет позднее связывание.

D Глава 12. Слу�бы

Рассматривается создание служб в Android. Служба - это компонент приложения, который позволяет работать ему в фоновом режиме без ис­пользования интерфейса пользователя . Читатель научится создавать служ­бы и управлять ими .

D Глава 13. Приемники широковещательных намерений

Эта глава научит созданию приемников широковещательных намерений (Broadcast Receiver). Приемник широковещательных намерений использу-

Page 15: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

Введение 5

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

О Глава 14. Работа с файлами и сохранение пользовательских настроек

Рассматривается механизм предпочтений - сохранение пользовательских настроек приложения, а также чтение и запись файлов и управление фай­ловым вводом-выводом из приложения.

О Глава 15. База данных SQLite и контент-провайдеры

Сохранение и загрузка данных - необходимое требование для большин­ства приложений . В данной главе будут рассмотрены способы хранения и обработки дан ных, доступные в Android, - файлы и база данных SQLite. Контент-провайдеры служат удобным механизмом для сохранения и об­мена данными между приложениями .

В этой главе читатель научится создавать базы данных и работать с ними из приложения, а также создавать контент-провайдеры, добавлять, удалять и модифицировать данные любых других приложений (если они предос­тавляют соответствующие разрешения) из своего приложения .

О Глава 16. Ресурсы, активы и локализация приложений

Рассматривается работа с файлами ресурсов и активами и использование их в своих приложениях. Ресурсы и активы - это неотъемлемая часть любого Аndrоid-приложения. Читатель научится загружать в разрабаты­ваемую программу изображения, строки, разметки, стили, темы, ХМL­документы и т. д.

Аndrоid-приложение может работать на м ногих устройствах во многих ре­гионах. Ваше приложение должно соответствовать настройкам и языкам того региона, где оно будет использоваться .

О Глава 17. Графика

Обсуждаются различные варианты использования графических ресурсов в Аndrоid-приложении . Рассматриваются вопросы рисования графики на канве представления, загрузка графики из ресурсов или ХМL-документов для создания визуально привлекательных интерфейсов. Примеры прило­жений в этой главе показывают использование нашей собственной графи­ки и анимации в Приложениях с применением АРI-библиотек для работы с графикой.

О Глава 18. Создание анимации

Рассматривается создание анимации в приложениях для разработки визу­ально привлекательных приложени й для Android с использованием воз­можностей Android SDK, который предоставляет двумерную графическую библиотеку анимации на канве и представлениях.

Page 16: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

6 Введение

Исходные коды при меров Н а прилагаемом диске находятся все исходные коды примеров, приведеиных в книге . У станов ка примеров описана в приложении.

Все примеры используют функциональность Android SDK версии 2 .0 или ниже и скомпилированы в среде Ecl ipse. Установка и настройка среды разра­ботки подробно описана в главе 2. Книга содержит полные исходные коды всех программ , однако некоторые листинги для экономии места и во избежание иенужиого дублирования ин­формации содержат только изменения программнаго кода относительно пре­дыдущих л истингов . Такое сокращение позволяет не только экономить ме­сто, но и улучшить понимание программ наго кода, делая акцент только на новой функционал ьности.

На диске также находятся файлы ресурсов - графика, иконки, шрифты, ис­пользуемые в примерах приложений, приведеиных в книге .

Благодарности В первую очередь хочу поблагодарить своих родных и близких за оказанную моральную поддержку в процессе написания этой книги. Отдельная благо­дарность заместителю главного редактора Игорю Владимировичу Шишигину и всем сотрудникам издательства "БХВ-Петербург", которые помогали мне в создании этой книги.

Page 17: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

ГЛ А В А 1

Базовые сведения о платформе Android

Перед тем как приступ ить к разработке приложений для Android, хотелось бы вкратце познакомить читателя с архитектурой системы и основными особен­ностями этой платформы.

Система Android - это программный стек для мобильных устройств, кото­рый включает операционную систему, программное обеспечение промежу­точного слоя (middleware), а также основные пользовательские приложения (е-mаi l -кл иент, календарь, карты, браузер, контакты и др.) .

Архитектуру Aпdroid принято делить на четыре уровня:

D уровень ядра;

D уровень библиотек и среды выполнения;

D уровень каркаса приложений ;

D уровень приложений .

На рис. 1 . 1 показаны основные компоненты операционной системы Aпdroid и их взаимодействие между собой.

1.1 . Уровен ь ядра Ядро является слоем абстракции между оборудованием и остал ьной частью программнаго стека. На этом уровне располагаются основные службы типа управления процессами, распределения памяти и управления файловой сис­темой.

Ядро Android основано на ядре Linux версии 2 .6, но сама система Android не является Linuх-системой в чистом виде, имеет некоторые отличия и содержит дополнительные расширения ядра, специфичные для Android, - свои меха­низмы распределения памяти, взаимодействие между процессами и др.

Page 18: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

в

1 Главный экран 1 Приложения

Телефон 1 1 Контакты 1 1 Брауэер l 1 ' 1 ,П . . . '-· ------' Приложения �

Каркас приложений

Библиотеки Среда выполнения

Библиотеки ядра

Глава 1

1 Виртуальная машина Dalvik 1

Драйвер Менеджер межпроцесснаго управления взаимодействия энергопотреблением

Рис. 1.1. Архитектура системы Android

Основные компоненты уровня ядра:

D драйвер межпроцесснога взаимодействия ( IPC Driver);

D драйвер управления питанием (Android Power Management) ;

D набор драйверов для оборудования, входящего в состав мобильного уст­ройства.

Рассмотрим теперь кратко основные компоненты ядра Android .

1.1.1. Драйвер IPC

Приложенил и службы могут работать в защищенных отдельных процессах, которые должны общаться между собой и иметь доступ к общим данным . Платформа Android обеспечивает механизм IPC (Inter-process Communi­cation), который является основным механизмом взаимодействия между про­цессами .

Page 19: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

Базовые сведения о платформе Android

Драйвер IPC обесnечивает следующую функционал ьность:

О взаимодействие nроцессов;

О создание и обработку nулов nотоков в nроцессах;

О nодсчет и отображение ссылок на объекты в других nроцессах;

О синхронные заnросы между nроцессами .

1.1.2. Управление энергопотреблением

9

Система уnравления энергоnотреблением (Android Power Management) разра­ботана на основе стандартного драйвера уnравления nитанием Linux, но оn­тимизирована для мобильных устройств с учетом их сnецифических особен­ностей .

Основная функция системы уnравления энергоnотреблением - экономное исnользование батареи мобильного устройства. Драйвер nереводит системы в "сnящий режим" с м инимальным nотреблением мощности nроцессором, если nриложения и службы не исnользуются.

1.1.3. Драйверы оборудования

Программный стек An.droid разработан с учетом необходимой гибкости, включая работу со многими доnолнительными комnонентами, имеющимися в мобильных устройствах. Эти комnоненты в значительной стеnени nолагают­ся на достуnность оnределенных аnnаратных средств на данном устройстве. Они nредоставляют доnолнительную функциональность для мобильных уст­ройстн·(сенсорный экран, камера, GPS, акселерометр и т. д.) .

Встроенные драйверы включают в себя nоддержку работы с оборудованием мобильного устройства. Набор драйверов может быть различным в зависимо­сти от nроизводителя и модели устройства. Поскольку новое всnомогатель­ное оборудование для мобильных устройств nостоянно nоявляется на рынке, драйверы для них должны быть наnисаны на уровне ядра Linux для обесnе­чения nоддержки оборудования, так же как и для настольных Linux-cиcтeм.

Преимущества исnользования ядра Linux как основы Android в том, что ядро системы nозволяет верхним уровням nрограммнога стека оставаться неиз­менными, несмотря на различия в исnользуемом оборудовании . Конечно, хо­рошая nрактика nрограммирования требует, чтобы nользовательские nрило­жения корректно завершал и свою работу в случае вызова ресурса, являюще­гося недостуnным, наnример камеры, не nрисутствующей в данной модели смартфона.

Page 20: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

10 Глава 1

1.2. Уровен ь библиотек Следующий уровень над ядром Linux является набором библиотек С/С++ ти­па OpenGL, WebKit, FreeType, SSL, библиотеки поддержки l ibc, базы данных SQLite и мультимедиабиблиотек (Media Framework). Системная библиотека базируется на Berkeley Software Distribution (BSD) и разработана длЯ' мобиль­ных устройств на основе Linux.

Следующий уровень над ядром Linux включает набор библиотек С/С++, ис­пользуемых различными ком понентами ОС. Для разработчиков доступ к функциям этих библиотек реализован через использование Appl ication Framework - каркаса приложений . Библиотеки этого уровня по своему функциональному назначению можно разделить на следующие групп ы :

О системная библ иотека С ;

О менеджер поверхностей;

О функциональные библиотеки С/С++.

1 .2 .1. Системная библиотека l ibc

Компания Google разработала собственную С-библиотеку ( l ibc) - Bioпic. Это было необходимо по следующим причинам :

О библ иотека будет загружаться в каждый процесс и, следовательно, должна иметь маленький размер. Библиотека Bionic имеет размер около 200 Кбайт, что в два раза меньше размера gl ibc;

О ограниченная мощность центрального процессара мобильного устройства. Это означает, что библиотека должна быть оптим изирована для макси­мального быстродействия.

Библиотека Bionic имеет встроенную поддержку важных для Android систем­ных служб и регистрацию системных событий . Библиотека Bion ic не поддер­живает определенные функциональности, например исключения С++, и несо­вместима с GNU l ibc и стандартом POSIX.

1.2.2 . Менеджер поверхностей

Система Android использует ком позитны й менеджер поверхностей, похожий на Compiz (композитный менеджер окон для Х Window System, использую­щий для ускорения 3 D-графику OpenGL) . Вместо того чтобы рисовать непо­средственно в буфер экрана, команды рисунка входят за кадром в битовые массивы, которые потом объединяются с другим и битовыми массивами, что­бы сформировать изображение, которое видит пользователь. Это позволяет системе создавать все виды интересных эффектов, например прозрачные ок­на и причудливые переходы .

Page 21: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

Базовые сведения о платформе A[ldroid 1 1

Менеджер поверхностей обрабатывает весь рендеринг поверхности на фрей­мовый буфер. Менеджер может объединить 2D- и 3D-поверхности и поверх­ности от нескольких приложений . Поверхности передают как буферы компо­новкой IРС-запросов. Менеджер поверхностей использует двойную буфери­зацию, используя транспонирования страницы . Системные интеграторы могут подключать аппаратное 2D-ускорение, используя плагины Khronos. Обработка графической информации менеджером поверхностей представле­на на рис. 1 .2 .

Surface

Surface

Surface

Surface Fl inger

Fгame Buffer

Рис. 1 .2. Обработка графической информации менеджером поверхностей

1 .2 .3 . Функционал ьные библиотеки

Android включает ряд библиотек С/С++, используемых различными компо­нентами системы. Далее приводятся основные функциональные библиотеки системы .

D Мультимедиа (Media Framework) . Эти библиотеки ответственны за реги­страцию и воспроизведение аудио- и видеоформатов. Основаны на PacketVideo OpenCORE и предназначены для поддержки популярных аудио- и видеоформатов (MPEG4, Н.264, МР3 и др.) .

D SQLite - процессор баз данных, доступный всем приложениям. SQLite не использует парадигму клиент-сервер, т. е . движок SQLite не является от­дельно работающим процессом, с которым взаимодействует программа, а предоставляет библиотеку, с которой программа компонуется, и движок становится составной частью программы . Таким образом, в качестве про­токола обмена используются вызовы функций (API) библиотеки SQLite. Такой подход уменьшает накладные расходы, время отклика и упрощает разработку приложений для работы с данными . SQLite хранит всю базу данных (включая определения, таблицы, индексы и данные) в единствен­ном стандартном файле на том компьютере, на котором исполняется про­грамма.

D OpenGL ES - движок для работы с 3 D-графикой, основанный на АРI­версии OpenGL ES 1 .0 . OpenGL ES - это упрощенная версия специфика­ции OpenGL, позволяющая мобильным устройствам работать с тяжело­весными в графическом отношении приложениями. Библиотека использу-

Page 22: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

12 Глава 1

ет аппаратный 3 D-акселератор (если он доступен на этом устройстве) или встроен ное высоко оптимизированное трехмерное программное обеспече­ние для работы с растровой графикой .

D FreeType - библиотека шрифтов, предназначенная для работы с растро­выми и векторными шрифтами .

D WebKit - библиотека, предназначенная для функцион ирования встроен­ного в Android WеЬ-браузера. WebКit поддерживает CSS, JavaScript, DOM, Ajax.

D SGL - движок для работы с 20-графикой. Android также поддерживает собственную графическую 20-библиотеку Skia, которая написана на С и С++ (Skia также формирует ядро популярного браузера Google Chrome).

D SSL - библиотека предназначена для работы с сокетами, основанная на протоколе SSL: SSLvЗ .O или TLSv 1 .2 .

1 .3 . Среда вы пол нения Среда выполнения обеспечивает библиотеки ядра Dalvik V irtual Mach ine (виртуальная машина Dalvik), которые предоставляют требуемую функцио­нальность для Jаvа-приложений .

1 .3 . 1 . Da lvik Virtual Mach ine

Прикладное программное обеспечение, запускаемое на мобильном устройст­ве, испол няет виртуальная машина Dalvik, которая хоть и являеtся аналогом виртуальной машины Java, существенно от нее отличается . Dalvik относится к классу регистровых машин (регистры процессара используются как пер­вичные модули хранения данных), идеально подходящих для работы на про­цессарах RISС-архитектуры, к которым относятся и процессары ARM, при­меняемые в мобильных устройствах, тогда как стандартная виртуальная машина Java компании Sun M icrosystems - стековая . В результате использо­вания регистровой виртуальной машины Google надеется на 30 процентов уменьшить количество команд по сравнению со стековыми машинами .

Созданные с помощью стандартного Jаvа-компилятора с lаss-файлы преобра­зуются в байт-код Dalvik (* .dex) транслятором dx, входящим в состав SDK. Изнутри работающий Android выглядит как набор виртуальных машин Dalvik, в каждой из которых исполняется прикладная задача.

Виртуальная маш и на Dalvik, на которой построена вся операционная система Google Android, дает разработчикам приложений удобный механизм для на-

Page 23: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

Базовые сведения о платформе Android 13

писания приложений, которы м не принципиален объем используемой памяти и мощность процессора.

1 .3 .2 . Core Libraries

Включает набор основных библиотек, которые предоставляют функциональ­ность для Java. Библиотеки ядра обеспечивают слой API и являются основной платформой разработки Jаvа-приложений для Android .

1 .4. Уровен ь каркаса п риложений Уровень каркаса приложений находится н а вершине системных библиотек, функциональных библиотек и Dalvik VM. На этом уровне находятся основ­ные службы Android для управления жизненным циклом приложений, паке­тами, ресурсами и т. д.

Программист имеет полный доступ к тем же АР\, которые используются ос­новными приложениями . Архитектура этих приложений разработана с целью упрощения м ногократного использования ком понентов . Любое разрабаты­ваемое приложение может использовать возможности базовых приложений и, соответственно, любое другое стороннее приложение может использовать возможности вашего приложения (с учетом установленных разрешений). Этот же самый механизм позволяет многократно использовать уже разрабо­танные ком поненты.

Службы Android - это службы, которые являются основными для всех при­ложений, работающих на устройстве. К ним относятся :

D менеджер деятельностей (Activity Manager) - управляет жизненным цик­лом приложений и предоставляет систему навигации по истории работы с деятельностями (стеку деятельностей);

D менеджер пакетов (Package Manager) - управляет установкой и разверты­ванием пакетов прикладных программ, которые находятся на устройстве;

D менеджер окон (Window Manager) - сохраняет окна приложения . Если разработчик предусмотрел вывод экрана, а затем переключение на другой экран, первый будет сохранен операционной системой и поставлен в ре­жим ожидания. Это, в свою очередь, позволяет с помощью клавиши <Back> мобильного устройства просматривать уже использовавшиеся эк­раны подобно тому, как это делается в WеЬ-браузере;

D менеджер ресурсов (Resource Manager) - предназначен для доступа к строковым, графическим и другим типам ресурсов;

D контент-провайдеры (Content Providers) - службь!, которые позволяют nриложениям получать доступ к данным других приложений, а также пре­доставлять сторонним приложениям доступ к своим данным;

Page 24: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

14 Глава 1

О система представлений (View System) - система с расширяемой функ­циональностью, которая служит для создания внешнего вида приложений, вкл ючающего такие компоненты, как списки, таблицы, поля ввода, кноп­ки, встроенный WеЬ-браузер и м ногое другое;

О телефонный менеджер - обеспечивает слой API, контролирующий ос­новную телефонную информацию, такую как сетевой тип и статус под­ключения, а также предоставляет различные утил иты для управления те­лефонными номерами;

О менеджер местоположения - навигационные службы, которые позволяют Приложениям получать периодические обновления географического ме­стоположения устройства или запускать определенное приложение;

О менеджер уведомлений - позволяет любому приложению отображать пользовательские уведомления в строке состояния .

1 .5. Уровен ь приложений Мобильное устройство Android поставляется с набором основных приложе­ний, вкл ючая почтового клиента, программу для работы с SMS, календарь, навигационные карты, браузер, контакты и др.

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

При разработке приложений программисты и меют полный доступ ко всей функциональности операционной системы. Архитектура приложений по­строена так, чтобы было легко использовать основные ком поненты, предос­тавляемые системой. Также есть возможность создавать свои ком поненты и предоставлять их в открытое использование.

Page 25: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

ГЛ А В А 2

Среда разработки

Чтобы писать приложения для Android, необходимо установить среду разра­ботки . В этой главе мы установим Java Development Kit, интегрированную среду разработки Ecl ipse, Android SDK и Android Development Too\s, а также сканфигурируем Ecl ipse для разработки приложений под Android .

2 .1 . Создан ие среды разработки Google предлагает для свободного скачивания набор инструментов для раз­работки (Software Development Кit), который Предназначен для х86-машин под операционными системами Windows ХР , Мае OS и Linux.

2. 1 . 1 . Систем ные требования

Поскольку среда разработки не зависит от операционной системы и Аndrоid­приложения в настольных операционных системах запускаются в эмуляторе мобильного устройства, необходимые инструменты для .разработки можно установить на любую из следующих систем :

D Windows ХР (х86) или Vista (32 или 64 бита);

D Мае OS Х 1 0 .4 .8 или новее;

D Linux (тестирован только на Linux Ubuntu Hardy Heron) .

В качестве среды разработки рекомендуется Ecl ipse 3 .5 (Gal i leo) или Ecl ipse 3 .4 (Ganymede) следующих версий :

D Ecl ipse IDE for Java ЕЕ Developers ;

D Ecl ipse IDE for Java Developers;

D Ecl ipse for RCP/Piug- in Developers.

Page 26: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

1 6 Глава 2

ПРИМЕЧА ННЕ

В принципе, можно использовать и другую среду разработки , например NetBeans I D E , но возможн ы некоторые неудобства , о которых будет рассказано далее.

Для начала работы необходимо загрузить и установить следующее про­грамммое обеспечение:

Ll J DK 5 или 6; Ll Ecl ipse IDE;

Ll Android SDK 2.0 ;

Ll Android Development Tools (ADT) .

Поскольку версии SDK, Java и Ecl i pse доступны для Windows, Мае OS и Linux, можно создавать Аndrоid-приложения на любой операционной систе­ме, которая вам нравится . SDK включает эмулятор для всех трех операцион­ных систем, и , поскольку Аndrоid-приложения выполняются на виртуальной машине, нет никакого преимущества для разработки приложений в любой из

ЭТИХ ОС.

ПРИМЕЧАННЕ

Все примеры и скриншоты в этой книге даются для ОС Microsoft Windows ХР

2. 1 .2 . Установка JDK

Дnя разработки программ н а языке Java нам потребуется специальное Про­грамммое обеспечение. Самые новые версии системного программнога обес­печения, необходимого для поддержки, можно загрузить с сайта ком пании Sun Microsystems.

Для запуска и исполнения программ необходима Java Runtime Environment (среда выполнения Java, JRE) . Для разработки программ также требуется ком плект разработки программнога обеспечения - JDK (Java Development Кit). Java Development K it - это комплект разработчика приложений на язы­ке Java, включающий в себя ком пилятор Java Uavac), стандартные библиоте­ки классов Java, примеры, документацию, различные утилиты и уже вклю­чающий в себя Java Runtime Environment (JRE) . Java Development Kit досту­пен для свободной загрузки на сайте Sun Microsystems по адресу http://java.sun.com/javase/downloads/index.jsp.

ПРИМЕЧАННЕ

На момент написания книги последней версией была JDK 6 Update 1 7 Для ра­боты с примерами в данной кн иге была установлена версия JDK 6 Update 1 7 with Java Е Е .

Page 27: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

Среда разработки 1 7

После загрузки JDK сделайте инсталляцию с параметрами по умолчанию, предлагаемыми мастером установки.

Однако в состав JDK не входит интегрированная среда разработки на Java (IDE), поэтому для разработки приложений необходимо использовать Ecl ipse.

2. 1 .3. Уста новка Ecl i pse

Следующий шаг - загрузка интегрированной среды разработки Ecl ipse. Ec l ipse доступен для загрузки по адресу http://www.eclipse.org/downloads/.

Загрузите одну из рекомендованных к использованию версий Ecl ipse, пере­численных в разд. 2. 1 . 1 (автором была применена версия Ecl ipse IDE for Java ЕЕ Developers) .

После того как вы загрузили Ec l ipse, разверните архив и запустите файл ecl ipse.exe. По умолчанию Ecl ipse устанавливается в ваш пользовательский каталог (в MS Windows), нь вы можете установить его в каталог Program Fi les или любой другой.

Несмотря на то что для разработки можно использовать и другие IDE, есть несколько причин , почему Ecl ipse рекомендуется для разработки Аndrоid­приложений :

D Ecl ipse - наиболее полно документированная, свободная и доступная ин­тегрированная среда разработки для Java. Ecl ipse также очень прост в изу­чении - освоение его займет минимальное время . Это делает Ecl ipse очень привлекательным IDE для разработки приложений под Android;

D ком пания Google выпустила плагин к продукту Android для Ecl ipse ­Android Development Tools, который позволяет создавать Android-пpoeкты, ком пилировать и использовать эмулятор мобильного Android-ycтpoйcтвa для их запуска и отладки приложений. Плагин Android Development Tools для Ecl i pse автоматически создает необходимую структуру Android­пpoeктa и устанавливает требуем ые параметры настройки компилятора.

2. 1 .4. Установка Android SDK

Чтобы разрабатывать приложения для Android, необходим Android SDК. SDK вкл ючает эмулятор, так что нет необходимости в мобильном устройстве с ОС Android, чтобы разрабатывать приложения для Android . Последняя версия на момент написания книги - Android SDK v2 .0 . Android SDK доступен для свободного скачи вания на официальном сайте Android по адресу http://developer.android.com/sdk/index.html.

После загрузки распакуйте файл в выбранную вами директорию. Начиная с версии 2.0 архив Android SDK содержит только инструментальные средства.

Page 28: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

1 8 Глава 2

В ранних версиях SDK архив содержал полный комплект компонентов теку­щей платформы Android . В версии 2 .0 используется Android SDK and А VD Manager, чтобы установить или модифицировать компоненты SDK - паке­ты, инструменты, дополнения и документацию.

Чтобы разрабатывать приложения, необходимо установить не менее одной версии платформы Android, используя Android SDK and А VD Manager. Это требует подключения к Интернету, т. к. все необходимые для загрузки и об­новления ком поненты SDK находятся в репозитории на сервере Google .

Чтобы открыть Android SDK and А VD Manager, заnустите файл SDK Setup .exe в корневом каталоге SDК. После установки соединения с реnозито­рием в окне менеджера будет отображен сnисок достуnных nакетов, как nо­

казана на рис. 2 . 1 .

v SDK Platform Android 1 .6, API 4, re . . . ? Google AP!s Ьу Google Inc . , Andro1d . . .

v SDK Platform Android 1 . 1 , АР! 2 , r e . . .

v SDK Platform Android 2 . 0, API 5, re . . .

? Google AP!s Ьу Google Inc . , Android . . .

? Usb Dr1ver package, revi 10n 2 V Documentation for Android SDK, АР! . . .

Рис. 2 .1 . Выбор пакетов для инсталляции

В ыбрав необходимые nакеты, нажмите кноnку Install Accepted и далее, сле­дуя инструкциям, установите комnоненты SDK. После успешной установки Android SDK можно пристуnать к установке АDТ-nлагина для Ecl ipse.

2.1 .5 . Установка Android Development Tools

Плагин Android Development Tools (ADT) - это расширение для интегриро­ванной среды разработки Ec l ipse, ускоряющее и упрощающее создание и от­ладку приложений .

Page 29: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

Среда разработки 1 9

Для установки Android Development Tool s сначала запустите Ecl ipse, затем выберите пункт меню Help 1 Install New Software. В появившемся диалого­вом окне нажмите кнопку Add . После установки соединения пометьте уста­навливаемые компоненты ADT, как показано на рис. 2 .2 .

Рис. 2.2. Инсталляция комnонентов ADT

После выполнения всех инструкций по установке перезапустите среду Ecl ipse.

Теперь необходимо связать Ec l ipse с каталогом Android SDK. Выберите в главном меню Ec l ipse пункт Window 1 Preferences, чтобы открыть диалого­вое окно Preferences. Выберите в левой паиели пункт Android . В поле SDK Location в основной паиели необходимо указать каталог, в котором располо­жен Android SDK. Для этого нажмите кнопку Browse и установите путь к ка­талогу Android SDK, как показано на рис. 2 . 3 .

Нажмите кнопку Apply, затем ОК. IDE Ecl ipse теперь "видит" библиотеки и инструменты Android SDK, и можно начинать разрабатывать приложения для Android .

АDТ-плагин для Ecl ipse автоматизирует и упрощает процесс построения при­ложений для Android, интегрируя инструменты разработки непосредственно в среду разработки Ecl ipse, что делает создание, запуск и отладку ваших при­ложений быстрее и проще.

Page 30: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

20

fii Ant

Build DDMS Launch LogCat Usage Stats

fii Data Management fii Help � Instaii/Update � Java

Java ЕЕ '* Plug-in Development fii Remote Systems fii Run/Debug 'J Server

fii Tasks rti Team

Terminal r1:i Usage Data Collector

Validation fii Web r1:i Web Services ;tJ XDoclet fii XML

Android 1 . 1 Android 1 . 5 Android 1 . 6 Android 2 .0 Google AP!s Google APis Google APis

Android Open Source Project Android Open Source Project Android Open Source Project Android Open Source Project Google Inc . Google Inc. Google Inc.

Рис. 2.3. Связывание среды Eclipse с Android SDK

1 .5 1 . 6 2 .0 1 .5 1 . 6 2 . 0

5 з 4 5

Глава 2

АDТ-плагин к программе интегрирует в Ecl ipse следующие компоненты :

L] мастер создания проекта Android - New Project Wizard, который упрощд­ет создание новых проектов Android и формирует шаблон проекта;

L] редактор Layout Editor - для разработки графического интерфейса при­ложения;

L] редакторы ресурсов для создания, редактирования и проверки правильио-сти ХМL-ресурсов разработчика.

АDТ-плагин также предоставляет доступ к остальным инструментам Android внутри Ecl ipse. Например, ADT позволяет запускать эмулятор мобильного устройства, получить доступ ко многим возможностям DDMS (Dalvik Debug Monitor Service) - инструмента SDK для управления портами, настройки контрольных точек (breakpoints), просмотра информации о потоках и процес­сах непосредственно из среды Ecl ipse. Подробнее инструменты для разработ­ки будут рассмотрены позднее.

Page 31: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

Среда разработки 21

2 .2 . Обзор Android SDK Android SDK включает в себя разнообразные библ иотеки, документацию и инструменты, которые помогают разрабатывать мобильные приложения для платформы Android .

D API Android SDK - АРI-библиотеки Android, предоставляемые для разра­ботки приложений .

D Документация SDK - включает обширную справочную информацию, детализирующую, что включено в каждый пакет и класс и как это исполь­зовать при разработке приложений .

D AVD (Android Virtual Device) - интерактивный эмулятор мобильного устройства Android . Используя эмулятор, можно запускать и тестировать приложения без использования реального Android-ycтpoйcтвa.

D Development Tools - SDK включает несколько инструментальных средств для разработки, которые позволяют компилировать и отлаживать созда­ваемые приложения .

D Sample Code - Android SDK предоставляет типовые приложения, которые демонстрируют некоторые из возможностей Android, и простые програм­мы, которые показывают, как использовать индивидуальные особенности API в вашем коде.

2.2. 1 . Версии SDK и And roid API Level

Перед началом разработки приложений для Android полезно понять общий подход платформы к управлению изменением API . Также важно понять Android API Level (Идентификатор уровня API) и его роль в обеспечении со­вместимости вашего приложения с устройствами, на которых оно будет уста­навливаться .

Уровень API - целочисленное значение, которое однозначно определяет версию API платформы Android . Платформа обеспечивает структуры API, которые приложения могут использовать для взаимодействия с системой Android . Каждая следующая версия платформы Android может включать об­новления API .

Обновления АРI-структуры разработаны так, чтобы новый API оставался со­вместимым с более ранними версиями API . Таким образом, большинство из­менений в API является совокупным и вводит новые функциональные воз­можности или исправляет предыдущие. Поскольку часть API постоянно об­новляется, устаревшие API не рекомендуются к использованию, но не удаляются из соображений совместимости с имеющимися приложениями .

Page 32: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

22 Глава 2

Уровень API , который использует приложение для Aпdroid, определяется це­лочисленным идентификатором, который указывается в файле конфигурации каждого Апdrоid-приложения . На момент написания книги существовало 7 уровней API .

Табл . 2 . 1 определяет соответствие уровня API и версии платформы Aпdroid .

Таблица 2. 1 . Соответствие версии платформы и уровня АР/

Версия платформы Урове н ь API

Andro id 2 . 1 And ro id 2 .0 . 1 Android 2 . 0 Andro id 1 . 6 Andro id 1 . 5 Andro id 1 . 1 Android 1 . 0

2.2 .2 . Инструменты для разработки и отладки п риложений

7 6 5 4 3 2 1

Кроме эмулятора, SDK также включает множество других инструмента,пьных средств для отладки и установки создаваемых приложений . Есл и вы разраба­тываете приложения для Aпdroid с помощью IDE Ecl ipse, многие инструмен­ты командной строки, входящие в состав SDK, уже используются при сборке и ком п иляции проекта. Однако кроме них SDK содержит еще ряд полезных инструментов для разработки и отладки приложений :

D aпdroid - важны й инструмент разработки, запускаемый из командной строки, который позволяет создавать, удалять и конфигурировать вирту­альные устройства, создавать и обновлять Апdrоid-проекты (при работе вне среды Ecl ipse) и обновлять Aпdroid SDK новыми платформам и, до­полнениями и документацией ;

D Dalvik Debug Moп itor Service (DDMS) - интегрированный с Dalv ik V i rtual Macl1 iпe, стандартной виртуальной машиной платформы Aпdroid, этот ин­струмент позволяет управлять процессам и на эмуляторе ил и устройстве, а также помогает в отладке приложений . Вы можете использовать этот сервис для завершения процессов, выбора определенного процесса для от­ладки, генерирования трассировочных данных, просмотра "кучи" или ин­формации о потоках, делать скриншоты эмулятора ил и устройства и мно­гое другое;

Page 33: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

Среда разработки 23

О Hierarchy Viewer - визуальный инструмент, который позволяет отлажи­вать и оптимизировать пол ьзовательский интерфейс разрабатываемого приложения . Он показывает визуальное дерево иерархии представлений, анализирует быстродействие перерисовки графических изображений на экране и может выполнять еще м ного других фун кций для анализа графи­ческого интерфейса приложений;

О Layoutopt - инструмент командной строки, который помогает оптим изи­ровать схемы разметки и иерархии разметок в создаваемом приложении . Необходим для решения проблем при создании сложных графических ин­терфейсов, которые могут затрагивать производител ьность приложения;

О Draw 9-patcl1 - графический редактор, который позволяет легко создавать N iпеРаtсl1-графику для графического интерфейса разрабаты ваемых при­ложений;

О sq l iteЗ - инструмент для доступа к файлам данных SQLite, созданных и используемых приложениями для Android;

О Tracev iew - этот инструмент выдает графический анализ трассировочных логов, которые можно генерировать из приложений;

О mksdcard - инструмент для создания образа диска, который вы можете использовать в эмуляторе для симуляции наличия внешней карты памяти (например, карты SD) .

Далее в этой книге, при разработке учебных приложений, мы рассмотрим не­которые из этих инструментов .

Наиболее важный из них - эмулятор мобильного устройства, однако в со­став SDK входят и другие инструменты для отладки, упаковки и инсталляции ваших приложений на эмулятор.

2.2 .3 . And roid Vi rtual Device

Android V i rtual Dev ice (Виртуальное устройство Aпdroid) - это эмулятор, который запускается на обычном ком пьютере. Эмулятор испол ьзуется для проектирования, отладки и тестирования приложений в реальной среде вы­полнения .

Прежде чем вы сможете запускать Аndrо id-эмулятор устройства, необходимо создать Andro id V i rtual Device (А VD) . А VD определяет систем ное изображе­ние и параметры настройки устройства, используем ые эмулятором .

Создавать эмулятор устройства можно двумя способами :

1 . В командной строке утилитой android, доступной в каталоге, куда вы установили Aпdroid SDK, в шiпке too ls .

Page 34: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

24 Глава 2

2 . Визуально с помощью Android SDK and А VD Manager в IDE Ec l ipse, вы­брав пункт меню Window 1 Android SDK and А VD Manager. Появится окно Android SDK and А VD Manager, с помощью которого можно созда­вать и конфигурировать эмуляторы мобил ьного устройства, а также за­гружать обновления Android SDK (рис. 2 .4).

ПРИМЕЧА НИ Е

Окно Android SDK and AVD Manager также появится , если в командной строке вызвать android .exe без параметров .

Рис. 2.4. Окно Android SDK and AVD Manager

В правой части панели List of existing Android Virtual Devices нажмите кнопку New, при этом откроется окно Create new А VD (рис. 2 . 5 ) .

В этом окне задайте нужную конфигурацию для создаваемого эмулятора уст­ройства:

LJ Name - имя создаваемого устройства;

D Target - версия Android SDK, поддерживаемая устройством. Устройство имеет обратную совместимость со старыми версиями SDK, т. е . если вы­брана версия Aпdroid 2 .0, эмулятор будет поддерживать версии SDK 1 .6, 1 . 5 , 1 . 1 ;

D SD Card - устанавливает виртуальную карту SD;

LJ Skin - тип экрана устройства. Загружаемая платформа включает ряд ски­нов для эмулятора, которые можно использовать для модел ирования раба-

Page 35: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

Среда разработки 25

ты приложения в устройствах с разными размерами и разрешением экра­на. Набор скинов для эмулятора в зависимости от установленной версии SDK, указанной в поле Target, содержит различные типы и размеры экра­на, например:

• HVGA (Нalf-size VGA Video Graphics Array), размер 32Ох480, сред­няя плотность, нормальный экран;

• WVGA800 (Wide Video Graphics Array), размер 48Ох 800, высокая плотность, нормальный экран;

Рис. 2.5. Диалоговое окно создания нового AVD

• WVGA854 (Wide Video Graphics Array), 48О х 854, высокая плотность, нормальный экран;

• QVGA (Quarter Video Graphics Array), размер 24Ох320, низкая плот­ность, малый экран;

• WQVGA (Wide Quarter Video Graphics Array), размер 24Ох400, низ­кая плотность, нормальный экран;

Page 36: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

26 Глава 2

D Hardware - имитация оборудования, установленного на устройстве. При необходимости нажатием кнопки New можно вызвать окно для добавле­ния доnолнительного виртуального оборудования (рис. 2 .6) .

Р и с . 2 . 6 . Окно для добавления дополн ительного виртуального оборудования

После задания конфигурации и нажатия кноnки Create AVD (см . рис. 2 . 5 ) менеджер создаст новое виртуальное устройство, название и версия API ко­торого появятся в списке List of existing Android Virtual Devices (см . рис. 2 .4).

ПРИМЕЧА НИ Е

Для более тонкой настрой ки луч ше испол ьзовать инструмент командной строки andгoid .exe . Он и меет более широкие возможности , чем визуальн ый AVD Мапаgег, и удобен для конфигурации сети , портов и виртуального оборудова­ния эмулятора. К сожалению , из-за ограниченного объема книги нет возможно­сти рассмотреть подробнее этот инструмент.

В зависимости от поддерживаемой версии API внешний вид виртуального устройства будет отличаться . Для версий 1 . 5 и ниже устройство примет вид, показанный на рис. 2 . 7, для версий 1 .6, 2 .0, 2 . 1 будет выглядеть, как на рис. 2 . 8 .

Окно эмулятора оформлено в виде телефона с допол нительной клавиатурой . На рис . 2 . 8 показана загруженная операционная система. После загрузки сис­темы появляется Home screen - рабочий стол Android . Для доступа к нему используется кнопка со значком домика. Эмулятор также имитирует сенсор­ный экран реального мобильного устройства - в эмуляторе на экран нажи­мают левой кнопкой мыши .

В эмуляторе два виртуал ьных рабочих стола, перемещение по которым осу­ществляется с помощью кнопок со стрелкам и на навигационной паиел и уст­ройства или передвижением курсора при нажатой левой кнопке мыши (в реальном устройстве - перемешая палец по экрану). Кроме ярлыков про­грамм ы на рабочем столе можно размещать виджеты .

Page 37: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

Среда разработки 27

Рис. 2 . 7 . Внешни й вид AVD версии 1 . 5

Рис. 2 .8 . Внешний в ид AVD верси и 2 .0

Page 38: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

28 Глава 2

ПРИМЕЧА ННЕ

ДЛSI тестирования внешнего вида создаваемого п риложения п ри разн ых поло­жениях экрана комбинацией клавиш <Ctгi>+ < F 1 1 > можно изменять расположе­ние экрана с вертикального на горизонтальный и наоборот.

Паиель в верхней части экрана - это Status Bar. На ней расположены значки системных уведомлений : мощность сигнала станции мобильной связи, заряд аккумулятора и текущее время . Паиель Status Bar также предназначена для отображения (в виде значков, появляющихся в левой части панели) пользова­тельских уведомлений о п ропущенных звонках, непрочитанных текстовых и мультимедийных сообщениях, полученной почте и системных уведомлений от служб, работающих в фоновом режиме. Если в Status Bar выбрать значок уведомления и потянуть вниз появившийся маркер, открывается расширенная паиель уведомления с более подробной информацией и кнопкой закрытия уведомления .

Маркер внизу экрана позволяет открыть окно запуска установленных в сис­теме приложений - Application Launcher (рис. 2 .9) . Окно выдвигается при нажатии на маркер.

Эмулятор, тем не менее, не поддерживает некоторые функциональности, дос­тупные на реальных устройствах:

О входящие и исходящие сообщения . Однако можно моделировать обраще­ния по телефону через интерфейс эмулятора;

Рис. 2.9 . Панель запуска установленных приложений Application Launcher

Page 39: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

Среда разработки

D соединение через USB;

D видеокамера (однако есть имитатор работы видеокамеры);

D подключен ие наушн иков;

D определение статуса соединения;

D определение уровня заряда аккумуляторной батареи ;

D определение вставки или изъятия карты SD;

D соединение по 8 \uetooth .

29

Конечно, реальные телефоны несколько отличаются от эмулятора, но в целом А VD разработан очень качествен но и близок по функциональности к реаль­ному устройству.

Page 40: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

ГЛ А В А 3

Первое п риложен ие для And roid

Итак, после того как м ы установил и и настроил и среду разработки и эмуля­тор мобильного устройства, можно приступить к созданию своего первого приложения, в качестве которого традиционно выступает приложение "He l lo, Andro id ! "

3.1 . Создан ие п роекта в Ecl i pse Создавать проект для платформы Android довольно легко, особенно при ис­пол ьзовани и в качестве среды разработки Ecl i pse. Откройте Ecl ipse и выбери­те File 1 New 1 Android . Выберите опцию Android Project и нажмите кнопку Next (рис. 3 . 1 ) .

Откроется диалоговое окно мастера New Android Project (рис. 3 .2) . В этом окне заполните поля приведеиными значениями :

О Project name - Hel loAndroict;

О Application name - He l l o , Android ! Sample;

О Package name - сот . samp l e s . hel l oandroid;

О Create Activity - HelJ_oAndroidAc t ivity;

О Build Target - Android 1 . s; О Min SDK Version - з. Далее представлены описания каждого поля .

О Project name - имя проекта Ec l ipse - имя каталога, которы й будет со­держать проектные файлы .

О Application name - заголовок вашего приложения - имени, которое появится в заголовке окна приложения в верхней части экрана.

Page 41: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

32

Select а wizard

& Class

fi Interface

·� Java Pro}ect

� Java Project from Existi"'l Ant Buildfile

;J& Plug-in Project

!±1 Q:i. General

;j;j Q:i. Android

. · ·ill3 dd'МI Jci1 Android Test Project

.� Android XML File

00 · ·1:7 Connection Profiles

;±! l.ii& cvs

Рис. 3.1 . Диалоговое окно создания нового проекта

Глава 3

О Package name - имя пакета, которое имеет такие же правила построения и и менования пакетов, как и для приложений на Java. Это поле устанавл и­вает имя пакета, под которым класс, расширяющий Act ivi ty, будет сгене­рирован .

ОБРА ТИ ТЕ ВНИМА НИЕ

И мя ва шего пакета должно быть уникально по отношению ко всем пакетам , установленн ым на мобильном устройстве Aпdгoid. По этой п ричи не очень важ­но испол ьзовать стандартный пакет доменного стиля для ваших приложений .

О Create Activity - имя для заглушки класса, которая будет сгенерирована плагином. Заглушка является подклассом класса Activity. Переключатель около поля ввода предполагает, что создание класса является необязател ь­ным, но Activity почти всегда используется как основа для приложения . Подробнее об Act ivity м ы поговорим в главе 4, когда будем рассматри­вать ком поненты Аndrоid-приложений .

О Use default location - позволяет изменять местоположение на диске, где файлы проекта будут сгенерированы и сохранены .

О Min SDK Version - значение определяет минимальный уровень API , тре­буемый для приложения .

Page 42: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

Первое приложение для Android

New Android Project Creates а new Android Project r

1 .5 1 .6 1 . 6 2 .0 2 .0 2.0. 1 б

Рис. 3. 2. Диалоговое окно New Android Project

33

О Build Target - указание компилятору собрать приложен ие для выбранно­го уровня API (выставляется автоматически, основы ваясь на выбранной версии SDK в поле Min SDK Version).

ОБРА ТИТЕ ВНИМАНИЕ

П ри выборе уровня API не следует устанавливать самый последний из доступ­ных на данный момент уровней. Необходимо учиты вать требования к фун кцио­нальности приложения и поддерживаемый на реальном устройстве уровень A P I . Если приложение требует уровень AP I , который выше, чем уровень AP I , поддерживаемый устройством , то приложение не будет установлено.

Page 43: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

34 Глава 3

В поле Bui ld Target была выбрана для использования платформа Android 1 . 5 (Min SDK Version - 3) . Это означает, что ваше приложен ие будет откомпили­ровано с исnользованием библиотек Android 1 . 5 . П риложения Android совмес­тим ы снизу вверх , так что приложения , собранные на версии библиотек API 1 . 5 , будут работать на платформах 1 .6 , 2 . 0 , 2 . 0 1 и 2 . 1 .

Нажмите кнопку Finish . Мастер New Android Project сгенерирует проект. Это должно быть видно в окне Package Explorer слева.

По умолчанию АDТ-плагин генерирует проект с единственным окном и тек­стовы м полем, с надписью "Hel lo, World" + имя класса деятел ьности (главно­го окна приложения), которое вы определили в поле Create Activity. При же­лании можете поменять надпись, например, на "Hel lo, Android ! " Для этого откройте файл stri ngs.xm l , находящийся в каталоге res/values/, и в появив­шемся окне редактора ресурсов Resource Editor перейдите в режим тексто­вого редактирования XML и измените значение для элемента < s t r ing

name= " he l l o " > :

< s t ring name= " he l l o " >Hel l o , Android ! < / s t ring>

Нажм ите кнопку Run . Появится окно Run As запуска проекта на выполне­ние. Выберите из списка Select а way to run 'HelloAndroid' опцию Android Application и нажмите кнопку ОК (рис. 3 .3 ) .

2_elect а way t o run 'НelloAdrold':

i!tii�IDШГ� _rgдndroid JUnit Т est

� Java дpplet

Ш Java дpplicati

,Tti JUnit Test

Des�ription Runs an дndroid App&cation

Рис. 3.3. Окно компиляции и запуска проекта

АDТ-плагин для Ec l ipse автоматически создаст новую исполняемую конфи­гурацию для вашего проекта, которая автоматически запустится в эмуляторе мобильного устройства. После запуска эмулятора и загрузки операционной

Page 44: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

Первое приложение для Android 35

системы разблокируйте его, нажав кнопку MENU. В окне эмулятора поя вит­ся ваше приложение (рис. 3 .4 ) .

Рис. 3.4. Окно програ м м ы "Hel lo , Android' Sample"

В окне программ ы мы увидим две строки. Текст "Hel lo, Android ! Sample" , который виден в серой области вверху, - это заголовок приложения . Текст ниже заголовка - текст, который вы создали в файле строковых ресурсов strings.xml .

3 .2 . Структура проекта АDТ-плагин при создании проекта организует структуру в виде дерева ката­логов, как и любой другой проект Java. В среде Ecl ipse, в окне Package Explorer, можно видеть структуру созданного проекта (рис. 3 . 5 ) .

ПРИМЕЧАННЕ

Структура файлов и каталогов проекта может меняться в зависимости от уров­ня AP I , установленного для проекта . Например, для уровня 7 (версия Aпdroid 2 . 0) в каталоге res/ вместо папки d rawaЫe/ будут создан ы три пап ки : d rawa Ыe­hdpi/, d rawaЫe-mdpi/, drawaЫe-ldp i/ с иконками для разного разрешен ия экрана мобильного устройства .

Page 45: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

36

$· (� src з е com. samples.helloandroid

lfi . . 0 Helloдndroidдctlvity. java 8 ®!! gen [<;e;.er· ,ted .J�·•• File·;]

liil · !!: com.samples. helloandrord lti ilJ R. java

:iJ ·W. дndroid 1 .5 . ... � assets

� ·� res ::.0 ·2& dr аwаЫе . · · ·iJ icon.pnQ

!i:il 2& layout · i)t main.xml

8 (i&, values LJt strings.xml

<Qi дndroidManifest .xml

[@ default.properties

Рис. 3.5. Структура проекта "HelloAndroid" в окне Package Explorer

Глава 3

При компиляции в каталоге проекта создается папка b in/. Откомпилирован­ный код Jаvа-классов вместе с файлами данных и ресурсов помещается в ар­хивный файл с расширением apk. Этот файл используется для распростране­ния приложения и установки его на мобильных устройствах . . Рассмотрим теперь подробнее каталоги и файлы, созданные в проекте.

3.2 . 1 . Каталог ресурсов

В этом каталоге хранятся используемые в приложении статические файлы ресурсов : изображения, строки, анимация и др. Некоторые из подкаталогов создаются ADT -плагином, другие необходимо добавлять самостоятельно, используя предопределенные имена. Обычно в ресурсы включают следую­щие подкаталоги :

D res/drawaЬJe/ - для изображений (PNG, JPEG и т. д.) ;

D res/layout/ - для ХМL-файлов разметки (компоновка графических эле-ментов управления для окон приложения);

D res/menu/ - для ХМL-файлов меню;

D res/values/ - для строковых ресурсов, массивов и т. д. ;

D res/xml/ - для других ХМL-файлов, которые понадобятся для разработки приложения.

Следует отметить несколько ограничений относительно создания папок фай­лов ресурсов . Во-первых, Android поддерживает только линейный список файлов в пределах предопределенных папок под каталогом res/. Например, он не поддерживает вложенные паnки под nаnкой для ХМL-файлов разметки (или другим и папками в каталоге res/) .

Page 46: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

Первое приложенив для Android 37

Подкаталог res/layout/ В эту папку помещаются файлы разметки в формате XML, которые опреде­ляют внешний вид окна деятельности и расположение на нем элементов управления. Плагин по умолчанию генерирует базовую разметку для главно­го окна приложения с единственным элементом TextView (листинг 3 . 1 ) .

< ? xrnl ve rsion= " l . O " encoding= " utf-8 " ?>

<LinearLayout xmlns : android= " http : / / schernas . android . com/ apk/ res / android"

android : layout_width= " fi l l_parent "

android : layout_height= " fi l l_parent " >

<TextView

android : id= " @ +id/TextViewO l "

android : layout_width= " fi l l_parent "

android : layout_he ight="wrap_

content "

android : text= " @ s tring /he l l o " >

< /TextView>

< / LinearLayout>

Создание файлов разметки будет рассматриваться в главе 5, элементов управления - в главах 6 и 7.

Подкаталог res/drawaЬie/ В этом каталоге размещаются все графические файлы, используемые в при­ложении . На данный момент там есть только файл icon .png - значок прило­жения, по умолчанию устанавливаемый для приложения мастером создания проекта и отображаемый в меню запуска установленных на телефоне прило­жений (Application Launcher).

Подкаталог res/va lues/ В этой папке хранятся общие константы для всего приложения : текст, ис­пользуемый элементами управления, цвета, стили и т. д. Например, если мы хотим вывести "He l lo, Android ! " в текстовое поле, можно это сделать двумя способами :

D написать явно в файле разметки или в файле манифеста;

D создать в strings.xml константу he l l o со значением " Hel lo, Android ! " , а в файле разметки в атрибуте android : text для элемента TextView указать ссылку на ресурс в striпgs .xml , как в л истинге 3 . 1 :

andro i d : t e x t = " @ s t r ing / he l l o "

Page 47: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

38 Глава 3

Пример файла строковых ресурсов для нашего приложения представлен в л истинге 3 .2 .

< ? xml ve rsion= " . 0 " encoding= " ut f- 8 " ? >

<resources>

<st ring narne= " he l l o " >He l l o , Android ! < / st ring>

<string narne=" app_narne " > "He l l o , Android ! " Sarnple< / string>

</ res ources >

3.2 .2 . Файл R.java

Когда проект ком пилируется первый раз, среда создает класс R и помещает его в файл R.j ava. Этот класс используется в коде программы для обращения к ресурсам, которые находятся в каталоге res/.

Пример файла R.java для нашего приложения показан в листинге 3 . 3 .

AUTO-GENERATED FILE . DO NOT MODI FY .

Thi s class was automat ically gene rated Ьу the

aapt toQl from the resource data it found . It

should not Ье modi fied Ьу hand .

pac kage com . Зarnple s . he l loandroi d ;

puЬ l i c f i n a l class R

puЬlic static final class attr

puЬ l i c s tatic final class drawaЬle

puЬlic static final int icon=Ox7 f0 2 0 0 0 0 ;

puЬ l i c static final class id

puЬ l i c static fina l int TextViewO l=Ox7 f0 5 0 0 0 0 ;

puЬlic static final class layout {

puЬl i c static final int main=Ox7 f0 3 0 0 0 0 ;

Page 48: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

Первое приложение для Aпdroid

puЬl i c static final class s t r ing

puЬ l i c static final int app_name=Ox7 f 0 4 0 0 0 l ;

puЬ l i c s tatic final int hel lo=Ox7 f0 4 0 0 0 0 ;

39

Класс R содержит набор внутренних классов с идентификаторами ресурсов, которые он создает в зависимости от внутреннего содержимого каталога res/:

Ll drawaЬle - для каталога res/drawaЬ\e/;

Ll layout - для каталога res/layout/. Содержит идентификаторы файлов раз­метки. В нашем приложении только один файл разметки - main .xml , сге­нерированный мастером создания проекта. Если в приложении определе­ны несколько деятельностей, для каждой из них необходимо будет опре­делять файл разметки;

Ll id - для идентификаторов компонентов разметки, определенных в файле main .xm l ;

Ll s t r ing - для идентификаторов строк в файле str ings.xm l .

При добавлении в ресурсы других файлов среда сгенерирует новый класс R,

добавив в него допол нительные вложенные классы .

ОБРА ТИТЕ ВНИМАНИЕ

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

3.2 .3 . Файл Hel loAnd roidActivity.java

He l l oAndroidActi vi ty - это класс, автоматически генерируемый ADT -плаги­ном для главной деятельности (окна) приложения .

Плагин определяет в классе метод обратного вызова oncreate ( ) , который вы­зы вается системой для прорисовывания окна деятельности на экране устрой­ства. В этот класс разработчик может добавлять код, реализующий логику работы nриложения в данной деятельности .

Пример класса He l l oAndroidAct ivity, расширяющего класс Act ivity, для на­шего приложения показан в листинге 3 .4 .

pac kage com . sample s . helloandroid;

import android . app . Activi t y ;

import android . os . Bundle ;

Page 49: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

40

puЫ i c class He lloAndroidActivity extends Activity

/ * * Cal l ed when the activity is first created .

@Ove r ride

puЫ ic void onCreate ( Bundle savedins tanceState )

supe r . onCreate ( savedinstanceState ) ;

setContentView ( R . layout . main ) ;

Глава 3

Если приложение будет иметь несколько окон, для каждого из них надо будет

вручную создать отдельный класс, наследуемый от базового класса Act ivity.

В следующих главах будет подробно рассмотрено написание классов, реали­зующих деятельность в приложении.

3.2.4. Файл And roidMan ifest.xm l

Манифест - структурный ХМL-файл, всегда имеет название AndroidMan ifest.xml для всех приложений. Он задает конфигурацию прило­жения : объявляет ком поненты приложения, перечисляет любые библиотеки, связанные с приложеннем (помимо библиотек Android, связанных по умол­чанию), и объявляет разрешения, которые приложение предоставляет.

Код файла манифеста приведен в листинге 3 . 5 .

< ?xml ve rsion= " . О " encoding= " ut f- 8 " ?>

<mani fest xmlns : android= " http : / / s chemas . android . com/apk/ res /android"

android : versionCode= " l "

android : versionName= " l . O "

package= "com . s amples . he l l oandroid">

<application

android : icon= " @drawaЬle/ icon"

android : label= " @ s t ring /app_

name " >

<act ivi ty

android : name= " . He l loAndroidAct ivi ty"

android : label=" @ s t ring/app_name " >

< intent- f i lter>

<act ion android : name=" android . intent . action . МAIN "

<category android : name="android . intent . category . LAUNCНER" />

< / intent- filter>

< /activity>

Page 50: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

Первое приложение для Android 4 1

< /application>

<uses-sdk android : minSdkVe rs ion= " З "

< /rnanifest>

Например, атрибут android : name элемента <activity> вызывает подкласс

Act ivity, который реализует деятельность (окно) в приложении . Атрибуты icon и label прикрепляют файлы ресурсов, содержащих значок и текст, кото­рые могут быть отображены пользователю.

Аналогичным способом объявляются и другие ком поненты приложения. В следующей главе будет подробно рассказано о работе с файлом манифеста и о том, как требуемую функциональность Аndrоid-приложения можно объ­явить в файле манифеста.

Page 51: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

Г Л А В А 4

Ком поненты Аnd rоid -п риложения

Приложения для Android состоят из ком понентов, которые система может запускать и управлять так, как ей необходимо. Главная особенность плат­формы Android состоит в том, что одно приложение может использовать эле­менты других приложений (при условии, что эти приложения разрешают их использовать). При этом ваше приложение не включает код другого прило­жения ил и ссылки на него, а просто запускает нужный элемент другого при­ложения .

Для реализации такого использования ком понентов других приложений сис­тема должна быть в состоянии запустить процесс для приложения, в котором находится требуемый компонент, и инициализировать нужные ей объекты . Поэтому, в отличие от приложений в большинстве других систем, у прило­жений Android нет единственной точки входа для запуска всего приложения, аналогичной, например, функции main ( ) в С-подобных языках программиро­вания . Аndrо id-приложения состоят из компонентов, которые система может инициализировать и запустить при необходимости .

Всего в Аndrоid-приложениях существует четыре типа ком понентов :

D деятельность (Activity);

D служба (Service ) ;

D приемник широковещательных намерений (Broadcast Receiver);

D контент-провайдер (Content Provider) .

4. 1 . Деятел ьность Деятельность представляет собой визуальный пользовател ьский интерфейс для приложения - окно. Как правило, окно полностью запол няет экран мо­бильного устройства, но может иметь размеры меньше, чем у экрана. Дея-

Page 52: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

44 Глава 4

тельность может также использовать дополнительные окна, например всплы­вающее диалоговое окно, которое запрашивает пользовательский ответ для основной деятельности, или окно уведомления о каком-либо событии в при­ложении или системе.

Визуал ьное информационное наполнение окна определяется иерархией пред­ставлений . Каждое представление уnравляет заданным nрямоугольным nро­странством в nределах окна. Родительские nредставления содержат и органи­зовы вают схему размещения своих дочерних nредставлений . Представления также могут реагировать на nользовательское взаимодействие с интерфейсом программы . У Android есть много готовых nредставлений для исnользования в nриложениях - кноnки, текстовые nоля, линейки прокрутки, nункты меню, флажки и т. д. Подробнее nредставления и работа с ними рассматривается в главах 5, 6 и 7.

Все деятельности реализуются как nодкласс базового класса Act ivity (для примера nосмотрите созданное в nредыдущей главе nриложение, класс He l loAndroidAct i vi ty) .

Приложеине может содержать несколько деятельностей . Каждая деятель­ность независима от других. При открытии новой деятельности работа nре­дыдущей деятельности nриостанавливается, а сама она вносится и сохраняет­ся в стек деятельностей (стек и взаимодействие деятельностей будут рас­смотрены в главе 1 1) .

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

Приложения могут подключаться к службе или заnускать ее, если она не за­nущена, а также останавливать заnущенные службы. Подключивщись к службе, вы можете обращаться к ее функциям через интерфейс, nредостав­ляемой этой службой .

4.3 . П рие м н и ки ш и роковещател ьных намерен и й Приемник широковещательных наиерений - компонент для получения внешних событий и реакции на них. Инициализировать nередачи могут дру­гие nриложения и службы. Приложеине может иметь любой номер nриемин­ков широковещательных намерений, чтобы ответить на любые объявления, которые оно считает важными .

Page 53: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

Компоненты Android-npuлoжeнuя 45

Приемники широковещательных намерений не имеют пользовательского ин­терфейса. Однако они могут запустить деятельность в ответ на информацию, которую они получают, или показать уведомление, чтобы предупредить пользователя .

4.4. Контент-п ровайдеры Контент-провайдер делает определенный набор данных, используемых при­ложением, доступны м для других приложений .

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

4.5 . П роцессы и потоки Когда хотя бы один из компонентов приложения (или все приложение) будет востребован, система Android запускает процесс, который содержит единст­венный основной поток для выполнения . По умолчанию все компоненты приложения работают в этом процессе и потоке .

Однако можно принять меры, чтобы компоненты работали в других процес­сах и пораждали дополнительные потоки для любого процесса.

Все компоненты инициализируются в основном потоке процесса. Отдельные потоки для каждого экземпляра обычно не создаются. Следовательно, все методы обратного вызова, определенные в компоненте и вызываемые систе­мой, всегда работают в основном потоке процесса. Это означает, что компо­нент не должен выполнять в методах обратного вызова длительные операции (например, загрузку файлов из сети или циклы вычисления) или блокировать системный вызов, т. к. это блокирует любые другие компоненты в этом про­цессе. Для таких операций порождают отдельные потоки .

4.5 . 1 . Жизнен н ы й цикл процессов

Aвdroid может решить завершить процесс в случае нехватки памяти или если память востребована другими, более важными процессами . Прикладные ком­поненты, выполняющиеся в этих процессах, будут уничтожены. Процесс бу­дет перезапущен для компонентов в случае их повторного вызова.

При выборе процесса для уничтожения Android оценивает относительную важность этого процесса с точки зрения пользователя, т. е. 'видимый пользо-

Page 54: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

46 Глава 4

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

4.5 .2 . П риоритет и статус процессов

Порядок, в котором процессы уничтожаются для освобождения ресурсов, оп­ределяется приоритетом. Система Android пытается поддерживать процесс приложения максимально долго, но, в конечном счете, будет вынуждена уда­лить старые процессы, если заканчивается свободная память. Чтобы опреде­лить, какой процесс сохранить или уничтожить, Android создает иерархию важности процессов, основанную на компонентах, выполняющихся в процес­сах и состоянии этих компонентов (рис. 4. 1 ) .

} Критич

еский приор итет

Рис. 4 .1 . Приоритет и статус п роцессов

Процессы с самой низкой важностью уничтожаются первыми . Есть пять уровней в иерархии важности. Следующий список представляет их в порядке убывания важности.

D Активный процесс (Foreground Process) - тот, которы й требуется для то­го, что пользователь в настоящее время делает. Процесс считается актив­ным, если выполняется любое из следующих условий :

• процесс выполняет деятельность, с которой взаимодействует пользова­тель ;

• процесс выполняет службу, которая связана с деятельностью, с которой взаимодействует пользователь;

Page 55: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

Компоненты Апdгоid-приложения 4 7

• процесс имеет объект Service, и выполняется один из методов обратно­го вызова, определенных в этом объекте;

• процесс имеет объект BroadcastReceiver, и выполняется его метод об-ратного вызова для приема намерения .

Одновременно могут существовать только несколько приоритетных про­цессов . Они будут уничтожены только в крайнем случае - если памяти настолько мало, что они все вместе не в состоянии продолжать работу.

О Видимый процесс (VisiЬie Process) - тот, который не имеет никаких при­оритетных компонентов. Компонент из этого процесса еще может вызы­ваться пользователем . Процесс, как полагают, является видимым, если выполняется любое из следующих условий :

• это процесс деятельности, которая не находится в фокусе, но все еще видна пользователю. Это может произойти, например, при вызове диа­лога, которы й не занимает весь экран, а деятельность потеряла фокус, но видна пользователю и находится позади диалога;

• это служба, которая в данный момент связана с деятельностью, нахо­дящейся на переднем плане (или частично закрытой другой деятель­ностью).

О Види�ы й процесс считаются важным и не будет уничтожен, пока остают­ся процессы с более низким приоритетом .

О Сервисный процесс (Service Process) - процесс, в котором выполняется служба и которы й не относится ни к одной из двух предыдущих катего­рий . Хотя сервисные процессы обычно не привязаны к интерфейсу, види­мому пользователем, они выполняют задания, нужные пользователю, на­пример фоновая работа медиаплеера или загрузка данных из сети, так что система сохраняет их при наличии свободной памяти наряду со всеми ак­тивными и видимыми процессами .

О Фоновый процесс (Background Process) - процесс в котором вы полняется деятельность, которую в настоящее время не видима пользователем . Эти процессы не имеют никакого прямого воздействия на пользовательский ввод и могут быть уничтожены в любое время, чтобы востребовать память для активного, видимого или сервисного процесса. Обычно имеется м ного фоновых процессов, они сохраняются в списке LRU ( least recently used, "не использующиеся дольше всех"), чтобы гарантировать, что находящийся в конце этого списка процесс, в котором вы полняется деятельность, был бы уничтожен в последнюю очередь.

О Пустой процесс (Empty Process) - не содержит никаких активных ког-.шо­нентов приложения . Единственная причина сохранять такой процесс -

Page 56: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

48 Глава 4

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

Если в одном процессе выполняются несколько компонентов, Android опре­деляет приоритет процесса по компоненту с самым высоким приоритетом . Например, если в процессе выполняется служба и видимая деятельность, процесс будет ранжирован как видимый, а не сервисный процесс.

Если от некоторого процесса зависят другие процессы, его ранг также может быть увеличен . Процесс, который обслуживает другой процесс, никогда не может иметь приоритет ниже, чем процесс, который он обслуживает. Напри­мер, если контент-провайдер в процессе А обслуживает клиента в процессе В или если служба в процессе А связана с компонентом в процессе В, то про­цесс А получит приоритет не меньше, чем приоритет процесса В .

Поскольку сервисный процесс имеет ранг выше, чем фоновая деятельность, для выполнения фоновых процессов, требующих длительное время для за­вершения (например, передачи данных по сети), но которые должны гаранти­рованно завершиться, часто запускают отдельную службу вместо того, чтобы просто породить поток в деятельности . Это важно в случае, если операция передачи данных по сети будет продолжаться больше времени, чем окно дея­тельности, ' из которой эта операция была запущена, будет оставаться в види­мом процессе (будет видима на экране мобильного устройства) . По этой же причине Приемники широковещательных намерений должны использовать службы, а не просто помещать отнимающие много времени операции в поток.

4.6 . Жизнен н ы й ци кл ком понентов приложения Компоненты приложения имеют жизненный цикл - начало, когда Android инициализирует их, активный период работы, неактивный период, когда они бездействуют, и конец, когда компоненты уничтожаются и освобождают ре­сурсы для запуска других компонентов .

Особенность жизненного цикла приложения Android состоит в том, что сис­тема управляет большой частью цикла. Все приложения Android выполняют­ся только в пределах своего собственного процесса. Все выполняющиеся процессы наблюдаются системой, и в зависимости от приоритета компонента и от того, насколько интенсивно компонент (например, деятельность) работа­ет, Android может закончить его работу и передать освободившиеся ресурсы другому компоненту из этого процесса.

Page 57: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

Компоненты Android-npuлoжeнuя 49

Решая, должен ли компонент быть закрыт, Android принимает во внимание активность пользователя в работе с этим ком понентом, использование памяти и др.

4.6. 1 . Акти вация компонентов

Деятельности, службы и приемники широковещательных намерений активи­зируются в соответстви и с асинхронными сообщениями, называющимися намерениями.

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

Контент-провайдеры активизируются только тогда, когда они получают запрос от другого приложения для доступа к общим данным вашего прило­жения .

4.6 .2 . Завершение работы компонентов

Некоторые компоненты требуют явного их завершения, другие, наоборот, завершаются сами . Например, контент-провайдер активен только тогда, когда отвечает на запрос, а приемник широковещательных намерений активен при ответе на широковещательное сообщение, так что нет никакой необходимо­сти явно завершать эти компоненты .

Деятельности, с другой стороны, обеспечивают поддержку визуал ьного ин­терфейса пользователя . Они находятся в длительном сеансе связи с пользова­телем и могут остаться активными даже когда приложение простаивает, но сеанс связи продолжается . Точно так же службы могут оставаться активными в течение долгого времени. Поэтому Android имеет функции завершения дея­тельностей и служб в принудительном порядке.

Компоненты также могут быть закрыты системой, когда они больше не ис­пользуются или когда Android должен востребовать память для более при­оритетных компонентов.

4. 7 . Файл AndroidMan ifest.xm l Прежде чем Android запустит компонент приложения, он должен узнать, что этот компонент существует. Поэтому приложения объявляют свои компонен­ты в файле манифеста AndroidManifest .xml , который предоставляет основную

Page 58: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

50 Глава 4

информацию системе. Каждое приложение должно иметь свой файл AndroidManifest .xm l .

Файл манифеста выполняет следующие функции :

D объявляет и м я Jаvа-пакета данного приложения . И м я пакета служит уни­кальным идентификатором для приложения;

D описывает компоненты приложения - деятельности, службы, приемники широковещательных намерений и контент-провайдеры, из которых при­ложение состоит. Он вызывает классы, которые реал изуют каждый из компонентов, и объявляет их намерения . Эти объявления позволяют сис­теме Android знать, чем компоненты являются и при каких условиях они могут быть запущены;

D объявляет, какие разрешения должно иметь приложение для обращения к защищенным частям API и взаимодействия с другими приложениями ;

"'Helloдdroid �nifest

. q;: The appl1catюn tag descriЬes app�cation�level components contained 1n the package, as we" as gener 1 apphcation attr1Ьutes.

Б?.] Define an <applicatlon> tag 11 the AndroidManifest.xml

• 1\.ppUt:�t:itю AttribнtE':§ Defines the attriЬutes spedfic to the app&cati

Theme

rmiss1

Has code

Appltr..aHon Node�

'···········································································' lerow� . . � 1 Per

1 Вrows� . . . .J Еn�ы

................... �] ( Вrowse • • • j Debugt;)o'ble

@ @ @ @ (Ю @ @ д: Atto·ibut es lor <Onolo· od.iпtent. © Attrbutes that can Ье suppl1ed 11 an AndroidManifest .xml catP.gor-;

tag, а ch�d of the lntent-filter tag.

Рис. 4.2. Редактор файла ман ифеста

Page 59: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

Компоненты Апdrоid-приложения 51

О объявляет разрешения, которые сторонние приложения обязаны иметь, чтобы взаимодействовать с компонентами данного приложения ;

О объявляет минимальный уровень API Android, которого приложения тре-бует;

О перечисляет библиотеки, с которыми при:Ложение должно быть связано .

Редактировать файл манифеста можно вручную, записывая ХМL-код непо­средственно в файл или через визуальный редактор. Для работы с файлом манифеста в Ec l ipse есть отдельный инструмент - Manifest Editor (Редактор файла манифеста), который позволяет визуальное и текстовое редактирова­ние файла манифеста приложения, как показано на рис. 4 .2 .

4.7. 1 . Общая структура манифеста

Файл манифеста инкапсулирует всю архитектуру Аndrоid-приложения, его функциональные возможности и конфигурацию. В процессе разработки при­ложения вам nридется постоянно редактировать файл, изменяя его структуру и дополняя его новыми элементами и атрибутами по мере усложнения разра­батываемого приложения, поэтому важно хорошо ориентироваться во внут­ренней структуре манифеста и назначении его элементов и атрибутов .

На рис. 4 .3 приведена общая структура файла манифеста и элементов, кото­рые содержатся в нем, и назначение каждого из элементов.

1 <maп ifest> 1 <uses-permissioп> 1

<permissioп> 1 <permissioп-tree> 1

<permissioп-group> 1 <i пstrumeпtatioп> 1

<uses-sdk> 1 <uses-coпfiguratioп> 1

<uses-feature> 1 <supports-screeп> 1

<applicatioп> 1

} Корневой элемент

Разрешения

} Взаимодействие с системой

} Уровень API

} Требования к оборудованию

} Требования к функциональности

} Поддерживаемое разрешение экрана

} Описа ние ком понентов приложения

Рис. 4.3. Структура файла ман ифеста

Page 60: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

52 Глава 4

Порядок расположения элементов, находящихся на одном уровне, произ­вольный . Все значения устанавливаются через атрибуты элементов. Элемент <app l i cat ion> является основным элементом манифеста и содержит м ножест­во дочерних элементов, определяющих структуру и работу приложения . Элементы <mani fe s t >, <app l i cation> и <us es- sdk> являются обязательными. Другие элементы используются по мере необходимости .

<manifest> Элемент <manifest> является корневым элементом файла Aпdroid­Maп ifest .xm l . По умолчанию мастер создания проекта Android в Ecl ipse соз­дает элемент с четырьмя атрибутами :

<mani f e s t xmlns : android= " ht tp : / / s chema s . andro id . com/apk/ res / android" package= " com . programmingandro i d . he l loandroid" andro id : ve r s i onCode= " l " android : ve r s i onName= " l . 0 " >,

где :

О xmlns : android - определяет пространство имен Android. Это значение всегда неизменно для всех приложений;

О package - определяет имя пакета приложения, которое вы определили при создании приложения;

О andro id : ve rs ionCode - указывает внутренний номер версии;

О android : ve rs ionName - указывает номер пользовательской версии . Этот атрибут может быть установлен как строка или как ссылка на строкавый ресурс .

<permission> Элемент <pe rmi s s ion> объявляет разрешение, которое используется для огра­ничения доступа к определенным компонентам или функциональности дан­ного приложения. В этой секции описываются права, которые должны запро­сить другие приложения для получения доступа к вашему приложению.

Приложение может также защитить свои собственные компоненты (деятель­ности, службы, приемники широковещательных намерений и контент­провайдеры) разрешениями. Оно может использовать любое из системных разрешений, определенных Aпdroid (перечисленных в android . Manifes t . pe rmi s s i on) или объявленных другими приложениями, а также может опреде­лить свои собственные разрешения. Новое разрешение должно быть объявле­но в атрибуте andro id : name элемента <pe rmi s s ion> следующим образом :

pe rmi s s ion andro id : name= " com . s ample s . custom_permi s s ion "

Page 61: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

Компоненты Android-npuлoжeнuя

Кроме того, используются дополнительные атрибуты :

О andro id : label - имя разрешения, отображаемое пользователю;

О android : des c ription - описание;

О android : i con - иконка, представляющая разрешение;

53

О andro id : penni s s i onGroup - определяет принадлежиость к группе разре­шений ;

О android : protec t i onLeve l - уровень защиты .

<uses-permission> Элемент <use s -permi s s ion> запрашивает разрешение, которые приложению должны быть предоставлены системой для его нормального функционирова­ния . Разрешения предоставляются во время установки приложения, а не во время его работы .

Этот элемент имеет единственный атрибут - с именем разрешения ­android : name . Это может быть разрешение, определенное в элементе <pe rmi s s i on> данного приложения, разрешение, определенное в другом при­ложении или одно из стандартных системных разрешений, например:

android : name=" android . penni s s ion . CAМERA"

или

android : name= " " android . pe rmi s s ion . READ_CONTACTS "

<permission-tree> Элемент <pe nni s s i on-t ree> объявляет базовое имя для дерева разрешений. Этот элемент объявляет не само разрешение, а только пространство имен, в которое могут быть помещены дальнейшие разрешения.

<permission-group> Элемент <pe nni s s i on-group> определяет имя для набора логически связанных разрешений . Это могут быть как объявленные в этом же манифесте с элемен­том <pe rmi s s i on> разрешения, так и объявленные в другом месте. Этот эле­мент не объявляет разрешение непосредственно, только категорию, в кото­рую могут быть помещены разрешения. Разрешение можно поместить в группу, назначив имя группы в атрибуте pe nni s s i onGroup элемента <pe rmi s s ion>.

<instrumentation> Элемент <inst rument at i on> объявляет объект I n s t rumentation, которы й дает возможность контролировать взаимодействие приложения с системой . Обыч-

Page 62: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

54 Глава 4

но используется при отладке и тестировании приложения и удаляется из rе lеаsе-версии приложения .

<uses-sdk>

Элемент <us e s - sdk> позволяет объявлять совместимость приложения с ука­занной версией (или более новы ми версиями API) платформы Aпdroid . Уро­вень API , объявленный приложением, сравнивается с уровнем API системы мобильного устройства, на который инсталлируется данное приложение.

Основной используемый в элементе атрибут - rninSdkVe r s i on, определяющий минимальный уровень API, требуемый для работы приложения. Система Aпdroid будет препятствовать тому, чтобы пользователь установил приложе­ние, если уровень API системы будет ниже, чем значение, определенное в этом атрибуте. Вы должны всегда объявлять этот атрибут, например:

android : rninSdkVe r s i on= " З "

<uses-configuration>

Элемент <us e s - con f i gurat i on> указывает требуемую для nриложения аnпа­ратную и программную конфигурацию мобильного .устройства. Наnример, приложение могло бы определить требования обязательного наличия на уст­ройстве физической клавиатуры или USВ-порта. Спецификация использует­ся, чтобы избежать инсталляции приложения на устройствах, которые не поддерживают требуемую конфигурацию.

Если nриложение может работать с различными конфигурациями устройства, необходимо включить в манифест отдельные элементы <us e s - confi guration> для каждой конфигурации.

<uses-feature>

Элемент <us e s - feature> объявляет определенную функциональность, тре­бующуюся для работы приложения. Таким образом, приложение не будет установлено на устройствах, которые не имеют требуемую функциональ­ность .

Например, приложение могло бы определить, что оно требует камеры с авто­фокусом . Если устройство не имеет встроенную камеру с автофокусом, при­ложения не будет инсталлировано.

<supports-screens>

Элемент <suppo r t s - s creens > определяет разрешение экрана, требуемое для функционирования устройства (для старых версий Апdrо id-устройств). По

Page 63: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

Компоненты Апdrоid-приложения 55

умолчанию современное приложение с уровнем API 4 или выше поддержива­ет все размеры экрана и должно игнорировать этот элемент.

4. 7 . 2 . Структура элемента <application>

Элемент <appl icat ion> - это важный элемент манифеста, содержащий оnи­сание ком понентов приложения, доступных в пакете. Этот элемент содержит дочерние элементы, которые объявляют каждый из компонентов, входящих

н

н

н

---1 <meta-data> 1 <service> 1

---1 <intent-filter> 1 ---1 <meta-data> 1

<receiver> 1 ---1 <intent-filter> 1 ---1 <meta-data> 1

<provider> 1 -1 <grant-uri-permission> 1 -1 <path-permission> 1 -1 <meta-data> 1

} Оn_исание комnонентов

nриложения } Объявление деятельности

} Оnределе�ие тиnов намерении } Добавление действия для фильтра } Добавление категории для фильтра } Сnецификация данных фильтра } Пары "имя-значение" для nроизвольных данных } Псевдоним для деятельности

} Объявление службы

} Объявлен�е nриемника намерении

} Объявление контент-nровайдера } П редоставление разрешений для клиентов } Путь и разрешения для nоставляемых данных

<uses-libгary> 1 } Подключаемые библиотеки

Рис. 4.4. Структура элемента <appl icat ion>

Page 64: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

56 Глава 4

с состав приложения, описание и принципы работы которых были представ­лены в начале этой главы.

Структура элемента <app l i cat ion> и назначение его дочерних элементов представлена на рис. 4 .4 .

<activity>

Элемент <act ivity> объявляет деятельность. Все деятельности должны быть явно представлены отдельными элементами <activity> в файле манифеста, например:

< a c t i v i t y andro id : narne= " com . s arnples . he l loandroid . He l l oAndroid" androi d : label= " @ s t r ing / app _ narne " >,

где:

CJ andro i d : narne - имя класса. Имя должно включать полное обозначение пакета, но т. к. имя пакета уже определено в корневом элементе <man i fe s t >, имя класса, реализующего деятельность, можно записы вать в сокращенном виде, опуская имя пакета:

android : narne= " com . samples . he l l oandroid . He l loAndro id"

CJ androi d : labe l - текстовая метка, отображаемая пользователю.

Кроме вышеперечисленных, элемент <activity> содержит множество атрибу­тов, определяющих разрешения, ориентацию экрана и т. д.

Если приложение содержит несколько деятельностей, не забывайте объявлять их в манифесте, создавая для каждой из них свой элемент <act ivity>. Если деятельность не объявлена в манифесте, она не будет видна системе и не бу­дет запущена при выполнении приложения.

<intent-filter>

Элемент < intent - f i lter> определяет типы намерений, на которые могут от­ветить деятельность, сервис или приемник намерений . Фильтр намерений объявляет возможности его родительского компонента - что могут сделать деятельность или служба и какие типы рассылок получатель может обрабо­тать. Фильтр намерений предоставляет для компонентов-клиентов возмож­ность получения намерений объявляемого типа, отфильтровывая те, которые не значимы для компонента, и содержит дочерние элементы <act i on>, <category>, <data>.

<action>

Элемент <act ion> добавляет действие к фильтру намерений . Элемент < intent - f i l ter> должен содержать один или более элементов <ac t i on>. Если

Page 65: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

Компоненты Апdrоid-приложения 57

в элементе < intent - f i l t e r> не будет этих элементов, то объекты намерений не пройдут через фильтр. Пример объявления действия :

<action android : name= " android . int ent . act ion . МAIN " >

<category>

Элемент < cat egory> определяет категорию компонента, которую должно об­работать намерение. Это строкавые константы, определенные в классе I ntent, например:

<category androi d : name="android . int ent . category . LAUNCHER"

<data>

Элемент <data> добавляет спецификацию данных к фильтру намерений . Специ­фикация может быть только типом данных (атрибут mimeType) , URI или типом данных вместе с URI. Значение URI определяется отдельными атрибутами для каждой из его частей, т. е. URI делится на части : android : s cheme, android : host, android : po rt, android : path ИЛ И android : pathPre f ix, andro id : pathPa t t e rn.

<meta-data> •

Элемент <met a-da ta> определяет пару "имя-значение" для элемента дополни-тельных произвольных данных, которыми можно снабдить родительский компонент. Составляющий элемент может содержать любое число элементов <meta-data>.

<activity-alias>

Элемент <activi t y- a l ias> - это псевдоним для деятельности, определенной в атрибуте t a rgetAct ivity. Целевая деятельность должна быть в том же са­мом приложении, что и псевдоним, и должна быть объявлена перед псевдо­нимом деятельности в манифесте .

Псевдоним представляет целевую деятельность как независимый объект. У псевдонима может быть свой собственный набор фильтров намерений, оп­ределяющий, какие намерения могут активизировать целевую деятельность и как система будет обрабатывать эту деятельность.

Например, фильтры намерений на псевдониме деятельности могут опреде­лить флаги

andro id : name=" android . intent . action . МAI N "

и

android : name=" android . intent . category . LAUNCHER " ,

Page 66: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

58 Глава 4

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

<service>

Элемент < s e rvice> объявляет службу как один из компонентов приложения.

Все службы должны быть представлены элементом < s e rvice> в файле мани­феста. Службы, которые не были объявлены, не будут обнаружены системой и никогда не будут запущены. Этот элемент имеет много атрибутов, опреде­ляющих имя, доступность, разрешения, процесс и т. д.

<receiver>

Элемент <receive r> объявляет приемник широковещательных намерений как один из компонентов приложения. Приемники широковещательных намере­ний дают возможность приложениям получить намерения, которые переданы системой или другими приложениями, даже когда другие компоненты при­ложения не работают.

<provider>

Элемент <provide r> объявляет контент-провайдера. Все контент-провайдеры, которые являются частью приложения, должны быть представлены в элемен­

тах <provider> в файле манифеста. Если они не объявлены, они не будут ра­ботать, т. к . система их не сможет увидеть.

Элемент <provide r> содержит свой набор дочерних элементов для установле­ния разрешений доступа к данным :

CJ <g rant -uri-permi s s ion>;

CJ <path-permi s s i on>;

CJ <meta-data>.

Этот элемент имеет много атрибутов, определяющих имя, доступность, раз­решения, процесс и т. д.

<grant-uri-permission>

Элемент <g rant -uri -permi s s ion> - дочерний элемент для <provide r>. Он оп­ределяет, для кого можно предоставить разрешения на подмножества данных контент-провайдера. Предоставление разрешения является способом допус­тить к подмножеству данных, предоставляемым контент-провайдером, кли­ента, у которого нет разрешения для доступа к полным данным.

Page 67: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

Компоненты Апdrоid-приложения 59

Если атрибут g rantUri Permi s s ions контент-провай.цера имеет значение t rue, то разрешение предоставляется для любых данных, поставляемых контент­провайдером . Однако, если атрибут поставлен в false, разрешение можно предоставить только подмножествам данных, которые определены этим эле­ментом . Контент-провайдер может содержать любое число элементов <g rant -uri -permi s s i on>.

<path-permission>

Элемент <path-permi s s i on> - дочерний элемент для <provider>. Определяет путь и требуемые разрешения для определенного подмножества данных в пределах поставщика оперативной информации . Этот элемент может быть определен многократно, чтобы поставлять множественные пути.

<uses-library>

Элемент <use s - l ibrary> определяет общедоступную библ иотеку, с которой должно быть скомпоновано приложение. Этот элемент указывает системе на необходимость включения кода библиотеки в загрузчик классов для пакета приложения .

Каждый проект связан по умолчанию с библиотеками Aпdroid, в которые включены основные пакеты для сборки приложений (с классам и общего на­значения типа Act i vi ty, S e rvi ce, I ntent, View, But t on, App l i cation, Content Provider и т. д .) . Однако некоторые пакеты (например, maps и awt) на­ходятся в отдельных библиотеках, которые автоматически не компонуются с приложением . Если же приложение использует пакеты из этих библ иотек или других, от сторон них разработчиков, необходимо сделать явное связыва­ние с этим и библиотеками и манифест обязательно должен содержать от­дельный элемент <us e s - l ibrary>.

Page 68: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

Г Л А В А 5

Графически й и нтерфейс пол ьзователя

В Аndrоid-приложении графический интерфейс пользователя формируется с использованием объектов View (представление) и Vi ewGroup (группа пред­

ставлений) . Класс view является базовым классом для Vi ewGroup и состоит из

коллекции объектов View (рис. 5 . 1 ) . Есть множество типов представлений и

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

Рис. 5.1 . Иерархия классGв View и Vi ewGroup

Объекты View - основные модули отображения интерфейса пользователя на

платформе Android. Класс View служит ядром для подклассов, называемых виджетами, которые предлагают полностью реализованные объекты пользо­вательского интерфейса подобно текстовым полям, кнопкам и т. д. Объект

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

Объект View обрабатывает свою собственную геометрию, разметку, рисунок, изменение центра, прокрутку для прямоугольной области экрана, в котором он находится. Как объект в интерфейсе пользователя, объект view является точкой взаимодействия пользователя и программы .

Класс Vi ewGroup служит ядром для подклассов, называемых разметками

( layouts), которые формируют расположение элементов пользовательского интерфейса на форме, используя различные виды архитектуры разметки ­фреймовый, линейный, табличный и относительный .

Page 69: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

62 Глава 5

5.1 . Деревья п редставлений На платформе Android необходимо определить пользовательский интерфейс для каждой деятельности, используя иерархии узлов V i e w и Vi ewGroup, как показано на рис. 5 .2 . Это дерево иерархии может быть и просты м, и слож­ным - в зависимости от требований к графическому интерфейсу прило­жения .

View

View

View

View

View

View

View

Рис. 5.2. Пример дерева представлений для деятельности

При запуске программы система Aпdroid получает ссылку на корневой узел дерева и использует ее для рисования графического интерфейса на экране мобильного устройства. Система также анализирует элементы дерева от вер­шины дерева иерархии, прорисовывая дочерние объекты View и Vi ewGroup и добавляя их родительским элементам .

5.2 . Разметка Разметка, как было сказано, - это архитектура расположения элементов ин­терфейса пользователя для конкретного окна, представляющего деятель­ность . Она оnределяет структуру расположения элементов в окне и содержит все элементы, которые предоставляются пользователю nрограм мы. Разметку можно объявлять двумя способам и :

О объявить элементы пользовательского интерфейса в XML. Aпdroid обес­печивает прямой ХМL-словарь, которы й соответствует классам View и Vi ewGroup;

О создать разметку для окна в коде программы во время выпол нения -инициализировать объекты Layout и дочерние объекты View, ViewGroup и управлять их свойствами программно.

Page 70: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

Графический интерфейс пользователя 63

Aпdroid позволяет использовать кажды й из этих методов в отдел ьности или оба сразу для объявления и управления пользовательским интерфейсом в приложении . Например, можно объявить заданные по умолчанию разметки вашего приложения в XML, включая экранные элементы, которые поя вятся в них, и их свойства, а затем добавить код в вашем приложении, который во время выпол нения изменит состояние объектов на экране, включая объяв­ленные в XML.

АDТ-плагин для Ecl ipse предлагает удобный инструментарий - визуальный редактор разметки Layout Ed itor (рис . 5 .3 ), которы ?\ применяется для созда­ния и предварительного просмотра создаваемых файлов разметки, которые находятся в каталоге res/\ayout/ проекта.

([IDralerFr�er

!I) ExpandableL.stV . . .

[) Fr.nelayout

([]Gнdlr'rew

(ii] Hootont:aiScro/1 . . . Ш ImaqeSwltchвr

{jJLnearLo!Jyout

(G"j�'·<*.f!r.. . :·".;;:;;"f.:,. �Surfao:elr'tew

(2) V.ew

(!}VIewStuЬ

,В,.i AnalogCiock

@ AutoComplete Т . . . @Вutton

(Q CheckВox

. · ·1Т1 Т�ь���Оi - IIJ TableROV\/Ql (iableRow)

(ф &.tton01 (Suttort) J) Вutton02 (Вutt011) @ БuttonOЗ(Вutton)

,� 1!.) TableRow02 (To!!bleRow) IT 1 TableRowOЗ(T�Row) llJ Т �eP:ow04 (Т aЬieRow)

Рис. 5.3. Редактор разметки Layout Editor

Pfopertles

: · :�:· But.ton Auto lrnk BackQround Buffertype Cllck.,Ьie Cursor v1srbl

Dr�aЫe bottom Dra�1aЫeleft Drawable paddrnq DrawaЬie r'Qht DrawaЬie top

Dr awrng �ache qualr Dup/lcdte parent st< Edtor extras ERJI)srze Em<

FadtngedQe Fдdlng e1ge length Flts system wrndow·

Focusable FocusdЬie n touch r Freezes text Gravll:y

Haptrcfeedbackf'nc HerQht Hrnt

Самый общий способ определять разметку и создавать иерархию представле­ния - в ХМL-файле разметки . XML предлагает удобную структуру для раз­метки, похожую на НТМL-разметку WеЬ-страницы.

Преимущества объявления пользовательского интерфейса в ХМ L-файле со­стоит в том, что это дает возможность отделить представление приложения от программнога кода, который управляет поведением приложения . Ваше описание пользовател ьского интерфейса является внешним по отношению к программ ному коду, что означает, что вы можете изменять пользовател ьский интерфейс в файле разметки без необходимости изменения вашего про­грам многа кода.

Page 71: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

64 Глава 5

Например, вы можете создавать ХМL-разметки для различных ориентаций экрана мобильного устройства (portrait, landscape), размеров экрана и языков интерфейса. Дополнительно, объявление разметки в ХМL-файле облегчает возможность по визуализации структуры вашего пол ьзовательского интер­фейса, что упрощает отладку приложения.

Каждый элемент в XML является объектом View или ViewGroup (или его по­том ком) . Объекты View - листья в дереве, объекты ViewGroup - ветви (см. рис. 5 .3 , вкладка Outline) . Вы можете также создавать объекты View и ViewGroups в Jаvа-коде, используя метод addView (View) , чтобы динамически вставлять новые объекты View и ViewGroup в существующую разметку.

Используя различные виды групп представлений, можно структурировать дочерние представления и группы представлений многими способам и в зави­симости от требований к графическому интерфейсу приложения . Некоторые стандартные группы представлений, предлагаемые Android (называющиеся разметкам и), включают LinearLayout, Relat iveLayout, TaЬleLayout и др. (бу­дут подробно описаны позднее) . Кажды й из этих типов разметки предлагает уникальный набор параметров, которые используются, чтобы определить по­зиции дочерних представлений и структуру разметки на экране.

5.2 . 1 . Объя вление в XM L

Испол ьзуя ХМL-словарь Android, можно быстро проектировать пользова­тельский интерфейс разметки и экранные элементы, которые он содержит, тем же самым способом, которы м вы создаете WеЬ-страницы в HTML ­с рядом вложенных элементов.

Каждый файл разметки должен содержать только один корневой элемент, которы й должен быть объектом View или ViewGroup. Как только вы определи­ли корневой элемент, вы можете добавить дополнительные объекты разметки или виджеты как дочерние элементы, чтобы постепенно форм ировать иерар­хию элементов, которую определяет создаваемая разметка.

Самый простой способ объяснять эту концепцию состоит в том, чтобы пока­зать образец. Например, вот этот ХМL-файл разметки приложения "Hel lo, Android ! " из главы 3 (листинг 5 . 1 ) .

< ?xrnl ve rsion=" l . O " encoding="utf- 8 " ?>

<LinearLayout xrnlns : android= "http : / /schemas . android . com/apk/ res /android"

android : orientation="vertica l "

android : layout_width= " fill_parent "

android : layout_height=" fi l l_parent " >

Page 72: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

Графический интерфейс пользователя 65

<TextView

android : id= " @ +id/TextViewO l "

android : layout_

width= " fill_

pa rent "

android : layout_

he ight= "wrap_

content "

android : text=" @ st ring /hel l o " >

< /TextView>

< /LinearLayout>

Общая структура ХМ L-файла разметки проста: это - дерево ХМL­элементов, где каждый узел представляет имя класса View (в нашем примере только один элемент View - TextView) . Вы можете использовать имя любого класса, производнога от класса View, как элемент в ХМL-разметках, включая ваши собственные классы . Эта структура позволяет быстро создавать пользо­вательский интерфейс, используя более простую структуру и синтаксис, чем при создании разметки в программнам коде .

5.2 .2 . ХМ L-элементы и атрибуты

В вышеупомянутом ХМL-примере есть корневой элемент <Linea rLayout> и только один дочерний элемент View . TextView (текстовое поле), который име­ет атрибуты . Описание того, что эти атрибуты означают, дается в табл . 5 . 1 .

Таблица 5. 1 . Назначение некоторых ХМL-атрибутов в файле разметки

Имя атрибута XML Описание

xmlns : android Декларация простра нства имен XML, которая сообщает ере-де Aпdroid, что вы ссылаетесь на общие атрибуты, опреде-ленные в пространстве имен Aпd roid . В каждом файле раз-метки у корневого элемента должен быть этот атрибут со значением

"http : / / s chemas . android . com/ apk/ re s /android"

android : l ayout_width Этот атрибут определяет, скол ько из доступной ширины на экране должен использовать этот объект View (или Vi ew-Group) . В нашем случае он - еди нственный объект, таки м образо м , можно растянуть его на весь экра н , которому в дан-нам случае соответствует значение f i l l_parent

android : l ayout_he ight Аналогично android : l ayout_width, за искл ючением того, что он ссылается на доступ ную высоту экрана

android : text Устанавливает текст, который должен отобразить Textview. В этом при мере используется строкавый ресурс вместо жест-ко закодирован ного строкового значения . Строка he l lo опре-деле на в файле гes/values/stгi ngs.xm l . Это рекомендуемая nрактика для использования Строковых ресурсов в ваших n риложен иях, потому что она делает локализацию приложе-ния на другие языки более n ростой , без потребности кодиро-вать наnрямую изменения в файле разметки

Page 73: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

66 Глава 5

Каждый объект view и viewGroup поддерживает свое собственное разнообра­зие ХМL-атрибутов . Некоторые атрибуты являются определенными только в объекте View (например, TextView поддерживает атрибут t ext S i z e) , но эти ат­рибуты могут также наследоваться любым и объектами View, которые расши­ряют этот класс. Некоторые атрибуты являются общими ко всем объектам View, потому что они унаследованы от корневого класса view (подобно атри­бутам id, layout_wi dth, layout_he ight) .

В общем, ХМL-словарь элементов пользовательскогu интерфейса близок к структуре классов и методов этих элементов, где имя элемента соответствует имени класса, а атрибуты элемента - методам этого класса. Фактически, со­ответствие является часто настолько точным, что легко предполо)кить без обращения к документации Aпdroid, какой ХМL-атрибут передает метод класса или, наоборот, какой метод класса соответствует конкретному ХМ L­элементу.

Так, например, элемент <TextView> создает текстовое поле тextView в вашем пользовательском интерфейсе, а элемент <LinearLayout> создает группу пред­ставления Linea rLayout . Когда вы загружаете ресурс разметки, система Aпdroid инициализирует эти объекты во время выполнения, соответствуя элементам в разметке. Однако обратите внимание на последнюю строку в табл . 5 .2 : не весь ХМL-словарь идентичен структуре классов.

Таблица 5. 2. Соответствие ХМL-атрибутов и методов в классах представлений

Имя атрибута XML Соответствующий метод в классе Java

android : gravi t y setGravi t y ( int )

android : height setHeight ( int )

android : t ext setText ( CharSequence )

android : textColor setTextCol or ( ColorStateLi st )

android : t ext S i ze setтextS i z e ( f l oat )

android : width setWidth ( int )

android : t extColorHighlight setHighl ightColor ( i nt )

Любой объект View в коде программы можно связать с объектом из файла разметки, однозначно определив элемент пользовател ьского интерфейса в пределах дерева. Когда приложение откомпилировано, на этот идентифика­тор ссылаются как на целое число, но идентификатор представления обычно обозначается в ХМ L-файле разметки как строка в атрибуте id. Синтаксис для идентификатора элемента в ХМL-теге следующий :

and roid : id= " @ + id/TextViewO 1 " ,

Page 74: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

Графический интерфейс пользователя 67

где символ @ в начале строки указывает, что синтаксический анал изатор XML должен проанализировать и развернуть остальную часть строки иден­тификатора и определить это выражение как ресурс идентификатора. Символ + означает, что это - новое имя ресурса, которое должно быть создано и до­бавлено к нашим ресурсам в файл R.java, который среда Aпdroid автоматиче­ски генерирует для проекта, как показано в листинге 5 .2 .

puЬlic final class R

puЬl ic static final class id puЫ ic static final int TextView01=0x7 f05 0 0 0 0 ;

Если в программ нам коде мы не работаем с некоторыми элементами пользо­вательского интерфейса, создавать идентификаторы для них необязательно, однако определение идентификаторов для объектов представления важно при создании Relat iveLayout (относительной разметки) . В Re lativeLayout распо­ложение представлений может определяться относительно другого представ­ления, на которое ссылаются через его уникал ьный идентификатор:

android : layout_toLe ftOf= " @ id/ TextViewO l "

Подробнее работа с о ссылками н а идентификаторы элементов будет рассмот­рена в разд. 5. 4. 4.

Требование к уникал ьности идентификаторов не распространяется на все де­рево представлений, но они должны быть уникальны в пределах части дерева (которая часто может быть и полным деревом представлений, так что лучше создавать полностью уникальные идентификаторы, если это возможно).

5.3 . И н и циал изация п редставлени й При запуске деятельности система должна получить ссылку на корневой узел дерева разметки, который будет использоваться для прорисовки графическо­го интерфейса на экране мобильного устройства. Для этого в методе onCreate ( ) необходимо вызвать метод s etContentView ( ) , передав ему в каче­стве параметра ссылку на ресурс разметки в следующем виде :

R . layout . layout_file_name

Например, если ваша ХМL-разметка сохранена как maiп .xm l, вы загружаете разметку для Act ivity примерно так (листинг 5 .3) .

Page 75: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

68

@Override puЫic void onCreate ( Bundle savedinstanceState )

super . onCreate ( savedinstanceStat e ) ;

setContentView ( R . layout . main ) ;

Глава 5

Прорисовка начинается с корневого узла дерева разметки . Затем последова­тельно прорисовываются дочерние представления дерева разметки. Это озна­чает, что родители будут прорисовываться раньше, чем их дочерние пред­ставления, - т. е. по окончании процесса прорисовки родители будут нахо­диться на заднем плане по отношению к дочерним узлам .

5.4. Стандартн ые разметки Существуют следующие стандартные типы разметок, которые вы можете ис­пользовать в создаваемых приложениях:

r:J FrameLayout;

r:J LinearLayout;

r:J TaЫeLayout;

r:J Relati veLayout.

Подобно всем разметкам, все они являются подклассами ViewGroup (рис. 5 .4) и наследуют свойства, определенные в классе View.

Framelayout

Relativelayout

� �·-, -Ta-b-le-La

_y_ou

-t'l Рис. 5.4. Иерархия классов разметок

5.4. 1 . FrameLayout

FrameLayout является самым простым типом разметки . Это в основном пустое пространство на экране, которое можно позже заполнить только единствен-

Page 76: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

Графический интерфейс пользователя 69

ным дочерним объектом View или viewGroup. Все дочерние элементы FrameLayout прикрепляются к верхнему левому углу экрана.

Чтобы поработать с разметкой " вживую", создайте в Ecl ipse новый проект и в диалоговом окне New Android Project введите следующие значения :

О Project name - FrameLayoutApp;

g Application name - FrameLayout Sample;

О Package name - com . samples . framelayout;

О Create Activity - FrameLayoutAct ivity.

Откройте файл main.xml и создайте разметку, как в листинге 5 .4 . Разметку можнс создавать, используя Layout Editor, или вручную, написав ХМL-код, приведенный в листинге.

<?xrnl ve rsion= " l . O " encoding= "ut f- 8 " ?>

<FrameLayout xmlns : android= "http : / / schemas . android . com/apk/ res /android"

android : id=" @ +id/FrameLayoutO l "

android : layout_height= "wrap_content "

android : layout_width= " t'i ll_parent ">

<Button android : text= " @ +id/ButtonO l "

android : id=" @ +id/ButtonO l "

android : layout_width="wrap_content "

android : layout_height="wrap_content " />

< / FrameLayout>

Запустите проект на выполнение. Внеший вид экрана с разметкой FrameLayout

должен получиться таким, как на рис. 5 . 5 .

В разметке FrameLayout нельзя определить различное местоположение для дочернего объекта View. Последующие дочерние объекты View будут просто рисоваться поверх предыдущих 'представлений, частично или полностью за­теняя их, если находящийся сверху объект непрозрачен, поэтому единствен­

ный дочерний элемент для FrameLayout обычно растянут до размеров роди­тельского контейнера и имеет атрибуты :

android : layout_width= " fi l l_parent "

android : layout_height= " fi l l_parent "

Page 77: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

70 Глава 5

Рис. 5.5. Разметка Frame Layout с од ним и д вумя дочерними элементами

5.4.2 . LinearLayout

Разметка Linea rLayout выравнивает все дочерние объекты nредставлений в одном наnравлении - вертикально ил и горизонтал ьно, в зависимости от то­го, как оnределен атрибут ориентации android : orient a t ion:

android : o r ient a t i on= " ho r i zont a l "

или

andro i d : o r i entat ion="vert i ca l "

Все дочерние заnиси nомещаются в стек один за другим, так что вертикаль­ный сnисок nредставлений будет иметь только один дочерний элемент в строке независимо от того, насколько широким он является . Горизонтальное расnоложение сnиска будет размещать элементы в одну строку с высотой, равной высоте самого высокого дочернего элемента сnиска.

Для nримера окна с линейной разметкой создайте новый nроект и в диалого­вом окне New Android Project введите следующие значения :

О Project name - Linea rLayout Арр;

О Application name - Line a r Layout S ample;

О Package name - сот . s amp l e s . l ine a r l ayou t ;

О Create Activity - LinearLayout Act i v i t y .

Page 78: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

Графический интерфейс пользователя 71

Далее в файле res/layout/main .xml создайте LinearLayout с тремя дочерними кнопками, как показано в листинге 5 . 5 .

< ?xml vers ion= " l . O " encoding="ut f- 8 " ?> <LinearLayout xmlns : android="http : / /schernas . android . com/apk/res/android"

android : id= " @ + id/LinearLayout O l " android : layout_width= " fi l l_parent " android : layout_height= " fi l l_parent " android : orientation="hori z ontal " >

<Button

<Button

<Button

android : id=" @ +id/buttonl " android : layout_width= "wrap_content" android : layout_height= "wrap_content " android : text="ButtonO l " />

android : id=" @ + id/button2 " android : layout_width= "wrap_content "

android : layout_height= "wrap_content " android : text=" Button02 " />

android : id= " @ +id/buttonЗ "

android : layout_height= "wrap_content " android : layout_width= " fi l l_parent " android : text="ButtonO З " />

</ LinearLayout>

Обратите внимание, что у первых двух кнопок атрибуту android : layout_width

присвоено значение wrap _ content, а у третьей кнопки - fi l l_parent, т. е . по­следняя кнопка заполнит оставшееся свободное пространство в разметке .

В результате поЛучится линейное горизонтальное размещение дочерних эле­ментов . Если изменить в корневом элементе значение атрибута andro­

id : layout_height:

android : orientat ion="vertical ",

элементы в контейнере расположатся вертикально. В нешний вид экрана для разметки Linea rLayout с горизонтальной и вертикальной ориентациями эле­ментов показан на рис. 5 .6 .

Разметка Linea rLayout также поддерживает атрибут andr<;>id : layout_we ight,

который назначает индивидуальный вес для дочернего элемента. Этот атри-

Page 79: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

72 Глава 5

бут оnределяет "важность" nредставления и nозволяет этому элементу рас­ширяться, чтобы заnолнить любое оставшееся nространство в родительском представлении . Заданный по умолчанию вес является нулевым .

Рис. 5.6. Разметка LinearLayout с горизонтальной и верти кал ьной ориентация м и элементов

Например, есл и есть три текстовых nоля, и двум из них объявлен вес со зна­чt:,нием 1 , в то время как другому не дается никакого веса (0), третье тексто­вое nоле без веса не будет расширяться и займет область, оnределяемую раз­мером текста, отображаемого этим полем . Другие два расширятся одинаково, чтобы заполнить остаток пространства, не занятого третьим nолем . Если третьему nолю присвоить вес 2 (вместо 0), это поле будет объявлено как "бо­лее важное", чем два других, так что третье поле nолучит 50% общего nро­странства, в то время как первые два получат по 25% общего nространства.

Для nримера nриложения с разметкой Linea rLayout для окна и размещением на ней компонентов с разным " весом" создайте новый nроект и в диалоговом окне New Android Project введите следующие значения :

О Project name - Linea rLayoutWe ightApp;

О Application name - TaЫeLayout S amp l e ;

О Package name - сот . sampl e s . t aЫ e l ayou t ;

О Create Activity - TextVi ewAct i v i t y .

Page 80: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

Графический интерфейс пользователя 73

Далее в файле res/layout/main .xml создайте LinearLayout с тремя дочерними

виджетами Editтext, как показано в листинге 5 .6 .

< ?xrnl ve rs ion= " l . O " encoding="ut f- 8 " ?>

<LinearLayout xrnlns : android="http : 1 /schernas . android . com/apk/ res/android'�

android : id=" @ +id/ LinearLayoutO l "

android : layout_width= " fil l_parent "

android : layout_height= " fi l l_parent "

android : orientation= "horizontal " >

<EditText

android : id=" @ + id/EditTextO l "

android : layout_width="wrap_content "

android : layout_height= "wrap_content "

android : text="EditTextO l "

android : layout_weight= " O " />

<EditText

android : id= " @ +id/EditText0 2 "

android : layout_width="wrap_content "

android : layout_he ight="wrap_content "

android : layout_we ight=" l "

android : text= "EditText02 " / >

<EditText

android : id=" @ + id/EditText O З "

android : layout_width= "wrap_content "

android : layout_he ight= "wrap_content "

android : layout_weight=" 2 "

android : text= "EditText O З " />

< / LinearLayout>

Внешний вид экрана и влияние атрибута android : layout _ weight По казаны на рис. 5 .7 .

Обратите внимание, как различные атрибуты XML определяют поведение представления . Попробуйте поэкспериментировать с различными значениями layout_weight для дочерних элементов, чтобы увидеть, как будет распреде­ляться доступное пространство для элементов.

Page 81: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

74 Глава 5

Рис. 5.7. Отображение элементов с различными значениями and r o i d : layout _ we i ght

5.4.3. TaЬ/eLayout

Разметка тaЬle Layout nозиционирует свои дочерние элементы в строки и столбцы . тaЬl eLayout не отображает линии обрамления для их строк, столб­цов или ячеек. тaЫeLayout может иметь строки с разным количеством ячеек. При формировании разметки таблицы некоторые ячейки nри необходимости можно оставлять nустыми .

При создании разметки для строк исnользуются объекты TaЬleRow, которые являются дочерними классами TaЬleLayout (каждый TaЬ leRow оnределяет единственную строку в таблице). Строка может не иметь ячеек или иметь од­ну и более ячеек, которые являются контейнерами для других объектов View

или Vi ewG roup. Ячейка может также быть объектом ViewGroup (наnример, до­nускается вложить другой TaЬle Layout или LinearLayout как ячейку).

Создайте новый nроект и в диалоговом окне New Android Project введите следующие значения :

D Project name - TaЬleLayoutApp;

D Application name - TaЬleLayout S ample;

D Package name - сот . s ampl e s . taЬl e l a yout;

D Create Activity - TaЬleLayoutAc t ivi t y.

Page 82: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

Графический интерфейс пользователя 75

Далее создайте тaЬleLayout с четырьмя дочерними TaЬleRow и двенадцатью кнопками, по три кнопки в каждой строке.

Для каждого элемента TaЬleRow на вкладке Properties задайте свойства:

О Layout height - wrap _ content;

О Layout width - fil l_parent;

О Gravity - center.

Свойство gravity задает выравнивание дочерних элементов в контейнере, в данном случае - по центру.

Для каждой кнопки на вкладке Properties задайте свойства:

О Layout height - wrap _ content;

О Layout width - 2 0pt.

Надписи на кнопках сделайте, как на телефонной клавиатуре ( 1 , 2, 3, 4, 5, 6, 7, 8, 9, * , О, #) . В результате должна получиться структура дерева представле­н ий, как показано на рис . 5 . 8 .

. .. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . , . . . , = EJ i ' );> + - · ' t ...

· · · · · · · ·ш тaьieL�v�utoi <т�elay�ut) ·· · ·· · · · · · ·· · · 1 с;:. [) TaЬieRowO I (TaЬieRow)

® ButtonOI (Button)

® Button02 (Button)

® ButtonOЗ (Button)

[) TaЬieRow02 (TaЬieRow)

® Button04 (Button)

® Button05 (Button)

® ButtonOб (Button)

[) TaЬieRowOЗ (TaЬieRow)

® Button07 (Button)

· ·® Button08 (Button)

® Button09 (Button)

[) TaЬieRow04 (TaЬieRow)

® Button ! O (Button)

® Buttonl l (Button)

® Button 1 2 (Button)

Рис. 5.8. Дерево представлений для разметки TaЬleLayout

Файл разметки должен получиться таким, как в листинге 5 . 7 .

< ?xml version=" l . O " encoding="utf-8 " ?>

<TableLayout xmlns : android="http : / /schemas . android . com/apk/ res /android" android : id=" @+id/TableLayout O l "

Page 83: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

76

android : layout_width= " fi l l_parent "

android : layout_height= " fi l l_parent " > <TaЬleRow

android : id= " @ + id/TaЬleRowO l "

android : layout_height= "wrap_content " android : layout_width= " fi l l_parent " android : gravity=" center"> <Button

android : id= " @ +id/ButtonO l " android : layout_height="wrap_content " android : text= " l " android : layout_width= " 2 0pt " />

<Button

android : id= " @ +id/Button02 " android : layout_height="wrap_content "

android : text= " 2 "

android : layout_width= " 2 0pt " /> <Button

android : id= " @ +id/ButtonO З " android : layout_height="wrap_content " android : text= " З " android : layout_width=" 2 0pt " / >

< /TaЬleRow> <TaЬleRow

android : id= " @ + id/TaЬleRow02 "

android : layout_height= "wrap_content "

android : layout_width= " fi l l_parent "

android : gravity=" cente r " > <Button

android : id=" @ + id/Button0 4 " android : layout_height="wrap_content " android : layout_width= " 2 0pt " android : text= " 4 " / >

<Button

android : id= " @ +id/Button0 5 " android : layout_height="wrap_content "

android : layout_width= " 2 0pt "

android : text= " S " /> <Button

android : id= " @ +id/Button0 6 "

android : layout_height="wrap_content " android : layout_width= " 2 0pt " android : text= " б " / >

< /TaЬleRow>

Глава 5

Page 84: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

Графический интерфейс пользователя

<TaЬleRow

android : id=" @ + id/TaЬleRowOЗ "

android : layout_height="wrap_content "

android : layout_width=" fi l l_parent "

android : gravity=" center">

<Button android : id= " @+id/Button07 "

android : layout_height="wrap_content "

android : layout_width= " 2 0pt "

android : text= " 7 " />

<Button

android : id=" @+id/ButtonO B , ;

android : layout_height="wrap_content "

android : layout_width= ".2 0pt " android : text= " B " />

<Button

android : id= " @ +id/Button 0 9 "

android : layout_height="wrap_content "

android : layout_width= " 2 0pt "

android : text= " 9 " />

< /TaЬleRow>

<TaЬleRow

android : id= " @ +id/TaЬleRow0 4 "

android : layout_height= "wrap_content "

android : layout_width= " fi l l_parent "

android : gravity= " center "

<Button

android : id= " @ +id/Button l O "

android : layout_height="wrap_content "

android : layout_width= " 2 0pt "

android : text=" * " />

<Button

android : id=" @ + id/Buttonl l "

android : layout_height="wrap_content "

android : layout_width=" 2 0pt "

android : text= " O " / >

<Button

android : id= " @ +id/Button l 2 "

android : layout_hei ght="wrap_content "

android : layout_width= " 2 0pt "

android : text= " # " / > < /TaЬleRow>

</TaЬleLayout>

77

Page 85: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

78 Глава 5

Запустите проект на выполнение. Внешний вид экрана с разметкой TaЬleLayout должен получиться в виде телефонной клавиатуры, как на рис. 5 .9 .

Рис. 5.9. При мер разметки TableLayout

5.4.4. RelativeLayout

Re lati veLayout (относител ьная разметка) позволяет дочерним представленн­ям определять свою позицию относительно родительского представления или относительно соседних дочерних элементов (по идентификатору элемента).

В Re lat iveLayout дочерние элементы расположены так, что есл и первый эле­мент расположен по центру экрана, другие элементы, выровненные относи­тельно первого элемента, будут выровнены относительно центра экрана. При таком расположении , при объявлении разметки в ХМ L-файле, элемент, на которы й будут ссылаться для пози ционирования другие объекты представле­н ия, должен быть объявлен раньше, чем другие элементы, которые обраща­ются к нему по его идентифи катору.

Создайте новый проект и в диалоговом окне New Android Project введите следующие значения :

D Project name - Re l a t iveLayoutApp;

D Application name - Re lativeLayout S ample;

Page 86: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

Графический интерфейс пользователя

О Package name - сот . samples . relativelayout;

О Create Activity - RelativeLayoutActivity.

В файле разметки напишите код, как показано в листинге 5 . 8 .

<?xml version= " l . O " encoding= "ut f- 8 " ?> <Relat iveLayout xmlns : android= "http : / / s chemas . android . com/apk/ res /android"

android : layout_height= " fil l_parent " android : layout_width=" fill_parent " >

<Button android : id=" @ +id/button center " android : text= "Cente.r" android : layout_width="wrap_content " android : layout_height="wrap_content" android : layout_centerVertical= " t rue " android : layout_centerinParent= " t rue " / >

<Button android : id= " @ +id/button_bottom" android : layout_width="wrap_content " android : layout_height="wrap_content " android : text= "Bottom" android : layout_centerHori zontal= " t rue " android : layout_al ignParentBottom= " t rue " />

<Button android : id= " @ +id/button_top " android : layout_width= "wrap_content " android : layout_height="wrap_content " android : text= "Top" android : layout_alignParentTop= " t rue " android : layout_centerHori zontal= "true " />

<Button android : id= " @ +id/button left " android : layout_width= "wrap_content " android : layout_height="wrap_content " android : text= " Left " android : layout_alignParentLeft="true " android : layout_centerVertical= " t rue " />

<Button android : id=" @ +id/button_right " android : layout_width= "wrap_content "

android : layout_he ight= "wrap_content "

79

Page 87: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

во

android : text="Right " android : layout_alignParentRight="true " android : layout_centerVert ical="true " / >

<Button android : id= " @ + id/button_re l right " android : layout_width="wrap_content " android : layout_height="wrap_content" android : layout_toLe ftOf= " @ id/button_right " android : layout_alignTop= " @ id/button_right " android : text="RelRight " / >

<Button android : id= " @ + id/button rel left " android : layout_width= "wrap_content " android : layout_height= "wrap_content " android : layout_toRightOf=" @ id/button_left " android : layout_alignTop= " @ id/button_left" android : text= "RelLeft " />

Глава 5

< /RelativeLayout>

0БРА ТИТЕ ВНИМАНИЕ

Атрибуты , которые обращаются к идентификаторам относительных элементов (например , layout _ toLe ftOf) , испол ьзуют синтаксис относительного ресурса @ id/ id.

Рис. 5. 1 0 . Пример разметки RelativeLayout

Page 88: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

Графический интерфейс пользователя 81

Запустите проект на выполнение. Внешний вид экрана с разметкой

Re lat i veLayout должен получиться, как на рис. 5 . 1 О.

5.5 . Отладка и нтерфейса с помощью H ierarchy Viewer В состав Android SDK входит утилита Hierarchy Viewer - полезный инстру­мент при разработке окон со сложной разметкой (рис. 5 . 1 1 ) . Он позволяет отлаживать и оптим изировать пользовательский интерфейс приложений . Hierarcl1y Viewer отображает визуальное представление иерархи и представ­лений создаваемой разметки и экранную лупу для просмотра пиксельной структуры разметки экрана мобильного устройства - Pixel Perfect V iew.

Fifo Vlew ��re;hv Ser'Ver stop Server R.efтesh �s !..мd 'J�ew H&rмchy DISJ)I&yY�ew lnv�Мat:e Request liiiVO\.t

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ,г·�-.. . .

20%

���:���-:�:���:· :.:���:�:-:������:-:i�-�����:��r-·:: ---

���:��-�-�-- .. '-�*-S"'I_·an�r-�:1 r .L<!!uncher ���:_s_�l :. · liiN�-L-�y�t�t��t� ·

j������-�?-� ... ��-��- - - - : . ;Tr�klnQVI j��:����������:::: :: :··· · ..

�statusВillr tiёY'9UNd--l . . . .. .

!

Рис. 5 . 1 1 . Инструмент H ierarchy Viewe r

Для запуска Hierarchy Viewer необходимо выполнить следующие действия :

D подключить свое мобильное устройство или запустить эмулятор;

D запустить файл hierarchyviewer.bat из каталога tools/ в Aпdro id SDK. В от­крывшемся окне появится список Апdrоid-устройств . При выборе устрой­ства в окне справа отображается список активных окон . Окно <Focused

11'/indow> в списке является окном мобильного устройства, находящимся в данный момент в фокусе, а также заданным по умолчанию окном мобиль-

Page 89: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

82 Глава 5

ного устройства, загружаемым в окно Layout View утил иты H ierarcl1y Viewer;

О выбрать нужное окно для отладки и нажать кнопку Load View Hierarchy. Откроется окно Layout View. После этого при необходимости можно за­грузить окно Pixel Perfect View, нажимая второй значок в левой нижней части окна Layout View.

ПРИМЕЧАННЕ

П ри выборе другого окна на устройстве необходи мо нажать кноп ку Refresh Windows , чтобы обновить сп исок доступ н ых окон устройства в пра вой части .

5 .5 . 1 . Layout View

Окно Layout View отображает иерархию разметки и ее свойства. У окна есть три панели :

О Tree View - дерево представлений ;

О Properties View - список свойств выбранного представления ;

О Wire-frame View - каркас разметки .

Fkl V11J1N Нll!fNC Setv«' ........ . . . . . ···-�-��--�����-�--��-��'ile!WiietW'Iy �у\1� Y�doto R�st\Ayout

'"''" ] -��-1

�::---' ·:��dl•� l od.'\Uiqoo_«'ll !

\ · r•it�Ja.l�� ' od.t.ll'\111\_� .. "

Рис. 5.1 2. Окно Layout View утилиты Hierarchy Viewer

Page 90: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

Графический интерфейс пользователя 83

На рис. 5 . 1 2 показано окно Layout View с загруженным проектом RelativeLayoutApp из разд. 5. 5. 4.

Для отображен,ия свойств представления на панели Properties View необхо­димо выбрать элемент в дереве разметки на панели Tree View. При выборе элемента на панели Wire-frame View будут в красном прямоугол ьнике пока­заны границы этого элемента. Двойной щелчок на узле дерева разметки от­крывает новое окно с рендерингом этого элемента.

Окно Layout View вкл ючает пару других полезных опций отладки создавае­мой разметки - Invalidate и Request Layout. Эти кнопки на панели инету­ментов вызывают соответственно методы inval idate ( ) и reques tLayout ( ) для выбранного элемента представления .

ПРИМЕЧАНИ Е

Есл и вы поменяете выбран н ы й объект, то Layout View не будет автоматически его обновлять . Вы должн ы перезагрузить Layout View, нажимая кнопку Load View H ierarchy .

5.5 .2 . Pixel Perfect View

Окно Pixel Perfect View обеспечивает экранную лупу для детального про­смотра разметки. У этого окна есть три панели :

О Explorer View - показывает иерархию представления;

О Normal View - нормальное представление окна устройства;

О Loupe View - увел иченное nредставление пиксельной архитектуры экра-на устройства.

Панель схемы разметки использует множественные прямоугольники для ука­зания нормальных границ, дополнений (padding) и краев (margin) . Фиолето­вый или зеленый прямоугольник указывает нормальные границы - высота и ширина элемента. В нутренний белый ил и черный nрямоугольник указывает границы информационного наnолнения, когда в элементе установлено до­полнение (paddiпg). Черный ил и белый nрямоугольник вне нормального фио­летового ил и зеленого nрямоугольника указывает любые существующие края (margiп) .

Очень удобной особенностью проектирования nользовател ьского интерфейса является способность накладывать доnолнител ьное изображение в Normal Views и Loupe Views. Наnример, у вас могло бы быть изображение макета разметки или отдельного nредставления, которую вы хотел и бы nрименить в разрабатываемом пользовательском интерфейсе. Нажав кноnку Load внизу nанели в Normal Views, можно загрузить изображение макета с ком nьютера. Выбранное изображение nрикреnится в углу левой нижней части экрана. Вы

Page 91: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

84 Глава 5

можете корректировать непрозрач ность оверлея и подстраивать разрабаты­ваемую разметку для соответствия макету.

-�·- � -��� �--'.�<�;· .. .;. · stop Ser.oer Rehesh Wt"ldow$ � I.�V!eW i'lor«d'>)l DlsployVItw ltd«:e RaQUOstLayout

Llnearlayoul: U Fra•п•!:L.syout

• Yextvtew �J Fr4tl'lel-wcut

: ";..,) Relat•velaycкt • Вuttcn • Вul.tCil • Butta'l • Вutton • Вul.ta'l • Вvt.tm • Elul.ta'l

Рис. 5. 1 3. Окно Pixel Perfect View утилиты Hiera rchy Viewe r

ПРИМЕЧАННЕ

Изображен ия экрана устройства на панелях Normal View и Loupe Views об­новля ются через равномерные п ромежутки времен и (5 секунд по умолчан ию) , но панель Explorer View а втоматических обновлен и й не п роизводит. Необхо­димо вручную обновлять содержимое Explorer View, нажимая кноп ку Load View H ierarchy.

Page 92: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

Г Л А В А 6

Базовые виджеты

Виджет - это объект View, который служит интерфей�ом для взаимодейст­вия с пользователем. Говоря простым языком, виджеты - это элементы управления . Aпdroid обеспечивает набор готовых вv.джетов, таких как кноп­ки, переключател и и текстовые поля, с помощью которых можно быстро сформировать пол ьзовательский интерфейс приложения .

6 . 1 . Текстовые поля Текстовые поля в Aпdroid представлены двумя классами :

О TextView;

О Edi tText .

В иджет тextview предназ·начен для отображения текста без возможности ре­дактирования его пользователем . Есл и необходимо редактирование текста,

испол ьзуется виджет EditTex t .

Классы TextView и Edi tText и меют множество атрибутов и методов, насле­дуемых от класса View, который был рассмотрен в предыдущей главе. Иерархия классов текстовых полей представлена на рис. 6 . 1 .

TextView EditТext

Рис. 6 .1 . Иерархия классов текстовых полей

Page 93: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

86 Глава 6

6 . 1 . 1 . TextView

Виджет Textview - самы й простой и в то же время один из сам ых исполь­зуемых в приложениях виджетов . тextView служит для представления nол ьзо­вателю оnисательного текста. Текст может иметь отношение к другому эле­менту уnравления л ибо к текущему состоянию системы. Кроме того, элемент TextView исnользуется как элемент для отображения текстовых данных в кон­тейнерных виджетах-сn исках.

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

Для отображения текста в TextView в файле разметки исnользуется атрибут

android : text, например :

android : text="Hello , Android ! "

В программнам коде текст задается методом setText ( ) :

за гружаем видже т и з ре сурсов

TextView text ( TextView ) findViewByid ( R . id . textЗ ) ;

1 1 задаем текст непосредств енно в коде программы

text . setText ( "He llo , Android ! " ) ;

Есл и планируется создание приложения с м ногоязыковой поддержкой поль­зовател ьского и нтерфейса, вместо непосредственного задания текста в ХМL­разметке ил и в коде программы необходимо создать ссылку на текстовый XML-pecypc:

android : text= " @ string /text_hello" ,

где text _ hello - имя ресурса.

В коде программ ы ссылка на XML-pecypc задается методом setText ( ) , кото­рый принимает ссылку на идентификатор ресурса, определенного в файле R.java (автоматически сгенерированным средой разработки), например:

TextView text ( TextView ) findViewByid ( R . id . text ) ;

1 / задаем текст из ресурсов

text . setText ( R . string . text_he llo ) ;

У элемента тextView есть многочисленные методы и ХМ L-атрибуты для ра­боты с текстом. Например, основные ХМL-атрибуты, отображающие свойст­ва элемента TextView:

D android : textSi ze - размер текста. При установке размера текста исполь­зуются несколько единиц измерения :

• рх (pixel s) - пикселы ;

Page 94: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

Базовые виджеты 87

• dp (density- i ndependent p ixels) - независимые от плотности пикселы. Это абстрактная единица измерения, основанная на физической плот­ности экрана;

• sp (scale- independent p ixels) - независимые от масштабирования пик­селы;

• i n ( i nches) - дюймы, базируются на физических размерах экрана;

• pt (points) - 1 /72 дюйма, базируются на физических размерах экрана;

• mm (mi l l imeters) - миллиметры, также базируются на физических раз­мерах экрана.

Обычно при установке размера текста используются един ицы измерения sp , которые наиболее корректно отображают шрифты, например:

android : textSi ze= " 4 Bsp";

О android : text Style - стиль текста. Используются константы :

• norma l ;

• bold;

• italic .

Пример установки стиля через атрибуты :

• android : textStyle= "bolct";

О android : textColor - цвет текста. Используются четыре формата в шест­надцатеричной кодировке:

• #RGB;

• #ARGB;

• #RRGGBB;

• #AARRGGBB;

где R, G, в - соответствующий цвет, А - прозрачность (alplш-channel) . Значение А, установленное в О, означает прозрачность 1 00%. Значение по умолчанию, без указания значения alpha, - непрозрачно.

Для всех вышеперечисленных атрибутов в классе TextView есть соотв'етст­вующие методы для чтения ил и задания соответствующих свойств .

В качестве примера приложения с виджетом TextView создайте новый проект и в диалоге Create New Project введите следующие значения :

О Project name - TextView;

О Application name - TextView Sample;

Page 95: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

88

О Package name - сот . samples . textview;

О Create Activity - TextViewActivity.

Глава 6

Откройте файл разметки и создайте разметку LinearLayout и в ней четыре элемента TextView с идентификаторами textl, text2, textз; text4 . Для textl

задайте текст непосредственно в ХМL-коде:

android : text="He l l o , Android ! "

Для элемента text2 текст задайте через ссылку на строкавый ресурс. Можно также задать различный размер, цвет и стиль форматирования текста для элементов textЗ и text 4 . Полный код файла разметки показан в л истинге 6 . 1 .

<?xml version=" l . O " encoding= "utf-8 " ?>

<LinearLayout xmlns : android="http : / /schemas . android . com/apk/ re s / android"

android : id=" @ +id/LinearLayout O l "

android : layout_width= " fil l_parent "

android : layout_height=" fil l_parent "

android : orientation="vert i ca l " >

<TextView

android : id=" @ +id/text l "

android : layout_width= "wrap_content "

android : layout_height="wrap_content "

android : text= "Hel lo, Android ! " /> <TextView

android : id= " @ +id/text2 "

android : layout_width= "wrap_content "

android : layout_height="wrap_content "

android : text= " @ s tring / text_hello"

android : textStyle= "bold" /> <TextView

android : id=" @ +id/text З "

androi d : layout_width= "wrap_content "

android : layout_height="wrap_content "

android : textSi z e= " З бsp"

android : textStyle="bold"

android : textColor= " #AВAВAВ" />

<TextView

android : id= " @ +id/text4 "

android : layout_width= "wrap_content "

android : layout_height="wrap_content "

Page 96: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

Базовые виджеты

android : textSize= " 4 8sp" android : textStyle= " italic " />

</LinearLayout>

89

В файле ресурсов strings.xml добавьте после ресурса арр _nате новый строко­вый ресурс "Hel lo, Android ! " (листинг 6 .2).

<?xml version= " l . O " encoding= "utf-8 " ?>

<resources> <string name="app_name " >TextView Sample</string> <string name=" text_hello">Hello, Android ! </string>

</ resources>

В классе TextViewActi vi ty инициализируйте техtViеw-объекты textЗ, text4

и методом setтext ( ) задайте для них текст. Полный код класса показан в листинге 6 .3 .

package corn . samples . textview;

irnport android . app . Activity; irnport android . os . Bundle ; irnport android . widget . TextView;

puЬlic class TextViewActivity extends Act ivity {

@ Ove rride

puЬl i c void onCreate ( Bundle saved!nstanceState )

supe r . onCreate ( savedinstanceStat e ) ;

setContentView ( R . layout . rnain) ;

1 1 загружаем виджеты из ресурсов

final TextView textЗ ( T extView ) findViewBy!d ( R . id . textЗ ) ; 1 1 задаем текст непосредственно в коде программы

text З . setText ( "Hello , Android ! " ) ;

final TextView text 4 ( TextView ) findViewBy!d ( R . i d . text4 ) ; 1 1 задаем текст из ресурсов

text 4 . setText ( R . string . text_hel l o ) ;

Page 97: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

90 Глава 6

Рис. 6.2. Приложение с виджетами TextView

Запустите проект на выполнение. Результат должен получиться, как на рис. 6 .2 . Для первого поля текст задается прямо в файле разметки, для второ­го - в файле разметки из ресурса, для третьего - задается в коде, для чет­вертого поля - читается в коде из файла ресурсов.

6 . 1 .2 . EditText

Элемент Edi tтext - это текстовое поле для пользовательского ввода. EditText представляет собой тонкую оболочку над классом TextVi ew, которая сконфигурирована для редактирования вводимого текста.

Основной метод класса Edi tText - getText ( ) , который возвращает текст, со­держащи йся в окне элемента EditTex t . Возвращаемое значение имеет тип EditaЬle. Этот тип представляет собой интерфейс для текста, информацион­ное наполнение и разметка которого могут быть изменены (в противополож­ность типу S t r ing, который я вляется неизменяемым, при его изменени и про­сто создается новый экземпляр s t ring) .

В классе также определены методы для выделения текста:

D s e l ectAl l ( ) - выделяет весь текст в окне;

D s e t Se l e c t ion ( int s t a rt , int s top ) - выделяет участок текста с позиции s ta r t Д О ПОЗ И Ц И И s t op;

D s e t S e l e c t ion ( i nt index ) - перемещает курсор на пози цию index.

Page 98: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

Базовые виджетьt 9 1

Большинство методов для работы с текстом и его форматированием уна­

следованы от базового класса тextView. Чаще всего используются мето­

ды setTypeface ( nul l , Typeface ) , setTextS ize ( int textS i ze ) , SetTextColor ( int

Color ) .

Для примера создайте новый проект и в диалоге Create New Project введите следующие значения :

О Project name - Edi tTextApp;

О Application name - EditText Sample;

О Package name - с от . samples . scroll view;

О Create Activity - EditTextActivity.

Откройте файл разметки и создайте структуру разметки подобно листингу 6.4.

Hel lo, Android!

Р ис. 6.3 . При мер использования элемента Edi tText

<?xml version= " l . O " encoding= " ut f- 8 " ?>

<LinearLayout xmlns : android="http : / /schemas . android . com/ apk/ res/android"

android : orientation="vertica l "

android : layout_width= " fi l l_parent "

android : layout_height= " fi l l_parent ">

Page 99: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

92

<EditText

androi d : id= " @ + id/EditTextO l "

android : layout_height=" fi l l_parent "

android : layout_width= " fi l l:_parent "

android : text="Hello , Android ! " />

</LinearLayout>

Глава б

Запустите проект на выполнение. Внешний вид программы с элементом тextview и полосами прокрутки по казан на рис. 6 .3 .

В приведеиных программах мы работали только с файлами разметки и пока почти не добавляли программ но го кода в класс Acti vi ty. Далее в этой главе по мере ознакомления с другими элементами пользовательского интерфейса мы будем постепенно усложнять наши примеры .

6 .2 . Добавление полос п рокрутки Класс TextView использует свою собственную прокрутку и в принципе не требует добавления отдельных полос прокрутки, но применение видимых полос прокрутки вместе с TextView (или любым другим элементом или кон­тейнером, размеры которого больше размера экрана мобильного устройства) улучшает внешний вид и повышает удобство использования приложения.

Полосы прокрутки в Android представляют виджеты scrollView

и HorizontalScrol lView, которые являются контейнерными элементами и наследуются от viewGroup, как показано на рис. 6 .4 .

View ViewGroup

ScroiiView

HorizontaiScroiiView

Рис. 6.4. Иерархия классов для Scrol lView и HorizontalScrol lView

Элементы Scroll View и HorizontalScro l l View - это контейнеры типа FrameLayout, что означает, что в них можно разместить только одно дочернее представление. Этот дочерний элемент может, в свою очередь, быть контей­нером со сложной иерархией объектов. В качестве дочернего элемента для полос прокрутки обычно испол ьзуют LinearLayout с вертикальной или гори­зонтальной ориентацией элементов.

Page 100: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

Базовые виджеты 93

Виджет scrol lView, несмотря на свое название, поддерживает только верти­кальную прокрутку, поэтому для создания вертикальной и горизонталь­ной прокрутки необходимо использовать scrollView в сочетании с HorizontalScrollView. Обычно ScrollView используют в качестве корневого элемента, а HorizontalScroll View - дочернего.

Рассмотрим создание полос прокрутки на практике. В среде Ecl ipse создайте новый проект и в диалоге Create New Project введите следующие значения :

О Project name - ScrollsApp;

О Application name - Scrol l s Sample;

О Package name - com . samples . scrolls;

О Create Activity - ScrollsAct ivity.

Откройте файл разметки main .xml и создайте струюуру разметки, разместив в ней ScrollView, Hori zontalScrol lView и TextView, как показано в листинге 6 . 5 .

<ScrollView xmlns : android="http : / /schemas . android . com/apk/res/android"

android : id=" @+id/scroll "

android : layout_width="wrap_content "

android : layout_height="wrap_content " >

<HorizontalScrol lView

android : id=" @ +id/scrol l_hor"

androi d : layout_width=" fi l l_parent"

android : layout_height= " f i l l_parent " >

<TextView

android : id=" @ +id/textview"

android : layout_width="wrap_content "

android : layout_height="wrap_content "

android : textColor= " # O O O O O O "

android : background= " # FFFFFF"

android : textSize= " 2 4 px "

android : shadowDx= " O "

android : shadowDy= " O "

android : shadowRadius=" O "

android : shadowColor= " # FFFFFF"

android : isScrol lContainer=" true " />

< /Hori zontalScrol lView>

</ ScrollView>

Page 101: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

94 Глава 6

В классе Scrol l ViewActi vi ty в теле метода oncreate ( ) создайте ссылку на

элемент TextVi ew, объявленный в ХМL-разметке, и запишите в него методом

s etText ( ) достаточно большой текст, который гарантированно не поместится в видимые размеры экрана устройства. Код класса деятельности

Scroll ViewAct i vi ty представлен в листинге 6 .6 .

ку новое вспомогател ь ва н и е для мобил ь н ых

ется на р ы н ке, дра й ве р ы а п и са н ы на уров н е ядра

е н и я поддержку обору настол · uх-си сте

Рис. 6.5. Текстовое поле с горизонтальными и вертикальными полосами прокрутки

package com . sample s . scrol l s ;

import android . app . Activi t y ;

import android . os . Bundle ;

import android . widget . TextView ;

puЬlic c l a s s S c rol l sActivity extends Act ivity

@ Ove rride

puЬ l i c void onCreate ( Bundle s avedins tanceState )

supe r . onCreat e ( savedins tanceStat e ) ;

setContentView ( R . layout . main ) ;

Page 102: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

Базовые виджетьt

TextView text ( TextView ) findViewByid ( R . id . textview ) ; 1 1 загружаем текст text . setText ( " введите любой достаточно большой текст

95

Запустите проект на выпол нение. Внешний вид программы с элементом тextview и полосами прокрутки по казан на рис. 6 .5 .

6.3 . Отображен ие графики Для отображения графики предназначен виджет Imageview. Как и элемент тextView, который является базовым виджетом для текстового наполнения пользовательского интерфейса, ImageView является базовым элементом для графического наполнения и может использоваться в контейнерных виджетах для отображения графики, например иконки.

Класс Imageview может загружать изображения из различных источников, та­ких как ресурсы или контент-провайдеры . В классе существует нескол ько методов для загрузки изображений :

D set imageResource ( int res i d ) - загружает изображение по его идентифи­катору ресурса;

D set imageURI ( Uri uri ) - загружает изображение по его URI ;

D setimageBitmap (Bitmap Ьitmap ) - загружает растровое изображение.

Для загрузки изображения в ХМL-файле разметки используется атрибут android : s rc .

1

Кроме того, в классе ImageView определены методы для установки разме­ров изображения - setMaxHeight ( ) , setMaxWidth ( ) , getMinimunHeight ( ) , getMinimunWidth ( ) , а также его масштабирования - getScaleType ( ) , setScaleType ( ) .

Для примера приложения с использован ием виджета ImageView создайте но­вый проект и в диалоге Create New Project введите следующие значения :

D Project name - ImageViewApp;

D Application name - ImageView Sample;

D Package name - com . samples . imageview;

D Create Activity - ImageViewAct ivity.

В каталог res/drawaЬ\e/ проекта поместите два изображения, android .png и aпdroidmarker.png (их можно найти на прилагаемом к книге CD-ROM).

Page 103: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

96 Глава б

Откройте файл разметки и создайте структуру разметки, разместив в ней два

элемента ImageView с идентификаторами imagel, image2 . .Цля первого элемента

задайте атрибут android : s rc= " @ drawaЬle/android" .

В листинге 6. 7 приведен полный код разметки.

<?xml vers ion= " l . O " encoding= "utf-8 " ?>

<LinearLayout юnlns : android= "http : / / schemas . android . com/apk/ res /android"

android : layout_

width= " fill_

parent "

android : layout_

height= " fi l l_parent "

android : gravity= " center"

android : orientation="hori zontal " >

< ImageView

android : id= " @ +id/ image l "

android : layout_

width= " wrap_

content "

android : layout_

height= "wrap_

content "

android : s rc=" @ drawaЬle /android"

android : padding= " l Opx " />

< ImageView

android : id= " @ + id/ image2 "

android : layout_

width= "wrap_

content "

android : layout_

height="wrap_

content "

android : padding= " l Opx " />

</ LinearLayout>

В классе ImageViewActivity загрузите программно изображение для второго виджета ImageView, методом setimageResource ( ) , как показано в листинге 6 .8 .

package com . samples . imageview ;

import android . app . Act ivity;

import android . os . Bundle ;

import android . widget . ImageView;

puЬlic class ImageViewActivity extends Activity { @ Override

Page 104: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

Базовые виджеты

puЬlic void onCreate ( Bundle savedinstanceState )

super . onCreate ( savedinstanceState ) ;

setContentView ( R . layout . main ) ;

final ImageView image ( ImageView ) findViewByid ( R . i d . image2 ) ; / 1 загрузка изображения из ресурса image . setimageResource ( R . drawaЬle . androidmarke r ) ;

97

Запустите проект на выполнение. Результат должен получиться , как на рис. 6 .6 .

Рис. 6.6. Пример виджетов ImageView с загруженны.ми изображениями

6.4. Обработка событий Как только в ы научитесь добавлять виджеты в пользовател ьский интерфейс, вы, вероятно, захотите узнать, как с ними взаимодействует пользователь. Чтобы создавать приложения, взаимодействующие с пользователем, необхо­димо определить обработчик события и зарегистрировать его для данного элемента.

Класс View содержит коллекцию вложенных интерфейсов, которые называ­ются on . . . Listener ( ) , в каждом из которых объявлен единственный абст-

Page 105: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

98 Глава б

рактный метод обратного вызова. Этот метод необходимо переопределить в вашем классе. Его будет вызывать система Android, когда экземпляр View,

к которому был подсоединен слушатель события, вызывается пользователь­ским взаимодействием с интерфейсом приложения.

Всего класс view содержит шесть вложенных интерфейсов :

О OnC l i c kListene r;

О , OnLongCl ickLis tener;

О OnFocusChangeLis tener;

О OnKeyLis tene r;

О OnTouchListene r;

О OnCreateContextMenuLi s tene r.

Например, есл и требуется, чтобы кнопка получила уведомление о нажатии ее пользователем, необходимо в классе деятельности реализовать интерфейс OnCli ckLi stene r и определить его метод обратного вызова onC l i c k ( ) , куда будет помещен код обработки нажатия кнопки, и зарегистрировать слуша­

тел ь события с помощью метода setOnC l i c kListener ( ) :

button l . setOnC l i ckLi stene r ( new View . OnC l i c kLis tene r ( )

puЬ l i c void onC l i c k (View v )

mText . setText ( "C l i c k on Fi rst Button" ) ;

Существует несколько способов подключения событий, о которых будет рас­сказано далее.

6 .5 . Кноп ки и флажки Кнопки и флажки в Android представлены следующими классами :

о Button;

о CheckBox;

о ToggleButton;

о RadioButton;

о ImageButton.

Почти у всех вышеперечисленных виджетов базовым классом является

Textview, от которого они наследуют м ногочисленные методы для отображе­

ния и форматирования текста. Исключение составляет виджет Imageвutton,

Page 106: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

Базовые виджеты 99

который является наследником класса ImageView и представляет собой кнопку с изображением без текста.

Класс вutton представляет командную кнопку и наследуется от Textview.

Он является базовым классом для класса CompoundButton. От класса CompoundButton наследуются остальные кнопки : CheckBox, ToggleButton

и Radioвutton. Иерархия классов кнопок представлена на рис. 6 .7 .

Object 1 г-----,

View 1 г-----, TextView 1 ,.--------,

Button 1 ,---------, '-----------1 CompoundButton 1

l mageView 1 г-----, '-----------1 l mageButton 1

г-------, CheckBox 1

ToggleButton J RadioButton 1

Рис. 6.7. Иерархия классов Button, Chec kBox, ToggleButton, RadioButton и ImageButton

Класс CompoundВutton представляет базовую функционал ьность для кнопок с двумя состояниями - checked и unchec ked. При нажатии состояние кнопки изменяется на противоположное. Класс compoundВutton содержит вложенный интерфейс oncheckedChangeListener с единственным методом onChec kedChanged ( ) .

6.5. 1 . Button

Класс вutton - самы й простой из всех элементов управления и при этом са­мый используемый . Чаще всего кнопка требует написания кода обработки события нажатия onClick.

Следующий пример реализует обработчик события onc l i c k ( ) . Когда выпол­няется щелчок на кнопке, появляется сообщение, отображающее имя кнопки . Создайте в среде Ecl i pse новый проект и в диалоге Create New Project введи­те следующие значения :

D Project name - вuttonApp;

D Application name - Button Sample;

D Package name - сот . samples . button;

D Create Activity - ButtonActivity.

Page 107: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

100 Глава 6

Откройте файл разметки и создайте разметку LinearLayout и в ней две кнопки с идентификаторами buttonl и button2, надписям и "Button 1 " и "Button 2" (листинг 6.9).

<?xml version= " l . O " encoding= " utf- 8 " ?>

<LinearLayout xmlns : android= "http : / / schemas . android . com/apk/ res /android"

android : orientation="ve rt i cal "

android : layout_

width= " fill__;parent "

android : layout_

height= " fi l l_

parent " >

<Button

android : id= " @ +id/buttonl "

android : layout_

width= "wrap_

content "

android : layout_

height= "wrap_

content "

android : text= "Button 1 " />

<Button

android : id=" @ +id/button2 "

android : layout_

width= "wrap_

content "

android : layout_

he ight= "wrap_

content "

android : text= "Button 2 " / >

<TextView

android : id= " @ +id/text "

android : layout_width= "wrap_

content "

android : layout_

height= "wrap_

content " />

< /LinearLayout>

Теперь в классе вuttonActivity подключим обработчики событий для кнопок, как показано в л истинге 6. 1 О .

package com . samples . button2 ;

import android . app . Activity ;

import android . os . Bundle ;

import android . widget . Button ;

import android . widget . TextView;

import android . view . View ;

puЬlic c l a s s ButtonActivity extends Act ivity {

private TextView mText ;

Page 108: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

Базовые виджеты

@ Ove rride

puЬlic void oпCreate ( Buпdle savediпstaпceState )

supe r . oпCreate ( savediпstaпceState ) ;

setCoпteпtView ( R . layout . maiп ) ;

mText (TextView ) fiпdViewByid ( R . id . text ) ;

fiпal Buttoп buttoпl ( Buttoп ) fiпdViewByid ( R . id . buttoпl ) ;

buttoпl . setOпC l ickListeпer ( пew View . OпClickLis teпe r ( ) {

puЬlic void oпClick ( View v )

mText . setText ( "Click о п Fi rst Buttoп" ) ;

fiпal Buttoп buttoп2 ( Buttoп ) fiпdViewByid ( R . id . buttoп2 ) ;

buttoп2 . setOпClickLis teпer ( пew View . OпCl ickLis teпe r ( ) {

puЬlic void oпClick (View v )

mText . setText ( "Click о п Secoпd Buttoп " ) ;

101

Выполните компиляцию проекта. При нажатии соответствующей кнопки в надписи под кнопками будет отображаться сообщение о нажатии этой кнопки (рис. 6 . 8) .

Существуют и другие варианты подключения событий . В предыдущем при­мере обработчики событий были реализованы внутри тела метода oпcreate ( ) . Наличие множества вложенных блоков кода создает трудности восприятия кода, особенно другими программистам и, поэтому желательно выно­сить обработчики событий за пределы метода oпCreate ( ) . В методе setoпclickListeпer ( ) в качестве параметра передается имя метода обратного вызова, который мы будем реализовывать:

buttoп . setOпCl i c kListeпer ( buttoп_

c l i c k ) ;

Затем мы описываем реализацию этого метода:

puЬlic OпCl ickListeпe r buttoп_

click пеw OпClickListeпe r ( )

@ Ove rride

puЬlic void oпClick (View v )

1 1 действия по обработке события

Page 109: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

1 02 Глава 6

Рис. 6.8. Пример приложения с кнопками

Внесите в класс вut tonActivity изменения, как показано в листинге 6 . 1 1 , и скомпилируйте проект. Результат не изменился, но код класса стал легче для восприятия .

@ Ove rride

puЬlic vo id onCreat e ( Bundle savedins tance State )

buttonl . setOnC l i c kLis tene r ( buttonl c l i c k ) ;

button2 . setOnC l i c kListene r (button2_c l i c k ) ;

puЬl i c OnCl ickListener buttonl_c l i c k

@ Override

puЬl ic void onC l i c k ( View v )

new OnCl ickListene r ( )

mText . setText ( " C l i c k on buttonO l " ) ;

puЬl ic OnCl i ckListener button2 c l i c k

@ Ove r ride

new OnCl ickListene r ( ) {

Page 110: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

Базовые виджеты

public void onC l i c k (View v )

mText . setText ( " Click o n button02 " ) ;

1 03

Наконец, есть еще способ, более эффективный, чем предыдущие, - реа­лизовать обработку однотипных событий всех элементов в одном мето­де. Для этого в нашем классе необходимо реализовать интерфейс View . OnC l i c kListene r:

puЬl i c class EditTextActivity extends Activity

impl ements OnC l i c kLis tene r

Этот интерфейс содержит единственный метод:

abs t ract vo id onC l i c k ( View v) ,

которы й необходимо определить в нашем классе вuttonAc t ivity. Есл и опре­делен идентификатор элемента (например, в файле разметки), то можно на­писать обработку событий элементов в операторе switch, получив I D элемен­та методом get r d ( ) :

@Override

puЬl i c vo id onClick (View v )

switch ( v . get i d ( ) ) {

/ 1 определяем ID элемента и обрабатываем событие

В качестве примера создадим простой текстовый редактор с возможностями форматирования текста и пятью кнопками для форматирован ия вводи мого текста. Создайте новый проект и в диалоге Create New Project введите сле­дующие значения :

О Project name - EditTextApp;

О Application name - Edi tтextSample;

О Package name - com . samples . edi ttext;

О Create Activity - AutoCompleteTextViewActivity.

Создайте файл разметки, как в листинге 6 . 1 2 .

< ?xml ve rs ion= " l . O " encoding= " ut f - 8 " ?>

<TableLayout xmlns : android= "http : / / s chemas . android . com/apk/ res /android"

Page 111: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

1 04

android : layout_width= " f i l l_pa rent "

andro id : layout_height= " f i l l_pa rent " >

<TaЬleRow

android : layout_width="wrap_content "

android : layout_hei ght="wrap_content "

android : gravity= " cente r " >

<Button

android : id= " @ +id/button r "

android : layout_width= " 5 0dp "

android : layout_he ight="wrap_content "

android : text= "R" / >

<Button

androi d : id= " @ +id/button Ь"

android : layout_width= " 5 0dp "

android : layout_he ight= "wrap_content"

android : text= " B " / >

<Button

android : id= " @ +id/button i "

android : layout_width= " 5 0dp "

android : layout_he ight= "wrap_content "

android : text= " I " / >

<TextView

androi d : id= " @ +id/ labe l "

androi d : layout_he ight="wrap_content "

android : text= " Text S i z e "

android : paddingLeft= " l Opx "

android : layout_width="wrap_content " />

<Button

android : id=" @ +id/button_plus "

android : layout_width= " 5 0dp "

android : layout_he ight="wrap_content "

androi d : text= " + " / >

<Button

android : id=" @ +id/button rninus "

android : l ayout_width= " 5 0dp "

android : layout_he ight= "wrap_content "

android : text= " - " / >

< /TaЬleRow>

<Edi tText

android : id= " @ +id/edit text "

android : layout_he i ght= " fi l l_parent "

Глава 6

Page 112: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

Базовые виджеты

android : layout_width= " f i l l_parent "

android : text= " He l l o , Android" />

< /TaЬleLayout>

1 05

В нашем примере кроме элемента Editтext будет небольшое меню из пяти кнопок для изменения стиля текста и его размера (листинг 6 . 1 3) .

package com . samples . edittext ;

import android . app . Ac t ivity;

import android . graphics . Typeface ;

import android . os . Bundl e ;

import android . view . View;

import android . view . View . OnC l ickLis tene r ;

import android . widget . Button ;

import android . widget . EditText ;

puЬlic c l a s s EditTextActivity extends Activity

implements OnCl ickListene r

private float mTextS i z e 2 0 ;

private EditText mEdit ;

@ Override

puЬl ic void onCreate ( Bundle savedinstanceState )

{

super . onCreate ( savedinstanceState ) ;

setContentView ( R . layout . main ) ;

mEdi t = { EditText ) f indViewByid ( R . id . edit_text ) ;

final Button buttonR

( Button ) findViewByid ( R . i d . button_r ) ;

f inal Button buttonB

( Button ) findViewByid ( R . i d . button_b ) ;

final Button buttoni

( Button ) findViewByid ( R . i d . button_i ) ;

f ina l Button buttonPlus

( Button ) findViewByid ( R . i d . button_plus ) ;

fina l Button buttonМinus

( Button ) findViewByid ( R . id . button_minus ) ;

Page 113: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

1 06

buttonR . setOnCl ickLis t ene r ( thi s ) ;

but tonB . setOnCl ickLis tene r ( thi s ) ;

button i . setOnCl ickListene r ( thi s ) ;

but tonPlus . setOnCl i ckLis t ene r ( thi s ) ;

buttonМinus . setOnCl ickLi s tener ( thi s ) ;

@ Override

puЫ i c void onC l i c k (View v )

switch ( v . get i d ( ) )

case R . id . button r :

mEdi t . setType face ( nul l , Type face . NORМAL ) ;

break;

case R . id . button Ь :

mEdi t . s etType face ( nul l , Type face . BOLD ) ;

break ;

case R . id . button i :

mEdit . setType face ( nul l , Typeface . ITALI C ) ;

brea k ;

case R . id . button_plus :

i f (mTextS i ze <= 7 2 )

mText S i ze+=2 ;

mEdit . s etText S i ze (mTextS i ze ) ;

brea k ;

case R . i d . butt on minus :

i f (mTextS i z e >= 2 0 )

mText S i z e-=2 ;

mEdi t . setText S i z e (mTextS i z e ) ;

brea k ;

Глава б

Запустите проект на выполнение. Получившийся простейший текстовый ре­дактор позволяет форматировать вводимый текст, изменяя его стиль и размер (рис. 6.9) .

6.5 .2 . RadioButton и RadioGroup

Виджеты Radioвutton (радиокнопки) обычно используются в составе груп­пы - контейнера RadioGroup. Радиокнопки дают возможность пользователю выбирать одну из нескольких опций. Когда вы используете множество эле­ментов управления Radi oButton в одном контейнере, выбранным может быть

Page 114: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

Базовые виджеты 1 0 7

He/lo, Android!

Рис. 6.9. Простой текстовый редактор

только один из них. Поэтому, если у вас есть три опции, например Red, Green и Blue, и если выбрана опция Red, а пользователь щелкает на Blue, то опция Red автоматически отключается.

Основной метод для изменения состояния - toggle ( ) , которы й ин вертирует состояние радиокнопки. Кроме того, от базового класса наследуются и дру­гие методы, например i s Checked ( ) , которы й возвращает состояние кнопки, и s etchecked ( ) , изменяющий состояние кнопки в зависимости от параметра.

Для примера приложения с радиокнопками создайте новый проект и в диало­ге Create New Project введите следующие значения :

D Project nаше - Radi oButtonApp;

D Application nаше - RadioButton Sarnple;

D Package nаше - com . s arnples . radiobutton;

D Create Activity - RadioButtonActivity.

Откройте файл разметки и создайте структуру разметки с корневы м контей­

нером RadioGroup, тремя радиокнопками и элементом TextView. Присвойте

кнопкам ID radiol, radio2, radioЗ и надписи Mode # 1 , Mode # 2 , Mode # 3 , как в листинге 6 . 1 4 .

Page 115: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

108 Глава б

<?xml ver s i on= " 1 . 0 " encoding= " ut f-8 " ?>

<RadioGroup xrn1ns : android= "http : / / schemas . android . com/ apk/ r e s / android"

android : orientation="vertica l "

android : layout_width= " fi l l_parent "

android : layout_he i ght= " fi l l_parent " >

<RadioButton

android : id= " @ + id/ radio1 "

android : layout_width="wrap_content "

android : layout_he i ght= "wrap_content "

android : text= "Mode # 1 "

android : checked=" true " / >

<RadioButton

android : id= " @ + id/ radio2 "

android : layout_width=" wrap_content "

android : layout_he ight= "wrap_content "

android : text= "Mode # 2 " />

<Radi oButton

android : id= " @ + id/ radioЗ "

android : layout_width="wrap_content "

android : layout_he i ght= "wrap_content "

android : text= "Mode # 3 " />

<TextView

androi d : id= " @ + id/ text "

android : layout_width= "wrap_content "

android : layout_he i ght= "wrap_content "

android : text= " Select : Mode # 1 " / >

</RadioGroup>

Для определения выбранной опции добавьте обработчик события onC l i c k ( )

на кнопках. В классе RadioвuttonActivity напишите код подобно листин­гу 6. 1 5 .

pac kage com . samples . radiobutton ;

import android . app . Act ivity;

import android . os . Bundle ;

import android . view . View;

Page 116: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

Базовые виджеты

import android . view . View . OnClickListene r ;

import android . widget . RadioButton ;

import android . widget . TextView ;

puЬlic class RadioButtonDemo extends Act ivity

private TextView mText ;

@ Override

puЬlic void onCreate ( Bundle savedinstanceState )

super . onCreate ( savedinstanceState ) ;

setContentView ( R . layout . main) ;

final RadioButton radiol

( RadioButton ) findViewByid ( R . id . radiol ) ;

final RadioButton radio2

( RadioButton ) findViewByid ( R . id . radio2 ) ;

final RadioButton radioЗ

( RadioButton ) findViewByid ( R . id . radioЗ ) ;

mText ( TextView ) findViewByid ( R . id . text ) ;

radiol . setOnClickListene r ( radioButton_

Click) ;

radio2 . setOnClickListener ( radioButton_

Click ) ;

radioЗ . setOnClickLi stener ( radioButton Click) ;

OnC l ickLis tene r radioButton Click

puЬl i c void onCl ick (View v ) { new OnClickListener ( )

RadioButton rb ( RadioButton ) v ;

mText . setText ( " Select : + rb . getтext ( ) ) ;

109

Выполните компиляцию проекта. Выбранная опция отображается в элементе тextView, изменение текста которого происходит в обработчике radioButton_Click. Внешний вид программы представлен на рис. 6 . 1 О.

6.5 .3 . CheckBox

Элемент CheckBox (флажок) - это переключатель с двумя состояниями . Для программнаго отслеживания изменения состояния элемента необходимо реализовать интерфейс CompoundButton . OnCheckedChangeListener.

Page 117: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

1 1 0 Глава б

Рис. 6 . 1 0 . Пример элементов RadioButton

В качестве примера использования checkBox в приложении создайте новый проект и в диалоге Create New Project введите следующие значения :

D Project name - Chec kВox;

D Application name - CheckBox Sarnple;

D Package name - com . s arnp le s . checkЬox;

D Create Activity - Chec kBox Act ivity.

Откройте файл разметки и создайте структуру разметки с одним элементом CheckBox подобно листингу 6 . 1 6 .

< ? xml ve rsion= " . 0 " encoding= " ut f- 8 " ? >

<Linea rLayout xmlns : android=" http : / / schema s . android . com/ apk / re s / android"

android : id= " @ + id/Linea rLayout O l "

android : layout_width= " f i l l_pa rent "

android : layout_he ight= " fi l l_parent " >

<CheckBox

android : id= " @ + id/ checkbox"

android : layout_width= "wrap_content "

Page 118: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

Базовые виджеты

android : layout_

height= "wrap content "

android : text= " CheckBox OFF" />

< /LinearLayout>

1 1 1

В классе CheckBoxAct ivity подсоедините слушатель события для флажка и в обработчике события сделайте проверку его состояния (листинг 6 . 1 7) .

package com . samples . checkЬox ;

import android . app . Act ivity ;

import android . os . Bundle ;

import android . widget . Chec kBox ;

import android . widget . CompoundВutton ;

puЬlic c l a s s CheckBoxActivity extends Activity

implements CompoundВutton . OnCheckedChangeListener

private CheckВox mCheckBox ;

@ Override

puЬl ic void onCreate ( Bundle savedinstanceState )

super . onCreate ( savedinstanceState ) ;

setContentView ( R . layout . main) ;

mCheckBox ( CheckBox ) findViewByid ( R . id . checkbox ) ;

1 1 регистрация слушателя события

mCheckBox . setOnCheckedChangeLi s tener ( thi s ) ;

обработчик события изменения состояния флажка

puЬl i c void onCheckedChanged (

CompoundВutton buttonView , boolean isChecked )

if ( isChecked )

mCheckBox . setText ( " CheckBox ON " ) ;

else

mCheckBox . setText ( " CheckBox OFF" ) ;

Выпол ните компиляцию проекта. Программа обрабатывает изменение со­стояния флажка, отображая текущее состояние в его текстовой метке. Резуль­тат должен получиться подобно рис. 6 . 1 1 .

Page 119: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

1 1 2 Глава б

Рис. 6 . 1 1 . Элемент CheckBox

6.5.4. ToggleButton

Виджет ToggleButton - это кнопка с двумя состояниями : " включено" и "вы­ключено" По умолчанию на кнопке определены надписи ON/OFF и LЕD­индикатор, изменяющий цвет на зеленый при переключении в состояние ON .

Основные свойства ToggleButton - android : textOff и android : textOn, уста­навливающие надписи на кнопке в разных состояниях. В программном коде им соответствуют методы setTextOff ( ) и setTexton ( ) .

Метод setChecked ( boolean checked) позволяет программно менять состояние кнопки. Основное событие ToggleButton - изменение состояния кнопки onChec kedChanged ( ) .

В качестве примера создайте новый проект и в диалоге Create New Project введите следующие значения :

О Project name - ToggleButtonApp;

О Application name - ToggleButton Sarnple;

О Package name - com . sarnples . togglebutton;

О Create Activity - Toggl eButtonActivity.

Откройте файл разметки и создайте структуру разметки, добавив элементы ToggleButton и тextView для вывода сообщения о состоянии кнопки (лис­тинг 6 . 1 8) .

Page 120: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

Базовые виджеты 1 13

< ?xml ve rsion= " l . O " encoding= " utf- 8 " ?>

<LinearLayout xmlns : android= "http : / / schemas . android . com/apk/ res / android"

android : orientat ion= "vert ica l "

android : layout_

width= " fi l l_

pa rent "

android : layout_

height= " fi l l_

parent " >

<ToggleButton

android : id= " @ +id/button

android : layout_

he ight= "wrap_

content "

android : layout_

width= " fi l l_

parent " / >

<TextView

android : id= " @ +id/ text "

android : layout_

width= "wrap_

content "

android : layout_

he ight= "wrap_

content " / >

< / LinearLayout>

Для создания обработчика события изменения состояния кнопки в нашем

классе необходима реализация интерфейса CompoundBut ton . OnCheckedChange­

Listener.

Этот интерфейс имеет единственный метод onCheckedChanged ( ) , которы й не­обходимо переопредел ить в нашем классе. При обработке события для опре­деления состояния используется параметр i s Checked. Полный код класса представлен в листинге 6 . 1 9 .

package com . samples . togglebutton ;

import android . app . Activity;

import android . os . Bundle ;

import android . widget . CompoundВutton ;

import android . widget . ToggleButton ;

import android . widget . TextView ;

puЬl i c c l a s s ToggleButtonActivity extends Act ivity

implements CompoundВutton . OnCheckedChangeListener

ToggleButton mВutton ;

TextView mLabel ;

Page 121: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

1 1 4

@ Ove rride

puЫ i c void onCreate ( Bundle s avedinstanceStat e )

supe r . onCreate ( savedinstanceState ) ;

setContentView ( R . layout . main ) ;

mВut ton ( ToggleButton ) f indVi ewByid ( R . id . button ) ;

mВut ton . setOnCheckedChangeLi s t ener ( thi s ) ;

mLabe l ( TextView ) findViewByi d ( R . id . text ) ;

@ Over ride

puЫ i c void onCheckedChanged (

CompoundВutton buttonView, bool ean isChecked )

i f ( i sChec ked )

mLabe l . s etText ( " Button checked " ) ;

e l s e

mLabe l . setText ( "Button unchecked" ) ;

Глава 6

Вы полните компиляцию проекта. При нажатии кнопки будет меняться надпись на кнопке с OFF на ON и цвет LЕD-индикатора, как показано на рис. 6 . 1 2 .

Рис. 6 . 1 2. Элемент ToggleButton

Page 122: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

Базовые виджеты 1 1 5

6.5 .5. /mageButton

Виджет ImageButton представляет собой кнопку с изображением (вместо тек­

ста). По умолчанию IrnageButton похож на обычный элемент Button, со стан­дартным фоном кнопки, который изменяет цвет во время других состояний кнопки.

Изображение на поверхности кнопки определяется атрибутом android : s rc

в элементе < IrnageButton> или в программ нам коде методом setirnageResource ( int ) .

Рассмотрим пример. Создайте новый проект и в диалоге Create New Project введите следующие значения :

D Project name - ImageButtonApp;

D Application name - IrnageButton Sarnple;

D Package name - сот . sarnples . imagebutton;

D Create Activity - IrnageButtonAct ivity.

Откройте файл разметки и создайте структуру разметки с элементом

IrnageButton подобно л истингу 6 .20 .

<?xrnl version= " . 0 " encoding= "ut f- 8 " ?>

<LinearLayout xrnlns : android="http : / /schema s . android . com/apk/ res / android"

android : orientation="vertica l "

android : layout_width=" fi l l_pa rent "

android : layout_height= " fi l l_parent " >

<ImageButton

android : id=" @ + id/button "

android : layout_width="wrap_content "

android : layout_height="wrap_content"

android : s rc= " @ drawable/play " / >

</LinearLayout>

В папку res/drawaЬ\e/ поместите изображения для отображения состояний кнопки (можно взять готовые из прилагаемоr:о к книге CD-ROM в каталоге Resources/lmages/ - иконки play.pпg и pause .pпg).

Для класса ImageButtonActi vi ty напишите код, как в листинге 6 .2 1 .

Page 123: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

1 1 6

package com . samples . imagebutton;

import android . app . Activity;

import android . os . Bundle ;

import android . view . View;

import android . widget . ImageButton ;

puЬlic class ImageButtonAct ivity extends Activity

ImageButton button ;

boolean mPlay t rue ;

@Override

puЬlic void onCreate ( Bundle savedins tanceState )

super . onCreate ( savedinstanceState ) ;

setContentView ( R . layout . main ) ;

button ( ImageButton ) findViewByid ( R . id . button ) ;

1 1 устанавливаем изображение на кноnке по умолчанию

button . setimageResource ( R . drawaЬle . play) ;

button . setOnCl ickListener ( new \Tiew . OnClickLis tene r ( )

puЬlic void onClick (View v ) 1 1 меняем изображение на кнопке

i f (mPlay)

button . setimageResource ( R . drawaЬle . pause ) ;

else

button . setimageResource ( R . drawaЬle . play) ;

mPlay ! mPlay ;

Глава б

Выnолните комnиляцию nроекта. При нажатии кноnки будет меняться кар­тин ка на этой кноnке, как nо казан о на рис. 6 . 1 3 .

Page 124: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

Базовые виджеты 1 1 7

Рис. 6. 1 3 . Изменение изображения при нажатии кнопки ImageBu t t on

6 .6 . Закладки Закладки в Aпdroid представлены классами таьноs t и TabWidget (рис . 6 . 1 4 ) .

Framelayout

TabHost

TabWidget

Рис. 6 . 1 4. Иерархия классов закладок

В иджет таьноst позволяет группировать связанные элементы управления в серии страниц-вкладок. таьноst является контейнером для коллекции элемен­тов типа тabWidget . Показывает список лейблов счета, представляющих каж­дую страницу в коллекции счета родителя . Контейнерный объект для этого виджета - таьноs t . Когда пользовател ь выбирает закладку, этот объект по­сылает сообщение в родительский контейнер таьно s t для перек.пючения на выбранную закладку.

Page 125: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

1 1 8 Глава 6

Контейнерный виджет таьноs t используется в основном только для добавле­ния закладок и обработки вызовов выбранных закладок. Основные методы для работы с тabHost:

D setup ( ) - инициализирует контейнер закладок. Необходимо вызы вать перед добавлением закладок, если таьноs t загружается методом findViewByid ( ) ;

D addTab ( ) - добавляет новую закладку;

D setCurrentTab ( ) - ставит задан ную закладку на передний план .

Большинство методов для работы с закладками реализованы в классе TabWidget . У закладки есть индикатор позиции табуляции, информационное наполнение и тег, который используется для идентификации в программнам коде . Их необходимо определить созданием экземпляра вложен ного класса TabSpec:

TabHost . TabSpec spec tabs . newТabSpec ( " tagl " ) ;

spec . setContent ( R . id . tabPagel ) ;

spec . s etindicator ( " Document 1 " ) ; tabs . addTab ( spec ) ;

В качестве примера закладок создайте новый проект и в диалоге Create New Project введите следующие значения :

D Project пате - TabHos tApp;

D Application name - TabHost Sample;

D Package пате - сот . samples . tabhos t;

D Create Activity - TabHostActivity.

Откройте файл разметки и создайте структуру разметки подобно листин­гу 6 .22 .

< ? xrnl ve rsion= " . 0 " encoding= " utf-8 " ?>

<TabHost xrnlns : android= "http : / / s chernas . android . com/apk/ res /android"

android : id= " @ +id/ tabhost "

android : layout_width= " fill_parent "

android : layout_he ight= " fi l l_parent " >

<TabWidget android : id= " @ android : id/ tabs "

android : layout_width= " fi l l_parent "

android : layout_he ight="wrap_content " />

Page 126: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

Базовые виджетьt

<FrameLayout android : id= " @android : id/ tabcontent "

android : layout_width= " fill_parent "

android : layout_height= " fil l_pa rent"

android : paddingTop= " 62px " >

<EditText android : id= " @ +id/tabPage l "

android : layout_width=" fill_parent "

android : layout_height=" fi l l_parent " />

<EditText android : id= " @ + id/ tabPage 2 "

android : layout_width=" fill_parent "

android : layout_height= " fi l l_parent " />

< /FrameLayout>

</TabWidget>

</TabHost>

1 1 9

В классе тaьнostActivity реализована приведеиная ранее последовательность инициализации таьноst и добавление к нему закладок. Полный код класса приведен в листинге 6 .23 .

package com . samples . tabhos t ;

import android . app . Act ivity;

import android . os . Bundle ;

import android . widget . TabHost ;

puЬli c class TabHostActivity extends Act ivity

@Ove rride

puЬlic void onCreate ( Bundle savedinstanceState ) supe r . onCreate ( savedinstanceState ) ;

setContentView ( R . layout . main) ;

TabHost tabs ( TabHos t ) findViewByid ( R . id . tabhost ) ;

tabs . setup ( ) ;

TabHost . TabSpec spec tabs . newTabSpec ( " tag l " ) ;

spec . setContent ( R . id . tabPagel ) ;

spec . set indicator ( " Document 1 " ) ;

tabs . addTab ( spec ) ;

Page 127: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

120

spec=tabs . newTabSpec ( " tag2 " ) ; spec . setContent ( R . id . tabPage2 ) ; spec . set indicator ( " Document 2 " ) ; tabs . addTab ( spec ) ;

tabs . setCurrentTab ( O ) ;

Глава 6

Запустите проект на выполнение. Внешний вид программ ы с виджетом таьноst и двумя закладками показан на рис. 6 . 1 5 .

Enter text . . �

Рис. 6.1 5. Контейнерный виджет TabHost с двумя закладками

6.7 . И нди каторы и слайдеры Индикаторы и слайдеры представлены в Android тремя классами :

Cl ProgressBar;

Cl RatingBar;

Cl SeekВar.

Иерархия классов для этих виджетов показана на рис. 6 . 1 6 .

Классы RatingBar (отображает рейтинг в виде звездочек) и SeekBar (слайдер) ЯВЛЯЮТСЯ расширениями клаССОВ Progres sBa r И AЬs SeekBar. Класс AЬsSeekBar

Page 128: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

Базовые виджеты 121

предоставляет базовую функционал ьность для интерактивного взаимодейст­вия пользователя с элементами RatingBar и SeekBar.

View ProgressBar

Rating Bar

SeekBar

Рис. 6. 1 6. Иерархия классов для Progres sBa r, RatingBar и SeekВar

6. 7 . 1 . ProgressBar

Элемент управления ProgressBar применяется для отображения степени за­вершенности длительных задач в приложении. Основные методы, используе­мые для работы с объектом ProgressBar:

D setProgress ( ) - устанавливает заданное значение прогресса;

Cl get progress ( ) - возвращает текущее значение прогресса;

D incrementProgressBy ( ) - устанавливает величину дискретизации прира-щения значения прогресса;

D setMax ( ) - устанавливает максимальное значение величины прогресса.

Выполнение длительной задачи лучше производить в отдельном потоке. Android предоставляет класс нandle r для порождения фоновых потоков и их безопасного взаимодействия с пользовательским интерфейсом .

Самое удобное средство порождения фонового потока - создать экземпляр нandler в классе деятельности . Фоновый поток может взаимодействовать с объектом нandler, который, в свою очередь, будет обновлять графический интерфейс в основном потоке деятельности (например, ш калу Progressвar) фрагментов.

Чтобы послать сообщение в объект нandler, сначала необходимо вызвать ме­тод obtainМessage ( ) , чтобы извлечь объект Message из глобального пула со­общений :

Handle r h ;

1 1 получаем сообщение Message msg = mНandler . obtainМessage ( ) ; 1 1 вставляем сообщение в очередь сообщений объекта Handler

h . sendМes sage (msg ) ;

Page 129: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

122 Глава 6

Для вставки сообщения в очередь сообще�ий объекта нandler существует несколько методов:

О sendМessage ( ) - nомещает сообщение в очередь немедленно (в конец оче­реди);

О sendМessageAtFrontOfQueue ( ) - nомещает сообщение в очередь немедлен­но и, кроме того, nомещает это сообщение впереди очереди (по умолча­нию оно ставится в конец очереди), таким образом ваше сообщение берет nриоритет над всеми другими ;

О sendМessageAtTirne ( ) - nомещает сообщение в очередь в установленное вре!\'IЯ в м иллисекундах;

О sendМessageDelayed ( ) - nомещает сообщение в очередь nосле задержки, выраженной в милл исекундах.

Чтобы обрабатывать эти сообщения, для объекта нandle r необходимо реали­

зовать метод обратного вызова handleмessage ( ) , который будет вызываться каждым сообщением из очереди сообщения.

Handler h;

h new Handler ( )

@Ove rride

puЬl ic void handleMes s age ( Mes sage rnsg )

1 1 код для обработки

Для nримера создадим nриложение с ProgressBar, который будет отображать ход выnолнения длительной задачи (это будет nростой цикл с nриостановкой nотока на О, 1 секунды в каждой итерации цикла) и обновлять стеnень за­вершения этой задачи через объект нandler в классе деятельности . Создай­те новый nроеюг и в диалоге Create New Project введите следующие значе­ния :

О Project name - Progres sBarApp;

О Application name - Progres sвar Sarnple;

О Package name - сот . sarnples . progres sbar;

О Create Activity - ProgressBarAct ivity.

В файле разметки создайте контейнер LinearLayout, добавьте в нее

ProgressBar и две кноnки, Stari и Stop, как nоказано в листинге 6 .24.

Page 130: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

Базовые виджетьt 1 23

<?xml ve rs ion= " l . O " encoding= " utf-8 " ?>

<Linea rLayout xmlns : android= "http : / /schemas . android . com/apk/ res /android" android : layout_width= " fi l l_pa rent" android : layout_height= " fi l l_parent " android : gravity=" center" android : orientation="vertica l " >

< Progres sBar android : id=" @ +id/progress "

s tyle= " ?android : attr/progressBarStyleHori zontal "

android : layout_width= " fi l l_parent " android : layout_height= "wrap_content "

<LinearLayout android : id= " @ +id/LinearLayoutO l "

android : layout_width="wrap_content " android : layout_height="wrap_content "

android : orientation= " hori zontal " android : padding= " l Opx " >

<Button

android : id=" @ +id/button start "

android : layout_height="wrap_content "

android : text= " Start " android : layout_width= " B Opx " / >

<Button

android : id= " @ + id/button_stop" android : layout_height="wrap_content" android : text=" S top"

android : layout_width= " B Opx" / >

</LinearLayout>

</ LinearLayout>

В классе ProgressBarActivity создадим отдельный nоток, работающий доста­точно длительное время, состояние которого будем Qтображать в Progres sBar.

Код класса Progres sBarActivity nредставлен в л истинге 6 .25 .

package com . android . progressba r ;

import android . app . Activity ;

import android . os . Bundle ;

Page 131: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

124

import android . os . Handler ;

import android . os . Message ;

import android . util . Log ;

import android . view . View;

import android . view . View . OnGl ickListene r ;

import android . widget . Button ;

import android . widget . ProgressBa r ;

puЬlic class ProgressBarAct ivity extends Activity

private Progres sBa r mProgressBa r ;

private boolean mi sRunning false ; private Handler mНandle r ;

@Override

puЬl ic void onCreate ( Bundle s avedinstanceState )

supe r . onCreate ( savedinstanceStat e ) ;

setContentView ( R . layout . main ) ;

mProgres sBar ( ProgressBa r ) findViewByid ( R . id . progress ) ;

final Button ButtonStart

( Button) findViewByid ( R . id . button_start ) ;

final Button ButtonStop =

( Button ) findViewByid ( R . id . button_stop ) ;

mНandler new Handler ( )

} ;

@Override

puЬlic void handleMes sage (Message msg)

mProgressBa r . incrementProgressBy ( l ) ;

1 1 запуск ProgressBar

ButtonStart . setOnCl ickListener ( new OnClickListene r ( )

@Override

puЬlic void onClick (View v )

onStart ( ) ;

1 1 остановка ProgressBar

ButtonStop . setOnClickLis tener ( new OnCl ickListene r ( ) {

@Override

puЬlic void onClick (View v) {

Глава б

Page 132: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

Базовые виджеты

onStop ( ) ;

1 1 создаем новый поток

puЬlic void onStart ( )

supe r . onStart ( ) ;

mProgressBar . setProgress ( O ) ;

1 1 создаем новый поток

Thread background = new Thread ( new RunnaЬle ( )

puЬ l i c void run ( ) { while (misRunning )

} ) ;

try { Thread . s leep ( l O O ) ;

catch ( InterruptedException е ) {

Log . e ( "ERROR" , "Thread Interrupted" ) ;

mНandle r . sendМessage (mНandler . obtainМessage ( ) ) ;

mi sRunning = t rue ;

background . start ( ) ;

puЬlic void onStop ( )

super . onStop ( ) ;

mi sRunning fal s e ;

125

Запустите проект на исполнение. Внешний вид программы представлен на рис. 6. 1 7 .

6. 7 . 2 . SeekBar

Виджет SeekBar - это слайдер (ползунок), который позволяет пользователю перемещать движок. Класс seekBar является расширением класса Progressвar.

Пользователь может коснуться пальцем или использовать клавиши курсора и переместить движок влево или вправо, чтобы установить нужное положе­ние.

Page 133: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

1 26 Глава 6

Рис. 6 . 1 7. Виджет Progres sBar в действи и

Для програм мнаго отслеживания перемещения ползунка seekвar необходимо реализовать вложенный интерфейс SeekBar . OnSeekBarChangeLi s t ener. Этот интерфейс объявляет три метода, которые необходимо переопределить в Act i vi tу-классе:

D onProgres s Changed ( ) - уведомление о том, что положение ползунка изме­нилось;

D onSta rtTrackingTouch ( ) - уведомление о том , что пользовател ь начал пе­ремещение ползунка;

D onStopTrackingTouch ( ) - уведомление о том, что пользователь закончил перемещение ползунка.

Основное событие виджета seekBar, которое используют для программнога

отслеживания перемещения ползунка, - SeekBar . OnSeekBa rChangeL i s t ener.

Для примера приложения 'с seekвa r создайте новый проект и в диалоге Create New Project введите следующие значения :

D Project name - SeekBar;

D Application name - SeekBar Sample;

D Package name - сот . sample s . seekba r;

D Create Activity - SeekBarActivity.

Page 134: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

Базовые виджеты 127

В файле разметки создайте контейнер Liш�arLayout, добавьте в него элемент

SeekBar и два текстовых поля для отображения значения, установленного слайдером, как показано в листинге 6.26.

<?xrnl vers ion= " l . O " encoding= "utf-9 " ?>

<LinearLayout xmlns : android="http : / /schemas . android . co�/apk/re s / android"

android : orientation="verti ca l "

android : layout_width= " fil l_parent "

android : layout_hei ght= " fi l l_parent "

android : gravity= " center"

android : padding=" l Opx " >

<SeekBa r

android : id= " @ + id/seek bar "

android : layout_height= "wrap_content "

android : layout_width= " fi l l_parent " />

<LinearLayout

android : layout_width= "wrap_content "

android : layout_height= "wrap_content "

android : padding= " l Opx" >

<TextView

android : layout_width= "wrap_content "

android : layout_height="wrap_content "

android : text="Value :

android : textStyle= "bold" />

<TextView

android : id=" @ +id/text value "

android : layout_width= "wrap_content "

android : layout_height="wrap_content "

android : text= " O "

android : textStyle="bold" />

< /LinearLayout>

</LinearLayout>

В классе seekBarActivity реал изуем обработку события остановки ползунка, значение которого будет выводиться в текстовое поле. Полный код класса приведен в листинге 6.27.

Page 135: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

1 28

package com . samples . seekЬa r ;

import android . app . Activity;

import android . os . Bundle ;

import android . widget . SeekBa r ;

import android . widget . TextView ;

puЬlic class SeekВarActivity extends Act ivity

implements SeekBar . OnSeekBarChangeListener

TextView mTextValue ;

@Override

puЬl i c void onCreate ( Bundle savedins tanceState )

super . onCreate ( s avedinstanceState ) ;

s etContentView ( R . layout . main ) ;

Глава 6

final SeekBar see kBar ( SeekВa r ) findViewByid ( R . id . seek_

bar ) ;

seekBar . setOnSeekBarChangeLi stener ( this ) ;

mTextValue ( TextView ) findViewByid ( R . ia . text_

value ) ;

mTextVa lue . setText ( " O " ) ;

1 1 обработка события остановки nолзунка @Ove rride

puЬ l i c void onStopTrackingTouch ( SeekBar seekВar ) { mTextValue . setText ( St ring . valueOf ( seekBar . getProgres s ( ) ) ) ;

1 1 остальные методы, реализующие интерфейс OnSeekBarChangeListener

11 в этой nрограмме исnоль зуются толь ко как заглушки @Override

puЬl i c void onProgres sChanged ( SeekBar seekBa r , int progres s ,

boolean fromU s e r ) { 1 / TODO Auto-generated method stuЬ

/ 1 TODO Сгенерированная автоматически заглушка для метода

@Override

puЬlic void onStartTrackingTouch ( SeekBar seekBa r )

1 1 TODO Auto-generated method stuЬ

1 1 TODO Сгенерированная автоматически заглушка для метода

Page 136: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

Базовые виджеты 1 29

Рис. 6. 1 8. Приложение с в иджетом SeekBar

Запустите проект на исполнение. Внешний вид програм мы представлен на рис. 6 . 1 8 . При перемещении ползунка в текстовом поле будет отображаться его текущее значение.

6. 7 . 3 . RatingBar

Виджет Rat ingвar - расширение классов AЬsSeekBar и ProgressBar, который показывает значение рейтинга в виде звездочек. Пользователь может касани­ем пал ьца или с помощью клавиш курсора устанавливать оценку (рейтинг), используя заданное заранее максимальное кол ичество звездочек в элементе Ratingвar. Элемент RatingBar также может отображать рейтинг в режиме без взаимодействия с пользователем "только для чтения"

Основные методы, используемые при работе с RatingBar:

О setNumStars ( int ) - устанавливает количество звездочек;

О getRating ( ) - возвращает значение рейтинга;

О isindicator ( ) - устанавливает Rat ingBar в режим "тол ько для чтения" ;

О setRat ing ( floa t ) - устанавливает значение рейтинга;

О setStepSize ( float ) - устанавливает значение приращения рейтинга.

Кроме того, Rat ingBar имеет вложенный интерфейс OnRatingBarChange­

Listener для реал изации отслеживания изменения рейтинга в приложении.

Page 137: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

130 Глава 6

Для примера приложения с RatingBar создайте новый проект и в диалоге Create New Project введите следующие значения:

D Project name - Rat ingBar;

D Application name - RatingBar Sample;

D Package name - сот . samples . ratingbar;

D Create Activity - RatingBarActivity.

В файле разметки создайте контейнер LinearLayout, добавьте в него Progressвar, две кнопки, Up и Down, и текстовые поля для отображения рей­тинга в числовом виде (листинг 6.28).

< ? xrnl version= " l . O " encoding= "utf-8 " ?>

<LinearLayout xrnlns : android=" http : / /schernas . android . com/apk/ re s / android"

android : orientation= "vertica l "

android : layout_width= " fi l l_parent "

android : layout_height= " fi ll_parent "

android : gravity= " center ">

<RatingBar

android : id=" @ + id/rating "

android : layout_width="wrap_content "

android : layout_height="wrap_content " / >

<LinearLayout

android : layout_width= "wrap content "

android : layout_height= "wrap_content "

android : padding=" 2 0px " >

<Button

android : id=" @ +id/button_up "

android : layout_height="wrap_content "

android : text="Up "

android : layout_width= " бOpx " / >

<Button android : id=" @ +id/button down "

android : layout_height="wrap_content "

android : text= " Down"

android : layout_width= " бOpx " />

<TextView

android : layout_width= "wrap_content "

Page 138: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

Базовые виджеты

android : layout_height="wrap content "

android : text= "Value :

android : padding= " ! Opx "

android : textStyle= "bold " />

<TextView

android : id= " @+id/text value "

android : layout_height="wrap_content "

android : layout_width=" 4 0px "

android : textStyle= "bold" / >

< /LinearLayout>

< /LinearLayout>

131

В классе RatingвarActivity реал изованы методы обратного вызова для кно­nок U р и Down, устанавливающие значения рейтинга без контакта nользова­

теля с элементом RatingBar, и обработчик события OnRatingBarChangeLi stener

для отображения изменения численного значения рейтинга (листинг 6 .29).

package com . samples . ratingba r ;

import android . app . Activity;

import android . os . Bundle ;

import android . view . View;

import android . view . View . OnCl ickListene r ;

import android . widget . Button ;

import android . widget . RatingBa r ;

import android . widget . TextView ;

import android . widget . RatingBar . OnRatingBarChangeListene r ;

puЬlic class RatingBarActivity extends Activity

private static final int NUМ STARS 5 ;

private float mStep 0 . 5 f ;

private float mRat ing l . O f ;

@ Override

puЫic void onCreate ( Bundle savedins tanceState )

super . onCreate ( s avedinstanceState ) ;

setContentView ( R . layout . main ) ;

Page 139: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

132

final RatingBar ratingBar l

( RatingBar ) findViewByid ( R . id . rating ) ;

final Button buttonUp

( Button ) f indViewByid ( R . id . button_

up ) ;

final Button buttonDown

( Button ) findViewByid ( R . id . button_

down ) ;

f inal TextView l abel

( TextView) findViewByid ( R . id . text_

value ) ;

ratingBarl . setNumStars ( NUМ_

STARS ) ;

rat ingBarl . setRating (mRat ing ) ;

rat ingBarl . setStepS ize ( 0 . 5f ) ;

label . setText ( String . valueOf (mRating ) ) ;

buttonUp . s etOnClickLis tener ( new OnCl i ckLis tene r ( )

@Override

puЬ l i c void onClick ( View v )

mRating += mStep ;

i f (mRating > NUM_

STARS )

mRating NUМ_

STARS ;

rat ingBa r l . setRat ing (mRating ) ;

buttonDown . setOnClickLis tene r ( new OnCl ickListener ( )

@Override

puЫ i c void onClick (View v )

mRating - = mStep ;

i f (mRating < 0 )

mRating О ; rat ingBarl . setRa ting (mRating ) ;

ratingBarl . setOnRat ingBarChang�Lis tene r (

new OnRat ingBarChangeLis tener ( )

@Override

puЫ i c void onRat ingChanged (

Rat ingBar ratingBar , f loat rat ing ,

Глава 6

boolean frornU s e r ) { label . setText ( St ring . valueOf ( ratingBa r l . getRating ( ) ) ) ;

mRating rat ingBarl . getRa t ing ( ) ;

Page 140: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

Базовые виджеты 1 33

Запустите проект на исполнение. Внешний вид программы представлен на рис. 6 . 1 9 . Приложение позволяет пользователю взаимодействовать с

Rat ingBar двумя способам и : используя сенсорн ый режим, устанавливая зна­

чение рейтинга в RatingBa r касанием звездочек пал ьцем, и через кнопки Up и Down.

Р ис. 6 . 19 . Приложение с виджетом Rat ingBar

6.8 . Ком поненты отображен ия времени Виджеты для отображения времени представлены тремя классам и :

D AnalogClock;

D Digi talClock;

D Chronorneter.

Для вывода системного времени используются виджеты Digita lClock и AnalogClock. Они чрезвычайно удобны, поскольку автоматически синхрони­зируются с системным временем . Иерархия классов для Ana logClock,

DigitalClock и Chronorneter представлена на рис. 6 .20 .

Page 141: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

1 34

1 Object 1 г-----,

View 1 г------,

TextView 1 .------, f--------1 AnalogCiock 1

DigitaiCiock 1 '------1 Chronometer 1

Глава 6

Рис. 6.20. Иерархия классов для AnalogClock, Digi talClock и Chronorneter

6.8 . 1 . AnalogC/ock и Digita/Ciock

Виджеты AnalogClock и DigitalClock очень простые и служат только для ото­бражения системного времени пользователю. Для примера приложения с этими виджетами создайте новый проект и в диалоге Create New Project введите следующие значения :

D Project name - AnalogClockApp;

D Application name - AnalogClock Sarnple;

D Package name - сот . samples . analogclock;

D Create Activity - AnalogClockActivity.

Откройте файл разметки и создайте структуру разметки подобно листин­гу 6 .30 .

< ?xrnl version= " . 0 " encoding= "ut f-8 " ?>

<RelativeLayout xrnlns : android= "http : / /schernas . android . com/apk/ res /android"

android : orientation="vertical " android : layout_width= " fi l l_parent "

android : layout_height=" fi l l_parent " >

<AnalogClock android : id=" @ +id/analog " android : layout_width= " fi l l_parent " android : layout_height="wrap_content " android : layout_centerHori zontal= " t rue " android : layout_alignParentTop= " t rue " />

<DigitalClock android : id= " @+id/digital " android : layout_width= "wrap_content " android : layout_height= "wrap_content "

android : layout_centerHori zontal= " t rue "

Page 142: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

Базовые виджеты

android : layout_be low= " @ id/analog"

android : textStyle= "bold" andro id : text S i z e= " 4 0 s p " />

</RelativeLayout>

1 35

Запустите проект на испол нение. Внешний вид экрана приложения с часами представлен на рис. 6 .2 1 .

Рис. 6.21 . Виджеты для отображения времени

6.8 .2 . Chronometer

Виджет Chronomete r - это управляемый таймер. Он позволяет пол ьзователю запускать и останавли вать начальный отсчет времени, задавать время запуска таймера.

Основные методы для работы с виджетом Chronometer:

О s tart ( ) - запускает отсчет времени ;

О s top ( ) - останавливает отсчет времени ;

О s e t Format ( ) - задает формат отображения времени . По умолчанию теку-щее значение таймера отображается в формате "MM : SS" ил и " H : M M : SS"

Класс Chronometer имеет вложенный интерфейс OnChronometerTi ckLi s tener,

который содержит два метода:

О getOnChronometerTi ckLi stene r ( ) ;

О setOnChronometerTi ckLis tene r ( ) .

Page 143: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

136 Глава б

Эти методы предназначены для реал изации отслеживания изменения значе­ния таймера в приложении.

Для примера приложения, испол ьзующего виджет Chronometer, создайте но­вый проект и в диалоге Create New Project введите следующие значения :

О Project name - Chronomete rApp;

о Application name - Chronometer Sample;

О Package name - сот . samples . chronometer;

О Create Activity - ChronometerActivity.

В файле разметки создайте корневой контейнер LinearLayout, в котором по­местите элемент Chronometer и три кнопки для управления виджетом - Start, Stop и Reset (листинг 6 .3 1 ) .

< ?xml ve rsion= " l . O " encoding= " ut f- 8 " ?>

<LinearLayout xmlns : android="http : / /schemas . android . com/ apk/re s / android" android : orientation="vertica l " android : layout_width=" fi l l_parent " android : layout_height= " fi l l_parent " android : gravity= " center">

<Chronometer android : id=" @ +id/chronometer" android : layout_width="wrap_content " apdroid : layout_height="wrap_content " android : textSize= " З бpx " android : gravity=" cente r " / >

<LinearLayout android : id=" @ +id/LinearLayout O l " android : layout_width= "wrap_content " android : layout_height="wrap_content " >

<Button android : id=" @ + id/button start "

android : layout_width="wrap_content " android : layout_height="wrap_content "

android : text="Start " / > <Button

android : id=" @ +id/button_stop" android : layout_width="wrap_content " android : layout_height= "wrap_content " android : text=" Stop " />

Page 144: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

Базовые виджеты

<Button

android : id=" @ +id/button reset "

android : layout_width= "wrap_content "

android : layout_height="wrap_content "

android : text="R�set " / >

</LinearLayout>

< /LinearLayout>

137

В классе ChronometerActivity напишите обработчики событий кнопок для запуска, остановки и сброса таймера, как показано в листинге 6.32.

package com . samples . chronomete r ;

import android . app . Activity;

import android . os . Bundle ;

import android . os . SystemClock ;

import android . view . View ;

import android . view . View . OnClickListener ;

import android . widget . Button ;

import android . widget . Chronomete r ;

puЫ ic class ChronometerActivity extends Activity

@ Override

puЫ i c void onCreate ( Bundle s avedlnstanceState ) supe r . onCreate ( savedlnstanceStat e ) ;

setContentView ( R . layout . main ) ;

1 1 загружаем виджеты из ресурсов

final Button buttonStart

( Button ) findViewByld ( R . id . button_start ) ;

final Button buttonStop

( Button ) findViewByld ( R . id . button_stop ) ;

final Button buttonReset

( Button ) findViewByid ( R . i d . button_reset ) ;

final Chronometer mChronometer

( Chronometer ) findViewByld ( R . id . chronomete r ) ;

1 1 обработчик события запуска

buttonStart . setOnClickListener ( new OnClickListener ( ) { @Override

Page 145: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

138

puЬ l i c void onCl i c k (View v )

mChronomet e r . s t a rt ( ) ;

1 1 обработчик события остановки buttonStop . se tOnC l i ckL i s t ene r ( new OnCl ickLi stene r ( )

@Ove rride

puЬ l i c vo id onCl i c k (View v )

mChronomete r . stop ( ) ;

1 1 обработчик события сброса buttonRe s e t . s etOnC l i ckLi s tener ( new OnClickLis tene r ( )

@Ove rride

Глава 6

puЬ l i c void onC l i c k ( View v ) {

mChronomet e r . setBase ( Sys temClock . e l apsedRealt ime ( ) ) ;

Запустите проект на вы полнение. Внешний вид экрана приложения с видже­том Chronometer и кнопкам и для его управления представлен на рис. 6 .22.

Рис. 6 .22 . Приложение с виджетом Chronometer

Page 146: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

Г Л А В А .7

Виджеты-сп иски и п ривязка данн ых

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

7 .1 . Адаптеры дан н ых Для отображения массивов данных в виджетах применяются адаптеры, кото­рые предназначены для связывания списка данных и отображающего эти данные виджета. Самым простым адаптером для использования при связыва­

нии данных является шаблонный класс ArrayAdapter<T>. Он создает оболочку вокруг массива данных, например, так:

St ring [ ] items= { "one " , "to" , " t ree" } ;

ArrayAdapte r<St ring> adapte r new ArrayAdapter<String>

( thi s , android . R . layout . s imple_l ist_item_l , items ) ;

Конструктор ArrayAdapter принимает три параметра:

D объект Context - обычно это экземпляр класса, реализующий Act ivity.

Класс context предоставляет интерфейс среды выполнения прикладной програм мы . context позволяет получить доступ к специфическим для при­ложения ресурсам и классам , а так же запрашивает операции на уровне приложения, таких, например, как запуск деятельности, передача и полу­чение намерений и т. д . ;

D используемы й идентификатор ресурса представления. В данном приме­

ре - встроенный системный идентификатор ресурса s imple_l i st_item_l .

Встроенные идентификаторы ресурса - это константы, определенные в классе android . R . layout, например s imple_spinner_dropdown_item, s imple

Page 147: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

1 40 Глава 7

gallery i tem, s imple _l ist _ i tern _ checked и др . , которые, как правило, соот­

ветствуют стандартным виджетам;

О массив или список типа List<T> объектов для отображения в виджете.

По умолчанию ArrayAdapte r вызывает метод toString ( ) для объектов списка и создает оболочку для каждой строки в представлении определяемым

встроенным системным идентификатором ресурса. R . layout . s irnple _l ist _

i tern_ 1 просто превращает эти строки в объекты TextView, являющиеся, на­пример, элементами контейнерного виджета ListView (или любого другого виджета-списка).

Можно также создать собственный класс, наследуемый от класса

ArrayAdapter, и переопределить в нем метод getView ( ) для привязки ваших собственных виджетов, как будет показано далее в этой главе.

7 .2 . Текстовые поля с автозапол нением Текстовые поля с автозаполнением в Aпdroid представлены двумя классами:

О AutoCornpleteTextView;

О MultiAutoCornpleteTextView.

Эти классы наследуют все методы для работы с текстом от класса тextView

и редактирования текста от класса Editтext . Иерархия классов текстовых по­лей с автозаполнением представлена на рис. 7 . 1 .

TextView

EditText

Рис. 7.1 . Иерархия классов текстовых полей с автозаполнением

7 . 2 . 1 . A utoComplete TextView

Виджет AutoCornpleteTextView - это текстовое поле с автозаполнением и возможностью редактирования вводимого текста. Такие виджеты очень по­лезны в мобильных приложениях, когда вы хотите ускорить процесс ввода текста в приложении .

Page 148: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

Виджеты-списки и привязка данных 1 4 1

Поскольку AutoCompleteTextView является подклассом Editтext, он позволяет использовать все возможности форматирования и редактирования текста. Кроме того, у AutoCompleteTextView есть свойство android : completion­

Threshold для указания минимального числа символов, которое должен вве­сти пользователь прежде, чем начинает работать функция автозаполнения списка. Для связывания с данными виджету AutoCompleteTextView необходим адаптер, содержащий список значений кандидата через setAdapte r ( ) .

Для практического примера приложения с элементом AutoCompleteTextView

создайте новый проект и в диалоге Create New Project введите следующие значения :

О Project name - AutoCompleteTextViewApp;

О Application name - AutoCompleteTextViewSample;

О Package name - сот . samples . autocompletetextview;

О Create Activity - AutoCompleteTextViewActivity.

Откройте файл разметки и создайте структуру разметки подобно листингу 7 . 1 .

< ?xml ve rsion= " . 0 " encoding="ut f- 8 " ?>

<LinearLayout

xmlns : android="http : / /schemas . android . com/apk/res /android"

android : orientat ion="vert ical "

android : layout_width=" fi l l_parent "

android : layout_height=" fi l l_pa rent " >

<TextView

android : layout_width=" fi l l_parent "

android : layout_height="wrap_content "

androi d : id= " @ + id/text "

<AutoCompleteTextView

android : id=" @ +id/auto_complete "

android : layout_width= " fi l l_parent "

android : layout_height="wrap_content "

android : completionThreshold=" З " />

< /LinearLayout>

Реализация класса деятельности с элементом AutoCompleteTextView представ­лена в листинге 7 .2 . Набором данных для виджета в программе является обычный статический массив строк с именами и фамилиям и людей (конечно, в реальных приложениях так не делают), которые связаны через адаптер С AutoCompleteTextView.

Page 149: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

142

package com . samples . autocompletetextview ;

import android . app . Act ivity ;

import android . os . Bundle ;

import android . text . EditaЬle ;

import android . text . TextWatcher ;

import android . widget . ArrayAdapte r ;

import android . widget . AutoCompleteTextView ;

import android . widget . TextView ;

puЬlic class AutoCompleteTextViewActivity extends Activity

implements TextWatcher

TextView mText ;

AutoCompleteTextView mAutoComplete ;

final St ring [ ] mContacts

"Jacob Anderson " , "Emily Duncan" , "Michae l Fuller" ,

Глава 7

"Emma Greenman" , " Joshua Harrison" , "Madison Johnson" ,

"Matthew Cotman" , "Ol ivia Lawson" , "Andrew Chapman" ,

"Michael Honeyman" , " Isabella Jackson" , "William Patterson " ,

" Joseph Godwin" , " S amantha Bush" , "Christophe r Gateman " } ;

@ Override

puЬlic void onCreate ( Bundle savedinstanceState )

super . onCreate ( savedinstanceState ) ;

setContentView ( R . layout . main ) ;

mText ( TextView ) findViewByid ( R . id . text ) ;

mAutoComplete= (AutoCompleteTextView ) findViewByid (

R . id . auto_complete ) ;

mAutoComplete . addTextChangedLi stener ( this ) ;

mAutoComplete . setAdapter ( new ArrayAdapter<String> ( thi s ,

android . R . layout . s imple_dropdown_item_l line , mContacts ) ) ;

puЬl ic void onTextChanged (

CharSequence s , int start , int before , int count )

mText . setText (mAutoComplete . getText ( ) ) ;

puЬl i c void beforeTextChanged (

CharSequence s , int start , int count , int a fter ) {

Page 150: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

Виджеты-списки и привязка данных 1 43

puЬl i c void afterTextChanged ( Edi taЬle s )

Запустите проект на выполнение. При наборе текста в окне виджета будут отображаться варианты автозапол нения (рис. 7 .2) .

joshua Ha rr ison

joseph Godwi n

Рис. 7.2. Пример виджета AutoCompleteTextView

7 . 2 . 2 . MultiA utoComplete TextView

Виджет Mult iAutoCompleteTextView - это текстовое поле с автозаполнением и возможностью редактирования текста, расширяющее функциональность

AutoCompleteTextView, который может показывать автозаполнение для каждой из подстрок текста, разделенных знаком пунктуации . Разделитель задается

явно вызовом метода setTokeni zer ( ) :

MultiAutoCompleteTextView textView

(MultiAutoCompleteTextView ) findViewByid (

R . id . Mult iAutoCompleteTextViewO l ) ;

textView . setAdapter ( adapter ) ;

устанавливаем разделитель для подстрок текста

textView . setTokeni zer ( пew Mul tiAutoCompleteTextView . CommaTokeпizer ( ) ) ;

Page 151: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

1 44 Глава 7

Покажем на примере работу Mul tiAutoCornpleteTextView. Создайте новый про­ект и в диалоге Create New Project введите следующие значения:

о Project name - Mul tiAutoCornpleteTextViewApp;

О Application name - MultiAutoCornpleteTextView Sarnple;

О Package name - corn . sarnples . rnul t iautocornpletetextview;

О Create Activity - MultiAutoCornpleteTextViewActivity.

Откройте файл разметки и создайте структуру разметки подобно листингу 7.3 .

<?xrnl version= " l . O " encoding="utf- 8 " ?>

<LinearLayout xrnlns : android="http : / /schernas . android . com/apk / res / android"

android : orientation="vertica l "

android : layout_width=" fi l l__parent "

android : layout_height=" fi l l__parent ">

<MultiAutoCornpleteTextView

android : id=" @ +id/MultiAutoCornpleteTextViewO l "

android : layout_height="wrap_content "

android : layout_width=" fi l l_parent " / >

< /LinearLayout>

Для того чтобы можно было различать подстроки в строке данных, необхо­димо вызвать метод setTokenizer ( ) :

textView . setTokeni zer ( new Mult iAutoCornpleteTextView . CommaTokenizer ( ) ) ;

Инициализация и привязка к данным для Mul tiAutoCornpleteTextView в основ­ном похожа на работу с AutoCornpleteTextView из листинга 7 .2 . Претерпел изменения только набор текстовых данных, в каждую строку которых была добавлена запятая для разделения на подстроки (листинг 7 .4) .

package corn . sarnples . autocornpletetextview ;

irnport android . app . Activity;

irnport android . os . Bundle ; irnport android . widget . MultiAutoCornpleteTextView ;

irnport android . widget . ArrayAdapte r ;

Page 152: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

Виджеты-списки и привязка данных

puЬlic class MultiAutoCornpleteTextViewActivity extends Activity

1 1 массив даннь� для отображения списка final St ring [ ] rnContacts

"Anderson, Jacob" , " Duncan, Erni ly" , " Fuller, Michael " , "Greenrnan, Ernrna " , "Harrison, Joshua " , " Johnson , Madison " , "Cotrnan , Matthew" , "Lawson , Olivi a " , "Chaprnan , Andrew" , "Honeyrnan , Michael " , " Jackson, I sabella " , " Patterson , Wil liarn" , "Godwin, Joseph" , "Bush, Sarnantha " , "Gaternan , Christopher" } ;

@ Override puЬlic void onCreate ( Bundle savedinstanceState )

super . onCreate ( savedins tanceState ) ; setContentView ( R . layout . rnain ) ;

ArrayAdapter<St ring> adapter new ArrayAdapter<String> (

1 45

thi s , android . R . layout . s irnple_dropdown_itern_l l ine , rnContacts ) ;

Mult iAutoCornpleteTextView textView (MultiAutoCornpleteTextView) findViewByid (

R . id . Mult iAutoCornpleteTextViewO l ) ;

textView . setAdapter ( adapter ) ; textView . setTokenizer (

new Mult iAutoCornpleteTextView . CornrnaTokeni zer ( ) ) ;

Harr ison , joshua

joh nso n , Mad ison

Godwi n , joseph

Р и с . 7 . 3 . Виджет Mult iAutoCornpleteTextView в приложении

Page 153: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

146 Глава 7

Запустите проект на выполнение. Получившееся приложение представлено на рис. 7 .3 . Здесь видно, как виджет при вводе текста пользователем отобра­жает варианты автозаполнения с учетом разбиения на подстроки элементов списка.

7 .3 . Отображен ие дан н ых в сп исках Элементы-списки в Android представляют пять классов:

о ListView;

о GridView;

о Gallery;

о Spinner;

о SlidingDrawer.

Это контейнерные виджеты, которые (кроме SlidingDrawer) являются под­классами AdapterView. Эти виджеты можно использовать для связы вания с определенным типом данных и отображения их пользователю. Иерархия классов списков представлена на рис. 7 .4 .

1 Object 1 г-----,

View 1 г------, � ViewGroup 1 г------, 1-------1 AdapterView j ,----....,

AbslistView 1 l

,----...., GridView 1 ListView 1

AbsSpinner 1 г-----, 1 Gallery

Spinner 1 '--------1 S l id ingDrawer 1 1 Рис. 7.4. Иерархия классов списков

Класс Adapte rView предоставляет две основные функциональности для рабо­ты со списками :

О заполнение схемы размещения с данными ;

О обработку выбора элемента данных пользователем .

AdapterView - подкласс ViewGroup, дочерние представления которого опреде­лены объектом Adapter, который связывает их с данными некоторого типа.

Page 154: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

Виджеты-списки и привязка данных 1 4 7

Объект Adapter действует подобно курьеру между вашим источником данных

(например, массивом строк) и AdapterView, который отображает эти данные.

Есть несколько реализаций класса Adapter для определенных задач, например CursorAdapter для чтения данных из объекта Cursor ил и ArrayAdapter для чте­ния из произвольнога массива. Иногда необходимо заполнить группу пред­ставлений небольшим количеством информации, которая не может быть же­стко закодирована, а будет связана с внешним источником данн ых, например базой данных SQLite. Чтобы сделать это, необходимо использовать объект AdapterView как группу представлений и каждый дочерний View инициализи­ровать и заполнять данными от объекта Adapter. Подробнее об этом будет рассказано в главе 15 .

Класс AdapterView я вляется базовым для класса AЬsListView, который может использоваться для реализации классов виджетов, представляющих списки

и таблицы (ListView и GridView) , и класса AЬs Spinner - для выпадающих списков и галереи с прокруткой (Gallery и Spinne r) .

7 . 3 . 1 . ListView

Элемент ListView представляет собой вертикальный список с прокруткой . Связанные со списком данные ListView получает от объекта ListAdapter.

В отличие от предыдущих примеров, когда мы использовал и в качестве базо­вого класса Act ivity, при работе с ListView в качестве базового применяется класс ListAct i vi ty.

Класс ListAct ivity реализует отображение списка элементов, привязанных к источнику данных, например к массиву, и набор методов обратного вызова для обработки событий выбора элементов списка данных, т. е . ListAct ivity

является хостом для объекта ListView, который может быть связан с различ­ными источниками данных. У ListActivity есть заданная по умолчанию раз­метка, которая состоит из единственного списка, растянутого на весь экран (точнее - на родительский контейнер).

Для связывания объекта Li stAct ivity с данными необходимо разработать класс, который реал изует интерфейс ListAdapter. Android обеспечивает два стандартных адаптера списка:

О S impleAdapter;

О S impleCursorAdapter.

s impleAdapter применяется для статического связывания данных неболь­шого объема. S impleCursorAdapter используется, как правило, при формиро­вании выборки из больших массивов данных и будет рассматриваться в главе 15 .

Page 155: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

148 Глава 7

В качестве примера использования элемента ListView в приложении создайте новый проект и в диалоге Create New Project введите следующие значения :

D Project name - ListViewApp;

D Application name - ListView Sample;

D Package name - сот . samples . l istview4 ;

D Create Activity - ListViewAct ivity.

Откройте файл разметки и создайте структуру разметки с контейнером LinearLayout 'И вложенными виджетами ListView для отображения списка и TextView для отслеживания события выбора элемента списка, как в лис­тинге 7 . 5 .

< ? xrnl version=" . 0 " encoding="ut f-8 " ?> <LinearLayout

xrnlns : android="http : / /schernas . android . com/apk/ res /android" android : orientat ion="vert ical "

android : layout_width= " fi l l_parent "

android : layout_height= " fi l l_parent " >

<TextView

android : id=" @ +id/text Select " android : layout_width= " fi l l_pa rent " android : layout_height= "wrap_content " android : textStyle= "bold" />

<ListView android : id= " @ android : id/ l i s t "

android : layout_width= " fi l l_parent "

android : layout_height= " fi l l_parent " android : drawSelectorOnTop=" false " />

</LinearLayout>

У ListAct ivity есть заданная по умолчанию разметка, которая состоит из единственного списка, растянутого на весь экран .

package corn . samples . l i stview;

irnport android . app . ListAct ivity;

irnport android . os . Bundle ;

Page 156: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

Виджеты-списки и привязка данных

import android . view . View;

import android . widget . ArrayAdapte r ;

import android . widget . ListView ; import android . widget . TextView ;

puЬlic class ListViewActivity extends ListAct ivity

,private TextView mTextView;

St ring [ ] mContacts

" Jacob Ande rson" , "Emi ly Duncan " , "Michael Fulle r " ,

" Emma Greenman " , " Joshua Harri son" , "Madi son Johnson " , "Matthew Cotman " , "Olivia Lawson " , "Andrew Chapman" ,

" Daniel Honeyman" , " I s abella Jackson" , "Wi lliam Patterson" ,

" Joseph Godwin" , "Samantha Bush" , "Christopher Gateman" ) ;

@Override

puЬlic void onCreate ( Bundle savedinstanceState )

super . onCreate ( savedinstanceStat e ) ;

setContentView ( R . layout . main ) ;

setListAdapte r ( new ArrayAdapter<String> (

thi s , android . R . layout . s imple_l ist_item_l , mContacts ) ) ;

mTextView ( TextView ) findViewByid ( R . id . textSelec t ) ;

puЬlic void onListitemClick (

Lis tView parent , View v, int pos i t ion , long id)

mTextView . setText ( " Select : + mContacts [ position ] ) ;

1 49

Запустите проект на выполнение. При выборе элемента списка в окне тексто­вого поля вверху окна деятельности будет отображаться содержимое вы­бранного элемента (рис. 7 . 5 ) .

7 . 3 . 2 . Spinner

Виджет Spinner - это аналог СоmЬоВох (выпадающий список) для Android . При нажатии кнопки на элементе или центральной кнопки на О-клавиатуре устройства появляется список опций с радиокнопками, который, в отличие от элемента Lis tView, не занимает весь экран .

Основное событие элемента Spinner, которое реализуют в программе, ис­пользующей Spinner, - это событие выбора пункта списка. Для этого в коде

Page 157: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

1 50 Глава 7

Рис. 7 .5 . Приложение с виджетом L i s tView

программ ы необходимо реализовать методы обратного вызова on itemSelected ( ) и onNothingSelected ( ) , которые объявлены в интерфейсе Adapte r\7iew . On i t emSele ctedL i s t ene r.

Для примера приложения с использованием выпадающего списка создайте новый проект и в диалоге Create New Project введите следующие значения :

О Project name - Spinne rApp;

О Application name - Spinne r S ample;

О Package name - сот . s amp l e s . spinne r;

О Create Activity - Spinne rActivity.

Откройте файл разметки и создайте структуру разметки подобно листингу 7.7

< ? xml ve r s i on= " . 0 " encoding= " ut f-8 " ? >

<Linea rLayout xmlns : andro id= " http : / / s chema s . android . com/apk / re s /android"

android : orientation="vert i ca l "

android : layout_width= " fi l l_pa rent "

andro id : layout_he ight= " fi l l_pa rent "

<TextView

android : id= " @ + id/TextViewO l "

Page 158: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

Виджеты-списки и привязка данных

android : layout_width= " fi l l_parent "

android : layout_height= "wrap_content " / >

<Spinner android : id= " @ + id/SpinnerO l "

android : layout_width= " f i l l_parent "

android : layout_height="wrap_content "

android : drawSelectorOnTop="true " />

</LinearLayout>

1 5 1

Для заполнения списка данными используйте все тот же массив строк из лис­тинга 7 .2 . Полный код класса SpinnerAct ivi ty представлен в листинге 7 .8 .

package com . samples . spinne r ;

import com . samples . spinner . R ;

import android . app . Activity;

import android . os . Bundle ;

import android . view . View;

import android . widget . AdapterView ;

import android . widget . ArrayAdapte r ;

import android . widget . Spinner ;

import android . widget . TextView;

puЬlic class Spinne rActivity extends Activity

implements Adapte rView . OnltemSelectedListener

TextView mLabel ;

1 1 массив данных для списка

final St ring [ ] mContact s

" Jacob Anderson " 1 "Emily Duncan" 1 "Michael Fuller" 1

"Emma Greenman" 1 " Joshua Harrison " 1 "Madi son Johnson " 1

"Matthew Cotman" 1 "Olivia Lawson" 1 "Andrew Chapman " 1

"Michael Honeyman" 1 " Is abella Jackson " 1 "William Patterson" 1

" Joseph Godwin" 1 " Samantha Bush" 1 "Christopher Gateman " } ;

@Override

puЬlic void onCreate ( Bundle s avedinstanceState )

super . onCreate ( savedinstanceState ) ;

setContentView ( R . layout . main ) ;

Page 159: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

1 52

mLabel ( TextView) findViewByid ( R . id . TextVi ewO l ) ;

final Spinner spin ( Spinner ) findViewByid ( R . id . SpinnerO l ) ;

spin . setOniternSelectedLi stener ( thi s ) ;

Глава 7

ArrayAdapter<St ring> arrayAdapter new ArrayAdapter<String> ( thi s , android . R . layout . s irnple_spinner itern, rnContacts ) ;

arrayAdapter . setDropDownViewResource (

android . R . layout . s irnple_spinner_dropdown_itern) ;

spin . setAdapter ( a rrayAdapte r ) ;

puЬlic void oni ternSelected (

Adapte rView< ? > parent , View v, int pos ition , long i d )

mLabel . setText (rnContacts [ position ] ) ;

puЬl ic void onNothingSelected (AdapterView< ?> parent )

mLabel . setText ( " " ) ;

Isa bella jackson

Williarn Pattersoп

Рис. 7.6. Приложен ие с виджетом Spinner

Page 160: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

Виджеты-списки и привязка данных 153

Запустите проект на выполнение. В нешний вид приложения с виджетом Spinne r и открытым выпадающим списком представлен на рис. 7 .6 .

7 . 3 . 3 . GridView

Виджет GridView представляет собой плоскую таблицу. Для GridView, вместо того чтобы использовать автоматически генерируемые виджеты TextView, как в случае с элементом Lis tView, можно использовать собственные поля для отображения элементов данных, создав класс, производный от класса ArrayAdapte r, и переопредел ив его метод getView ( ) .

Число столбцов для GridView чаще задается статически. Число строк в эле­менте определяется динамически на основании числа элементов, которые предоставляет адаптер.

Есть несколько свойств, которые определяют число столбцов и их размеры:

О android : numColшnns - определяет количество столбцов. Если поставлено значение auto _ fi t, то система вычислит количество столбцов, основанное на доступном пространстве;

О android : vertical Spacing - устанавливает размер пустого пространства между ячейками таблицы;

О android : colшnnWidth - устанавливает ширину столбцов;

О android : stretchМode - указывает, куда распределяется остаток свободно­го пространства для таблицы с установленным значением android : numColшnns="auto_fit " . Принимает значения colшnnWidth для рас­пределения остатка свободного пространства между ячейкам и столбцы для их увеличения или spacingWidth - для увеличения пространства меж­ду ячейками .

В качестве примера использования элемента GridView в приложении для ото­бражения текстовой информации создайте в Ecl i pse новый проект и в диалоге Create New Project введите следующие значения :

О Project name - GridViewApp;

О Application nаше - GridView Sample;

О Package nаше - com . samples . gridview;

О Create Activity - GridViewActi vi ty.

Откройте файл разметки и создайте структуру разметки подобно листин­гу 7 .9 .

Page 161: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

1 54

< ?xml version= " l . O " encoding="ut f-8 " ?>

<LinearLayout

xmlns : android= "http : / / schemas . android . com/apk/ res/android"

android : orientat ion="vert ical "

android : layout_width= " fi l l_parent "

android : layout_height= " f i l l_parent " >

<TextView android : id= " @+id/ labe l "

android : layout_width= " fi l l_parent "

android : layout _ height=1 'wrap _ content " />

<GridView

android : id= " @+id/grid"

android : layout_width=" fi l l_parent "

android : layout_height= " fi l l_parent"

android : verticalSpacing= " 3 5px "

android : hori zontalSpacing= " 5px "

android : numColumns="auto fit"

android : columnWidth=" l OOpx "

android : stretchМode=" columnWidth"

android : gravity= "center"/>

</LinearLayout>

Глава 7

Код класса-оболочки для данных DataAdapter, производнаго от ArrayAdapter,

представлен в листинге 7 . 1 О .

package com . samples , gridview;

import android . content . Context ;

import android . view . View ;

import android . view . ViewGroup ;

import android . widget . ArrayAdapte r ;

import android . widget . TextView;

puЬlic class DataAdapter extends ArrayAdapter<String>

{ private static final String [ ] mContacts

" J . Anderson " , "Е . Duncan " , "М . Fuller" ,

"Е . Greenman" , " J . Harrison" , "М . Johnson " ,

Page 162: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

Виджеты-списки и привязка данных

"М . Cotman" , " 0 . Lawson" , "А . Chapman" ,

"М . Honeyman" , " I . Jackson" , "W . Patterson" ,

" J . Godwin" , " S . Bush" , " С . Gateman" ,

" J . Anderson" , "Е . Duncan" , "М . Ful ler " ,

"Е . Greenman" , " J . Harrison" , "М . Johnson" ,

" М . Cotman" , "О . Lawson" , "А . Chapman" ,

" М . Honeyman" , " I . Jackson" , "W . Patterson" , " J . Godwin" , " S . Bush" , " С . Gateman" } ;

Context mContext ;

DataAdapter ( Context context , int resource )

super ( context , resource, mContacts } ;

this . mContext context ;

puЬl ic View getView (

int pos ition, View convertView, ViewGroup parent ) TextView label ( TextView) convertView ;

i f ( convertView == nul l ) { convertView new TextView (mContext } ;

label (TextView } convertView;

label . setText (mContacts [ position ] } ;

return ( convertView } ;

1 1 возвращает содержимое выделенного элемента списка

puЬl ic String Get item ( int position }

return mContacts [ pos ition ] ;

1 55

Код класса деятельности GridViewActivity представлен в листинге 7 . 1 1 . В целом, GridView работает так же, как и любой другой элемент из рассмот­ренных ранее: для связывания данных и дочерних представлений использует­ся метод setAdapter ( 1 , для регистрации слушателя события выбора ячейки вызывается setOnitemSelectedLi stener ( } , и в коде класса деятельности реали­зуются методы onitemSelected ( ) и onNothingSelected ( } .

package com . samples . gridview;

import android . app . Activity;

import android . os . Bundle ;

Page 163: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

156

import android . view . View ;

import android . widget . AdapterView ;

import android . widget . GridView ;

import andro id . widget . TextView ;

puЬlic class GridViewActivity extends Activity

implements Adapte rView . OnitemSelectedListener

private TextVi ew mSelectText ;

private DataAdapte r mAdapter ;

@Ove rride

puЬlic void onCreate ( Bundle savedinstanceStat e )

supe r . onCreate ( savedinstanceState ) ;

s etContentView ( R . layout . main ) ;

mSe lectText= ( TextView ) findViewByid ( R . i d . label ) ;

final GridView g (GridView ) findViewByid ( R . id . grid) ;

mAdapte r new DataAdapte r ( getApplicat ionContext ( ) ,

android . R . layout . s imple_

l i s t_

item_

l ) ;

g . setAdapter (mAdapter ) ;

g . setOnitemSelectedLi stener ( this ) ;

@Ove rride

puЬ l i c void onitemSelected (AdapterView< ?> parent , View v ,

Глава 7

int pos it ion, l ong i d )

mSelectText . setText ( " Selected items : +

mAdapter . Get item (position ) ) ;

@ Ove rride

puЬlic void onNothingSelected (AdapterView< ?> parent )

mSe l ectText . setText ( " Selected items : none " ) ;

Запустите проект на выполнение. При выборе элемента списка в окне тексто­вого поля вверху экрана будет отображаться содержимое выбранного эле­мента (рис. 7. 7).

Page 164: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

Виджеты-списки и привязка данных 157

Рис. 7.7. Приложение с' виджетом GridView

7 . 4 . Отображен ие графики в сп исках В Andro id существуют специализированные виджеты для отображения гра­фической информации . Кроме того, в виджетах-списках помимо текстовых данных можно также отображать графику. В этом разделе мы рассмотрим привязку графических данных к виджету GridView и изучим еще два специа­лизированн ых виджета - Gallery и S l idingDrawer.

7.4. 1 . Отображение графи ки в GridView

Привязка графики к GridView не nредставляет никаких трудностей . Необхо­димо только источник данных (в нашем примере - это статический массив) связать с внешними изображениями, размещенными в ресурсах.

В качестве примера приложения с исnользованием GridView для отображения графической информации создайте в Ec l i pse новый nроект и в диалоге Create New Project введите следующие значения :

О Project name - GridViewimageApp;

О Application name - Grid'liew with Image Sample;

О Package name - com . samples . grid'Jiew;

О Create Activity - GridViewAct ivity.

Page 165: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

158 Глава 7

Для окна используйте разметку, созданную в предыдущем примере приложе­ния с помощью GridView для отображения текстовых данных, представлен­ную в листинге 7 .9 .

Класс адаптера для связывания графических данных необходимо наследовать от вaseAdapter. Это базовый класс общей реализации адаптеров данных, ко­торы й может использоваться в списках. В предыдущих примерах для привяз­ки текстовых данных мы использовали в качестве базового класса специали­зированный класс ArrayAdapter<T>.

В классе адаптера массив данных должен содержать идентификаторы графи­ческих ресурсов, которые будут располагаться в каталоге res/drawaЬie/. Для данного примера возьмите файлы photo l .jpg . . . photo8.j pg из каталога Resources/Images/ на прилагаемом к книге диске .

Для создания нового класса нажмите правой кнопкой мыши на папке с про­ектом и в контекстном меню выберите пункт New 1 Class. Появится окно New Java Class . В поле Name введите имя нового класса, ImageAdapter, и нажмите кнопку Finish (рис. 7 . 8) .

Java Class dfi The use of the default package is discouraged.

·· ® : ···

· · · ·- · · · · · · · ·: · · · · ·:·. ·:· · · . · · · · · · · · · · : · · · · : : · · · : . . . . . . . . . . : .. . . . . . . . . . . . . . . . . . . . . : . . :.: .......... ... . . . . . ........... ........... ........... "' L.�_�P.?�.���y-�w-��ag�!��c

Рис. 7.8. Окно создания нового класса

Page 166: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

Виджеты-списки и привязка данных 159

Полный код класса адаптера данных IrnageAdapter представлен в л истин­ге 7 . 1 2 .

package com . samples . gridviewimage ;

import android . content . Context ;

import android . view . View ;

import android . view . ViewGroup ;

import android . widget . BaseAdapte r ;

import android . widget . GridView;

import android . widget . IrnageView;

puЬlic class ImageAdapter extends BaseAdapter

private Context mContext ;

private static final Integer [ ] mimages

R . drawaЬle . photol , R . drawaЬle . photo2 ,

R . drawaЬle . photoЗ , R . drawaЬle . photo4 ,

R . drawaЬle . photo5 , R . drawaЬle . photo б ,

R . drawaЬle . photo7 , R . drawaЬle . photo8 ,

R . drawaЬle . photol , R . drawaЬle . photo2 ,

R . drawaЬle . photoЗ , R . drawaЬle . photo4 ,

R . drawaЬle . photo5 , R . drawaЬle . photoб,

R . drawaЬle . photo7 , R . drawaЬle . photo8 ,

R . drawaЬle . photol , R . drawaЬle . photo2 ,

R . drawaЬle . photoЗ , R . drawaЬle . photo4 ,

R . drawaЬle . photo 5 , R . drawaЬle . photoб ,

R . drawaЬle . photo7 , R . drawaЬle . photo8

puЬlic IrnageAdapter ( Context context )

mContext context ;

puЬlic int getCount ( )

return mimages . length ;

puЬlic Obj ect get item ( int position )

return mirnages [pos ition] ;

Page 167: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

1 60

puЬlic long get i temid ( int position )

return mimages [position] ;

создание нового ImageView для каждого элемента даннь�

puЬlic View getView (

int posit ion, View convertView, ViewGroup parent )

ImageView view ; i f ( convertView nul l )

view new ImageView (mContext ) ;

Глава 7

view . setLayoutParams ( new GridView . LayoutParams ( 8 5 , 8 5 ) ) ;

view . setSca leType ( ImageView . ScaleType . CENTER_CROP ) ;

view . setPadding ( 2 , 2 , 2 , 2 ) ;

else

view ( ImageView ) conve rtView ;

view . setimageResource (mimages [ position ] ) ;

return view ;

Рис. 7.9. Приложение с виджетом GridView, отобража ющим графику

Page 168: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

Виджеты-списки и привязка данных 161

Класс деятельности также останется практически без изменений (см. лис­тинг 7 . 1 1 ), за исключением кода привязки данных в методе onCreate ( ) :

�Adapter new IrnageAdapter ( getApplicationContext ( ) ) ;

;rid . setAdapter (mAdapter) ;

Сделав необходимые изменения, запустите проект на выполнение. При выбо­ре элемента списка в окне текстового поля вверху экрана будет отображен идентификатор выбранного элемента (рис. 7 .9) .

7 .4 . 2 . Gallery

Виджет Gal lery - это окно списка с графическим напол нением, имеющее горизонтальную прокрутку и подеветку выбранного изображения. На мо­бильном устройстве список перемещают с помощью левых и правых кнопок со стрелками на D-pad . Чаще всего элемент Gallery используется как средст­во просмотра коллекции фотографий или значков.

Это простой в использовании виджет, и работа с ним в коде программы в це­.1ом аналогична работе с обычными списками . В качестве примера приложе­ния с использованием элемента Gallery создайте новый проект и в диалоге Create New Project введите следующие значения :

О Project name - Gal leryApp;

О Application name - CheckedTextView Sample; 1

О Package name - сот . samples . gallery;

О Create Activity - GalleryActivity.

Откройте файл разметки и создайте структуру разметки подобно листин­гу 7 . 1 3 .

<?xml version= " l . O " encoding="utf-8 " ?>

<LinearLayout xmlns : android="http : / /schernas . android . com/apk/res /android"

android : orientation="vertica l "

android : layout_width= " fil l_parent "

android : layout_he ight= " fi l l_parent "

android : gravity=" center" >

<Gallery

android : id=" @ +id/gallery"

androi d : layout_width=" fi l l_parent "

android : layout_height="wrap_content " / >

Page 169: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

162

<TextView

android : id= " @+id/text "

android : layout_width= "wrap_content "

android : layout_height= "wrap_content "

android : textStyle="bold"

android : textSize= " 2 4px " />

</LinearLayout>

Глава 7

Код класса-адаптера данных ImageAdapter представлен в листинге 7 . 1 4 . Раз­личие ме�у классами адаптеров для GridView и Gallery только в методе getView ( ) , загружающем графические ресурсы в виджет.

package com . samples . gal lery ;

import android . content . Context ;

import android . view . View;

import android . view . ViewGroup ;

import android . widget . BaseAdapte r ; import android . widget . Gallery;

import android . widget . ImageView ;

puЬlic class ImageAdapter extends BaseAdapter

private int mGalleryitemВackground ;

private Context mContext ;

private final Integer [ ] mimage

R . drawaЬle . photol , R . drawaЬle . photo2 ,

R . drawaЬle . photoЗ , R . drawaЬle . photo4 ,

R . drawaЬle . photoS , R . drawaЬle . photoб ,

R . drawaЬle . photo7 , R . drawaЬle . photo8 ,

puЬlic ImageAdapter ( Context с )

mContext с ;

puЬlic View getView ( int pos ition, View convertView, ViewGroup parent ) {

ImageView view = new ImageView (mContext ) ;

Page 170: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

Виджеты-списки и привязка данных

view . setimageResource (mimage [position] ) ;

view . setPadding ( 2 0 , 2 0 , 2 0 , 2 0 ) ;

view . setLayoutParams ( new Gal lery . LayoutParams ( l 4 0 , 1 9 0 ) ) ;

view . setSca leType ( ImageView . ScaleType . FIT_XY ) ;

view . setBackgroundResource (mGa lleryitemВackground) ;

return view ;

puЬlic int getCount ( ) { return mimage . length;

puЬlic Obj ect get item ( int pos ition )

return mimage [ pos ition ] ;

puЬlic long get i temid ( int pos ition )

return mimage [ position ] ;

Полный код класса GalleryActivity представлен в листинге 7 . 1 5 .

package com . samples . gallery;

import android . app . Activity;

import android . os . Bundle ;

import android . view . View;

import android . widget . AdapterView;

import android . widget . Gallery;

import android . widget . TextView ;

import android . widget . AdapterView . OnitemCl ickListener ;

puЬlic class Galle ryActivity extends Activity

@Override

puЬlic void onCreate ( Bundle savedinstanceStat e )

supe r . onCreate ( savedinstanceState ) ;

setContentView ( R . layout . main ) ;

final Gallery g ( Ga llery) findViewByid ( R . id . gallery ) ;

g . setAdapter ( new ImageAdapter ( this ) ) ;

1 63

Page 171: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

164

final TextView labe l ( TextView ) findViewByid ( R . id . text ) ;

label . setText ( " S l ide 1 from + g . getAdapter ( ) . getCount ( ) ) ;

g . setOnitemClickListener ( new Oni temCl ickLis tener ( )

puЫ ic void onitemCl ick (Adapte rView< ? > parent ,

View v, int pos , long id)

label . setText (

Глава 7

" S l ide + ++pos from + pa rent . getCount ( ) ) ;

Скомпилируйте и запустите проект на вы полнение. При выборе картинки из галереи в окне текстового поля внизу картинки также будет отобра»<аться индекс выбранного элемента и полное количество изображений в коллекции , как по казан о на рис . 7 . 1 О .

Рис. 7. 1 0 . Приложение с виджетом Gal lery

7 . 4 . 3 . SlidingDrawer

Виджет SlidingDrawer - это выдвижная панель с маркером . Этот виджет ис­пользуется в панели Application Launcher, который отображает список про­грамм, установленных на устройстве (см . рис . 2 .9).

Page 172: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

Виджетьt-списки и привязка данных 1 65

В неактивном состоянии SlidingDrawer скрыт и на экране виден только мар­кер. При нажатии маркера пользователем выдвигается информационная па­нель . SlidingDrawer может использоваться вертикально или горизонтально. Специальный графический фрагмент состоит из двух дочерних представле­ний: маркера, который может перемещаться пользователем, и информацион­ного наполнения, прикрепленного к маркеру и перемещаемого вместе с мар­кером .

Размер SlidingDrawer определяет пространство, которое будет занимать его информационное наполнение при выдвинутой паиели S l idingDrawer. Обычно для определения высоты и ширины используется значение fill_parent .

В ХМL-разметке S l idingDrawer необходимо определить ссылку на маркер (это отдельный графический ресурс) и контейнер для информационного на­полнения.

Можно создать собственный S lidingDrawer и использовать его в своем при­ложении . Поскольку S l idingDrawer является контейнерным виджетом, ин­формационное наполнение может быть любое - текст, графика или контей­нер с дочерними виджетами. Если содержимое паиели не помещается на экране, автоматически добавляется вертикальная полоса прокрутки.

При создании ХМL-разметки для Sl idingDrawer необходимо определить ре­сурс для маркера и информационного наполнения:

android : handle=" @ +id/handle"

android : content= " @ +id/content "

В качестве примера приложения с использованием виджета Sl idingDrawer

создайте в среде Ecl ipse новый проект и в диалоге Create New Project введи­те следующие значения:

D Project name - S l idingDrawerApp;

D Application name - S l idingDrawer Sample;

D Package name - com . samples . s lidingdrawer;

D Create Activity - S l idingDrawerActivity.

В нашем примере для информационного наполнения будет использоваться

GridView с иконками, как в примере в разд. 7. 4. 1 . Иконки можно взять из ка­талога Resources/Images/ на прилагаемом к книге диске или использовать свои собственные значки . Все изображения, использованные в примерах, взя­ты из Android SDK.

Откройте файл разметки и создайте структуру разметки подобно листин­гу 7 . 1 6 .

Page 173: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

1 66

<?xml vers ion=" l . O " encoding= " utf- 8 " ?>

<LinearLayout

xrnlns : android= "http : / / schemas . android . com/apk/ res /android"

android : orientation="vertica l "

android : layout_width=" fi ll_parent "

android : layout_height=" fi l l_parent " >

<TextView

android : id=" @+id/label "

android : layout_width= " fi l l_parent "

androi d : layout_height="wrap_content " />

<SlidingDrawer

android : id=" @ + id/drawer"

android : layout_width= " f i l l_parent "

android : layout_height= " f i l l_parent "

android : handle= " @ +id/handle"

android : content=" @+ id/ content "

android : bottom0ffset=" 9px " >

<ImageView

android : id=" @ id/handle"

android : layout_width=" 3 2 0dip"

android : layout_height=" 5 0dip"

android : s rc= " @drawaЬle/handle " / >

<LinearLayout

android : id=" @ id/content "

android : orientation= " vertica l "

android : layout_width=" fill_parent "

android : layout_height= " f i l l_parent ">

<GridView

android : id= " @ + id/grid"

android : layout width= " f i ll_parent "

android : layout_height=" fi l l_parent "

android : numColumns="auto fit"

android : verticalSpacing=" l Odp "

android : horizontalSpacing= " l Odp"

android : columnWidth=" бOdp"

android : stretchМode="columnWidth"

android : gravity= " center" />

Глава 7

Page 174: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

Виджеты-списки и привязка данных

< /LinearLayout>

< / S l idingDrawer>

</LinearLayout>

167

Код класса S l idingDrawerActivity в целом похож на код класса для работы с элементом GridView и представлен в листинге 7 . 1 7 .

package com . samples . sl idingdraver ;

import android . app . Activity;

import android . os . Bundle ;

import android . view . View;

import android . widget . AdapterView ;

import android . widget . GridView ;

import android . widget . TextView ;

puЬlic class S l idingDrawerActivity extends Act ivi ty

implements AdapterView . OnitemSelectedListener {

private TextView mSelectText ;

private ImageAdapter mAdapte r ;

@ Override

puЫ ic void onCreate ( Bundle savedinstanceState )

super . onCreate ( savedinstanceState ) ;

setContentView ( R . layout . main ) ;

mSelectText= ( TextView ) findViewByid ( R . i d . label ) ;

GridView gridview ( GridView) findViewByid ( R . id . grid) ;

mAdapter new ImageAdapter ( this ) ;

gridview . setAdapter (mAdapter ) ;

gridview . setOnitemSelectedListener ( this ) ;

@ Override

puЬlic void oni temSelected (AdapterView<? > parent ,

View v, int position, long id)

mSelectText . setText ( " Selected items I D :

mAdapter . geti temid ( pos ition ) ) ;

Page 175: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

1 68

@ Override

puЬl ic void onNothingSelected (AdapterView< ?> parent )

mSelectText . setText ( " Selected items : none" ) ;

Глава 7

В классе-оболочке данных ImageAdapter заполните массив данных ссылками на идентификаторы иконок, которые вы будете использовать для наполнения виджета.

Полный код класса представлен в листинге 7 . 1 8 .

package com . samples . s l idingdraver ;

import android . content . Context ;

import android . view . View ;

import android . view . ViewGroup ;

import android . widget . BaseAdapter ;

import android . widget . GridView ;

import android . widget . ImageView ;

puЬlic class ImageAdapter extends BaseAdapter

private Context mContext ;

1 1 массив элементов для наполнения виджета

private Integer ( ] mimages

R . drawaЬle . ic_launcher_allhide ,

R . drawaЬle . ic_launcher_android,

R . drawaЬle . ic_launcher_browser,

R . drawaЬle . ic_launcher_calculator ,

R . drawaЬle . ic_launcher_calenda r ,

R . drawaЬle . ic_launcher_camera ,

R . drawaЬle . ic_launcher_contacts ,

R . drawaЬle . ic_launcher_emai l ,

R . drawaЬle . ic_launcher_emai l_generic,

R . drawaЬle . ic_launcher_gal lery,

R . drawaЬle . ic_launcher_google_talk ,

R . drawaЬle . ic_launcher_home ,

R . drawaЬle . ic_launcher_im,

R . drawaЬle . ic_launcher_maps ,

Page 176: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

Виджеты-списки и привязка данных

R . drawaЬle . ic_launcher_mus icplayer_2 ,

R . drawaЬle . ic_launcher_phone_dialer } ;

puЬl ic ImageAdapter ( Context с )

mContext с ;

puЬl ic View getView ( int position ,

View convertView, ViewGroup parent )

ImageView imageView ;

i f ( convertView == nul l )

1 69

imageView new ImageView (mContext ) ;

imageView . setLayoutParams ( new GridView . LayoutParams ( 8 5 , 8 5 ) ) ;

imageView . setScaleType ( ImageView . ScaleType . CENTER_CROP ) ;

imageView . setPadding ( 8 , 8 , 8 , 8 ) ;

else

imageView ( ImageView) convertView ;

imageView . setimageResource (mimages [ pos ition ] ) ;

return imageView;

puЬl ic int getCount ( )

return mimages . length ;

puЫ ic Obj ect geti tem ( int pos ition )

return nul l ;

puЬlic long getitemid ( int pos ition )

return О ;

Запустите проект на выполнение. Нажав маркер, можно развернуть виджет на

весь экран . При выделении иконки в Slidingorawer в окне текстового поля вверху экрана будет отображаться идентификатор выбранного элемента (рис. 7 . 1 1 ) .

Page 177: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

1 70 Глава 7

Рис. 7.1 1 . Приложение с виджетом SlidingDrawer

7 . 5 . Создан ие сп иска с собственной разметкой Кроме использования стандартных виджетов-списков можно создать список, определив собственную разметку только для одной строки этого списка. Та­кой подход используется для связывания данных, представленных в виде плоских таблиц. Для связывания табличных данных используются классы

S impleAdapter И S impleCursorAdapter.

S impleAdapter - адаптер для связывания статических данных с представле­нием, определенным в ХМL-файле. Конструктор класса выглядит так:

SimpleAdapter ( Context context , List<? extends Map< St ring , ?>> dat a ,

int resource , String [ ] from, int [ ] t o ) ..

Данные представляются как список объектов мар, которые, в свою очередь, содержат данные для каждой строки : м ножества элементов ключ-значение, где ключ - это имя поля, значение - содержимое поля . То есть каждый

элемент в ArrayLi st соответствует одной строке данных в списке.

Класс SimplecursorAdapter применяют для связывания представлений с база­ми данных. Этот класс будет рассматриваться в главе 15 .

Page 178: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

Виджеты-списки и привязка данных 1 71

В качестве примера разработаем приложение, отображающее статические данные в табличном виде. Создайте новый проект и в диалоге Create New Project введите следующие значения :

О Project name - ListContact;

О Application name - Contacts Sample;

О Package name - сот . samples . l is tcontact;

О Create Activity - ListContactActivity.

В приложении будем отображать список контактов, приведенный ранее, но в строке будет два столбца: поле Name с выравниванием влево и поле Phone

с выравниванием вправо.

Для этого в файле разметки определим строку с двумя элементами TextView,

как показано в листинге 7 . 1 9 .

<?xml version= " . 0 " encoding= " ut f-8 " ?>

<Relat iveLayout xmlns : android= "http : / / s chemas . android . com/apk/ res /android" android : orientation="horizontal " android : layout_width=" fi ll_parent " android : layout_height=" fi l l_parent " >

<TextView android : id= " @ +id/name " android : layout_width="wrap_content " android : layout_height= "wrap_content " android : layout_alignParentLeft= " t rue" android : textS i ze= " l 8 sp" / >

<TextView android : id=" @ +id/phone " android : layout_width="wrap_content "

android : layout_height="wrap_content "

android : layout_alignParentRight= " t rue "

android : textSize= " 1 8 sp" android : paddingRight=" l Opx " / >

</RelativeLayout>

Для хранения строки, представляющей контакт, создадим отдельный класс contactrtem, расширяющий класс наshМар, в котором определим константы NАМЕ и PHONE с именами полей и конструктор с параметрами - имя контакта и телефон . Код класса представлен в листинге 7 .20 .

Page 179: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

1 72

package com . samples . l i stcontact ;

import j ava . ut i l . HashМap ;

puЬlic class Contact i tem extends HashМap<String , S tring>

private static final long serialVers ionUID l L ;

puЬl ic static final String NАМЕ "name " ;

puЬlic static final String PHONE "phone " ;

puЬlic Contactitem ( String name , String phone )

super ( ) ;

supe r . put ( NAМE , name ) ;

super . put ( PHONE , phone ) ;

Глава 7

В классе деятельности ListContactActivity заполним данными объект ArrayList

и отобразим его в виде таблицы в окне деятельности (листинг 7.2 1 ) .

package com . samples . l istcontact ;

import j ava . ut i l . ArrayList ;

import android . app . ListActivity;

import android . os . Bundle ;

import android . widget . ListAdapter ;

import android . widget . S impleAdapte r ;

puЬl i c class ListContactActivity extends ListActivity

@ Override puЫ ic void onCreate ( Bundle savedinstanceStat e )

super . onCreate ( savedinstanceState ) ;

ArrayList<Contactitem> l i s t new ArrayList<Contactitem> ( ) ;

/ 1 заполняем список контактов

l i s t . add ( new Contactitem ( " Jacob Anderson" , " 4 12 4 1 2 4 1 1 " ) ) ;

list . add ( new Contactitem ( "Emily Duncan" , " 1 61 8 63 1 87 " ) ) ;

l i s t . add ( new Contactitem ( "Michae l Ful ler" , " 8 9 64 4 3 65 8 " ) ) ;

l i s t . add ( new Contactitem ( "Emma Greenman" , " 9 6 4 9 9 0 5 4 3 " ) ) ;

l i s t . add ( new Contactitem ( " Joshua Harrison" , " 7 5 9 2 8 5 0 8 6 " ) ) ; l i s t . add ( new Contactitem ( "Madi son Johnson" , " 95 0 2 8 5 7 7 7 " ) ) ;

Page 180: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

Виджеты-списки и привязка данных

1 i s t . add ( new Contact i t em ( "Matthew Cotman" , " 68 7 6 9 9 9 9 9 " ) ) ; 1 i s t . add ( new Contacti tem ( "01 ivia Lawson " , " 1 61 8 6 3 1 8 7 " ) ) ;

1 i s t . add ( new Contact i t em ( "Andrew Chapman " , " 5 4 6 5 9 9 6 4 5 " ) ) ;

1 i s t . add ( new Conta c t i t em ( " Danie 1 Honeyman " , " 8 7 65 4 5 6 4 4 " ) ) ;

1 i s t . add ( new Contact i t em ( " I s abe 1 1 a Jackson " , " 9 0 7 8 6 8 7 5 6 " ) ) ; 1 i s t . add ( new Contacti tem ( "W i l l i am Patterson " , " 6 8 7 6 9 9 6 9 3 " ) ) ; 1 i s t . add ( new Contact l t em ( " Joseph Godwin" , " 9 654 6 7 57 5 " ) ) ; 1 i s t . add ( new Contactl tem ( " Samantha Bush" , " 9 0 7 8 65 6 4 5 " ) ) ; 1 i s t . add ( new Contact l t em ( " Chri s t opher Gateman" , " 8 9 68 7 4 55 6 " ) ) ;

создаем адаптер даннь�

Lis tAdapter adapte r new S imp1eAdapte r (

thi s , 1 i s t , R . 1ayout . main,

new St ring [ ] { Contact l t em . NAМE , Contact l tem . PHONE } ,

new int [ ] { R . id . name , R . id . phone } ) ;

setLis tAdapte r ( adapte r ) ;

1 73

Внешний вид приложения со сп иском контактов представлен на рис. 7 . 1 2 .

Это базовое приложение м ы будем развивать в следующих главах книги при рассмотрении передачи данных между деятел ьностями (глава 1 1) и работы с базами данных (глава 15) .

Рис. 7. 1 2 . Список с собственной разметкой

Page 181: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

Г Л А В А 8

Уведомлен ия

При работе пользователя с приложеннем могут возникать различные ситуа­ции, о которых необходимо уведомить пользователя . Некоторые ситуации требуют, чтобы пользователь обязательно среагировал на н их, другие не тре­буют реакции и выполняют чисто информационную функцию.

Для информирования пользователя о наступившем событии существует не­сколько типов уведомлений :

� Toast Not i fication - для кратких всплывающих сообщений, не требую­щих реакции пользователя ;

:::J Status B a r Not i f i cation - для постоянных напоминаний, отображаю­щихся в виде значка в строке состояния и требуЮщих реакции пользова­теля .

8 . 1 . Вспл ы вающие уведомления Всплывающее уведомление является сообщением, которое появляется на по­верхности окна приложения . Всплывающее уведомление заполняет необхо­.::щмое ему количество пространства, требуемого для сообщения, и текущая деятельность приложения остается видимой и интерактивной для пользова­теля . Само уведомление в течение нескольких секунд плавно закрывается и не принимает события взаимодействия. Всплывающее уведомление также \ЮЖет быть создано службой, работающей в фоновом режиме.

Всплывающее уведомление обычно применяется для коротких текстовых со­общений . Если требуется реакция пользователя на уведомление, то исполь­зуются уведомления в строке состояния, о которых будет рассказано в этой главе.

Для создания всплывающего уведомления сначала необходимо инициал изи­ровать объект Toa s t одним из методов тoa s t . ma keText ( ) , затем вызовом мето-

Page 182: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

1 76 Глава 8

да show ( ) отобразить сообщение на экране, как по казан о в следующем при­мере:

Context context getAppl i cationContext ( ) ;

Toast toas t Toas t . rnakeText ( context ,

"This i s Toast Not i fication " , Toas t . LENGTH SHORT ) ;

toas t . show ( ) ;

Метод makeText ( ) принимает три параметра:

D контекст приложения;

D текстовое сообщение;

D продолжительность времени показа уведомления, которое определяется двумя константами :

• LENGTH SHORT - показывает текстовое уведомление н а короткий про­межуток времени и является значением по умолчанию;

• LENGTH _ LONG - показывает текстовое уведомление в течение длительно­го периода времени .

Продолжительность времени показа уведомлен ия можно также зада­вать, выставляя конкретное значение в м иллисекундах.

По умолчанию стандартное всплывающее уведомление появляется в нижней части экрана. Изменить место появления уведомления можно с помощью метода setGravity ( int , int , int ) . Этот метод принимает три параметра:

D стандартная константа для размещения объекта в пределах потенциаль­но большего контейнера, определенная в классе Gravity (например, GRAVITY . CENTER, GRAVITY . ТОР И др.);

D смещение по оси Х;

D смещение по оси У. Например, если уведомление должно появляться в центральной части экрана, необходимо добавить следующий код:

toast . setGravi t y ( Gravity . CENTER, О , 0 ) ;

Если требуется сместить уведомление направо, необходимо увеличить значе­ние второго параметра. Чтобы сместить уведомление вниз - увеличить зна­чение последнего параметра.

Для примера приложения со всплывающим уведомлением создайте новый проект и в диалоге Create New Project введите следующие значения :

D Project name - Toas tNoti ficationApp;

D Application name - ToastNot i fi cation Sample;

Page 183: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

Уведомления

Ll Package name - сот . sarnples . toastnotification;

Ll Create Activity - ToastNoti ficat ionActivity.

1 77

Откройте файл разметки и создайте структуру с элементом Button для вызова уведомления подобно листингу 8 . 1 .

<?xml ve rsion= " l . O " encoding= "ut f- 8 " ?> <LinearLayout xmlns : android="http : / /schemas . android . com/apk/ res/android"

android : orientation="verti ca l "

android : layout_width= " fil l_parent " android : layout_height= " fi l l_parent "

<Button android : id= " @ + id/button" android : layout_width= " fi l l_parent " android : layout_height="wrap_content "

android : text= " Call а Toast Noti fication"/>

</LinearLayout>

В классе тoastAct ivity, реализующем деятельность, напишите код, как в лис­тинге 8 .2 .

package com . sarnples . toastdialog ;

import android . app . Act ivity;

import android . content . Context ;

import android . os . Bundle ; import android . view . Gravity;

import android . view . View; import android . widget . Button ;

import android . widget . Toast ;

puЬlic class ToastActivity extends Activit'y implements View . OnClickListene r {

private Button mВutton ;

@Override

puЬl i c void onCreate ( Bundle savedinstanceState )

supe r . onCreate ( savedinstanceState ) ;

Page 184: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

1 78

s etContentView ( R . layout . main ) ;

mВutton ( Button ) f indVi ewByid ( R . id . button ) ;

mВut ton . setOnCl ickLi s t ene r ( thi s ) ;

puЫ i c void onCl i c k ( View view)

получаем конте кст приложения

Context context getApplicationContext ( ) ;

создаем и отображаем текстовое уведомление

Toa s t toas t Toa s t . ma keText ( context ,

"Th i s i s Toa s t Not i f i cation " , Toa s t . LENGTH_SHORT ) ;

toas t . s etGravi ty ( Gravity . CENTER , О , 0 ) ;

toas t . s how ( ) ;

Глава В

Запустите проект на выполнение. При нажатии кнопки вызова должно по­явиться на несколько секунд окно уведомления с текстовым сообщением (рис. 8 . 1 ) .

Рис. 8 . 1 . Пример вызова всплывающего уведомления

Page 185: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

Уведомления

8.2 . Создан ие собственных вспл ы вающих уведомлений

1 79

Если простого текстового сообщения недостаточно для уведомления пользо­вателя приложения, можно создать собственный дизайн разметки своего уве­домления .

Для получения разметки из ХМL-файла и работы с ней в программе исполь­

зуется класс Layoutinflater и его методы getLayout inflater ( ) или getsystemService ( ) , которые возвращают объект Layout inflater. Затем вьiЗО­вом метода inflate ( ) получают корневой объект View этой разметки. Напри­

мер, для файла разметки уведомления с именем cus tom _layout . xml и его кор­

невого представления с идентификатором android : id= " @ +id/toast layout "

код будет таким :

Layoutinflater inflater getLayout inflater ( ) ;

View layout inflater . inflate ( R . layout . cus tom_layout ,

(ViewGroup ) findViewByid ( R . id . toast_layout ) ) ;

Параметры, передаваемые в метод inflate ( ) :

О идентификатор ресурса схемы размещения (в примере - custom

layout . xml) ;

О идентификатор ресурса корневого представления (в примере -toast _layout ) .

После получения корневого представления из него можно получить все до­

черние представления уже известным методом findViewByid ( ) и определить информационное наполнение для этих элементов.

Затем создается объект тoast и устанавливаются нужные свойства, такие, на­

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

Toast toast new Toast ( getApplicationContext ( ) ) ;

toast . setGravity ( Gravity . CENTER_VERT ICAL , О , 0 ) ;

toast . setDurat ion ( Toas t . LENGTH_LONG ) ;

После этого вызывается метод setView ( ) , которому передается разметка уве­домления, и метод show ( ) , чтобы отобразить уведомление с собственной раз­меткой :

toast . setView ( layout ) ;

toast . show ( ) ;

Для примера приложения с вызовом собственного уведомления создайте но­вый проект и в диалоге Create New Project введите следующие значения :

Page 186: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

180

О Project name - CustomToast;

О Application name - CustomToast Sample;

О Package name - сот . samples . customtoast;

О Create Activity - CustomToastActivity.

Глава В

Файл разметки экрана используйте из предыдущего примера (см . листинг 8 . 1 ) . Для создания новой разметки уведомления щелкните пра­вой кнопкой мыши на папке с проектом и в контекстном меню выберите Android Tools 1 New Resource File . Появится окно New Android XML File. В поле File введите имя нового файла разметки - custom _layout . xml, в груп­пе радиокнопок What type of resource would you like to create? установите значение Layout, поля Folder и Select the root element for the XML fille оставьте без изменений (рис. 8 .2) .

Project L9!��mT���t���iF·i��t;��=--Aie г���torn)�Y�ct·:;rnl .

What type of resourcё would you bke to cr

0i;;�!i@ Ovalues

О reference О SearchaЫe

Whвt type of resou�ce coofiguration � you lil<e?. дvaiahki Quaiflers i.i<;

Foider

l 'f�c���t;�·c;�,;� . " � . . . . . . . :"') ' . i ;, �=������ode Ш

l i:: �1R j d Orientation .,. ",". ! �Pixel Density =� :::�:;

1 ;�::��!��t \' i j!i ! 4$• Navigati 1 l:J.oimensi :�Н �--�-· ....... . . . . . . . .. .. . . . . .

Select the root olement for the ХМL

QМenu QAnlmatlon

(! AppWidget Provlder

Fin1sh ·1 !' Cancel

Рис. 8.2. Окно создания нового ХМL-файла

Page 187: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

Уведомления 181

Нажмите кнопку Finish . В созданном файле разметки корневому элементу

LinearLayout присвойте идентификатор toast _layout. Определите два дочер­них элемента, IrnageView и TextView, как показано в листинге 8 .3 .

<LinearLayout xmlns : android="http : / / schernas . android . com/ apk/ re s / android"

android : id= " @+id/toast_layout "

android : orientation="hori zontal "

android : layout_width=" fil l_parent "

android : layout_height= " fi l l_parent "

android : padding= " l Odp"

android : background=" # DAAA" >

< IrnageView android : id= " @+id/ irnage "

androi d : layout_width= "wrap_content "

android : layout_height=" f i ll_parent "

android : l ayout_marginRight= " l Odp " / >

<TextView android : id= " @ +id/text "

android : layout_width= "wrap_content "

android : layout_height= " fi l l_parent "

android : textColor= " # FFF" / >

</LinearLayout>

Полный код класса customтoastActivity для вызова и работы с уведомлением представлен в листинге 8 .4 .

package com . samples . customtoast ;

import android . app . Activity;

import android . os . Bundle ;

import android . view . Gravity;

import android . view . Layout inflate r ;

import android . view . View ;

import android . view . ViewGroup ;

import android . widget . Button ;

import android . widget . IrnageView;

import android . widget . TextView ;

import android . widget . Toast ;

Page 188: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

182

puЫ ic class CustomToastActivity extends Activity

implements View . OnClickLi stener

Button mВutton ;

@Override

puЫ ic void onCreate ( Bundle savedinstanceState )

supe r . onCreate ( savedinstanceState ) ;

setContentView ( R . layout . main ) ;

mВutton= ( Button ) findViewByid ( R . id . button) ;

mВutton . setOnClickListener ( thi s ) ;

puЫ ic void onClick (View view )

Layout inflater inflater getLayout inflater ( ) ;

View layout inflater . inflate ( R . layout . custom_layout ,

(ViewGroup ) findViewByid ( R . i d . toast layout ) ) ;

Глава 8

ImageView image ( ImageView) layout . findViewByid ( R . i d . image ) ;

image . setimageResource ( R . drawaЫe . androidЗd ) ;

TextView text ( TextView) layout . findViewByid ( R . i d . text ) ;

text . setText ( "Hello ! This i s а custom toast ! " ) ;

Toast toast new Toast ( getApplicat ionContext ( ) ) ;

toas t . setGravity ( Gravity . CENTER_VERTI CAL, О , 0 ) ;

toas t . setDuration ( Toast . LENGTH_LONG ) ;

toas t . setView ( layout ) ;

toas t . show ( ) ;

Запустите проект на выполнение . При нажатии кнопки вызова должно по­явиться на несколько секунд окно уведомления с текстовым сообщением и значком (рис. 8 .3 ) .

8 .3 . Уведомлен ия в строке состоя н ия Уведомление в строке состояния добавляет значок к системной строке сь­стояния (с дополнительным расширенным текстовы м сообщением, которое можно увидеть, открыв окно Notifications). Когда пользователь открывает расширенное сообщение, Aпdroid запускает объект Intent, который опреде­лен в соответствии с уведомлением . Можно также конфигурировать уведом-

Page 189: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

Уведомления 1 83

Рис. 8 .3 . Пример создания собственного всплывающего уведомления

.1ение с добавлением звука, вибрации и мигающих индикаторов на мобиль­ном устройстве.

Этот вид уведомления идеален, когда приложение работает в фоновом режи­\1е и должно уведомить пользователя о каком-либо событии . Фоновое при­.1ожение создает уведомление в строке состояния, и никогда не должно за­пускать деятельность самостоятельно для получен ия пользовательского взаимодействия, это должен делать только сам пользователь, т. к. в это время в фокусе может находиться другая деятельность, с которой пользовател ь в данный момент работает.

ПРИМЕЧАНИЕ В п ри веде н н ых далее п римерах уведомлен ия строки состоя н ия будут в ызы­ваться не из служб , а вручную с помощью кноп ки , чтобы показать сам процесс созда н ия уведомлен и й . Созда н ие служб и работа с н и м и будут рассмотрен ы в главе 1 2 .

Чтобы создать уведомление в строке состояния, необходимо использовать два класса:

О Not i f i cat ion - используется для определения свойств уведомления стро­ки состояния, такие как значок в строке состояния, расширенное сообще­ние и дополнительные параметры настройки (звук и др.) ;

О Not i f i cat ionМanager - это системный сервис Aпdroid, который управляет всеми уведомлениями . Экзем пляр Not i f i cationМanager в коде создается

Page 190: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

184 Глава 8

вызовом метода get Sys temService ( ) , а затем, когда надо по казать уведом­ление пользователю, вызывается метод noti fy ( ) .

При создании уведомления сначала надо получить ссылку на Not ificationМanager через вызов метода getSystemService ( ) , передав ему в качестве параметра строковую константу NOTIFICAТ ION _ SERVICE, определен­ную в классе Context :

Not i ficationМanage r notifyMgr (Noti ficationМanager ) getSystemService ( Context . NOT I FI CAT ION_SERVICE ) ;

Затем создать значок, текст уведомления и объект Not i ficat ion:

int icon R . drawaЬle . not ification icon ;

CharSequence tickerText "Warning ! " ; long when System. currentTimeMi l l i s ( ) ; Noti ficat ion notification new Notification ( icon , ticke rTex t , when ) ;

После чего определ ить расширенное сообщение для уведомления :

CharSequence contentTitle "Му noti fication" ; CharSequence contentText "Hello World ! " ;

и создать объект rntent :

Context context getApplicationContext ( ) ; Intent intent new Intent ( this , MyClass . class ) ;

Затем создать объект Pendingintent, которы й описы вает намерения и целевые действия и который запустится, когда пользователь среагирует на уведомле­ние:

Pendingintent contentintent Pendingintent . getActivity ( this , О , intent , 0 ) ;

Объект Pendingintent создается методом getAct i vi ty ( ) , который принимает четыре параметра:

О контекст приложения, в котором объект Pending rntent должен запустить деятельность;

О код запроса для отправителя (не используется, передается значение О) ;

О созданный ранее объект rntent;

О константа для управления намерением .

ПРИМЕЧАННЕ Подробно намерения и работа с ними будут рассмотрены в главе 1 4.

Затем для объекта Not ificat ion с помощью метода setLatestEvent info ( ) соз­дать представление, которое будет показано в расширенной строке состоя­ния :

Page 191: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

Уведомления 185

not ification . setLatestEvent info (

context , contentTitle , contentText , contentintent ) ;

Наконец, надо передать объект Not i fi cation в объект Noti ficationМanager

в качестве параметра для метода notify ( ) :

mNoti ficationМanage r . noti fy (NOT I FY_I D, not ification ) ;

где NOT I FY _ ш - идентификатор уведомления, определяемый в вашем классе для работы с уведомлением.

В качестве примера приложения с вызовом уведомления в строке состояния создайте новый проект и в диалоге Create New Project введите следующие значения :

О Project name - StatusBarNoti ficationApp;

О Application name - StatusBarNoti fi cation Sarnple;

О Package name - com . sarnples . statusbarnotification;

О Create Activity - StatusBarNotificationActivity.

Файл разметки создайте подобно листингу 8 . 1 (как в nримере для вы­зова стандартного всплывающего уведомления) . В классе StatusBarNotificationActivity реализуйте вызов уведомления, используя по­следовательность создания уведомления, приведеиную ранее. Полный код класса StatusBarNotificationActivity дан в листинге 8 . 5 .

package com . sarnples . statusbarnotification;

import android . app . Activity;

import android . app . Not ification;

import android . app . NotificationМanager ;

import android . app . Pendingintent ;

import android . content . Context ;

import android . content . Intent ;

import android . os . Bundle ; import android . view . View; import android . widget . Button;

puЬlic class StatusBarNoti ficationActivity extends Act ivity

implements View . OnClickListener

private Button mВutton ;

private static final int NOT I FY ID 1 0 1 ;

private Noti ficationМanage r mNoti fyMg r ;

Page 192: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

186

@ Override

puЬl ic void onCreate ( Bundle savedinstanceState )

supe r . onCreate ( savedinstanceState ) ;

setContentView ( R . layout . rnain ) ;

mNot ifyMgr ( Noti ficationМanager ) getSysternService (

Context . NOTIFICATION_SERVICE ) ;

rnВutton= ( Button ) findViewByid ( R . id . button ) ;

rnВutton . setOnClickListefie r ( this ) ;

puЬl ic void onClick (View view )

int icon R . drawaЬle . android_happy ;

CharSequence tickerText "Hello ! " ;

long when S ystern . currentTirneMi l l i s ( ) ;

Context context getAppl icationContext ( ) ;

CharSequence contentTitle

CharSequence contentText

Intent not i fication!ntent

"Notification" ;

"Hi , I arn Android ! " ;

new Intent (

thi s , StatusBarNoti ficationActivity . class ) ;

Pendingintent content !ntent Pendingintent . getActivity (

thi s , О , notificationintent , 0 ) ;

Not ification noti ficat ion new Noti fication (

icon , tickerText, when ) ;

noti fication . setLatestEvent info ( context , contentTitle,

contentText , content !ntent ) ;

mNoti fyMgr . notify ( NOTI FY_I D , notification ) ;

Глава В

Запустите проект на выпол нение. При нажатии кнопки вызова уведомления в строке состоян ия должен отобразиться значок и текст уведомления . При нажатии значка откроется расширенное уведомление (рис. 8 .4) .

Закрыть уведомление можно из окна Notifications кнопкой Clear. Поскольку уведомление вызывалось не службой, а простым нажатием кнопки, в верхней части развернутого уведомления присутствует надпись "No service" При вы­зове уведомления службой в этом месте появится название службы .

Page 193: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

Уведомления

2010 1 3 l'fD(§ 01 :38

Рис. 8.4. Пример вызова уведомления в строке состояния

8 .4. Создание собственных уведомлен и й для строки состоя ния

1 8 7

Если простого текстового сообщения недостаточно для уведомления пользо­вателя приложения или вам хочется создать оригинальный дизай н для режи­'vШ развернутого уведомления, можно создать собственный дизайн разметки развернутого уведомления .

По умолчанию расш ирен ное представление, используемое в окне Notifications, включает основной заголовок и текстовое сообщение . Они

определяются в методе setLates tEvent info ( ) двумя параметрам и : contentT i t l e - заголовок уведомления и contentтext - текст уведомления .

Однако вы можете также определ ить вашу собственную схему разметки для расширенного сообщения, создав экземпляр класса RemoteViews и передав его в contentVi ew уведомления :

RemoteViews contentView new RemoteViews (

getPackageName ( ) , R . l a yout . custom_l a yout ) ;

contentView . se t imageVi ewRe source ( R . id . image , R . drawaЫe . androidЗd ) ;

contentVi ew . setTextViewТext ( R . id . text , text ) ;

Page 194: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

1 88 Глава 8

Notification noti fication new Noti fication ( icon , tickerText , when ) ; not i fication . content !ntent content!ntent ; notification . contentView contentView;

mNoti fyMgr . not ify ( NOT I FY_I D , not i fication ) ;

Для примера приложения с вызовом уведомления с собственным дизайном для развернутого вида создайте новый проект и в диалоге Create New Project введите следующие значения :

О Project name - CustornStatusBarNoti ficationApp;

О Application name - CustornStatusBarNoti fication Sarnple;

О Package name - corn . sarnples . custornstatusbarnotificat ion;

О Create Activity - CustomStatusBarNotificationActivity.

Файл разметки maiп .xml для деятельности возьмите из листинга 8 . 1 . Разметку для custom_layout.xml используйте такую же, как в листинге 8 .3 для всплы­вающего уведомления .

В КЛассе CustornStatusBarNoti ficat,ionActivity реализуйте ВЫЗОВ уведомле­НИЯ, используя последовательность создания уведомления, приведенную ранее . Полный код класса custornStatusBarNotificationActivity приведен в листинге 8 .6 .

package corn . sarnples . custornstatusbarnotification;

irnport android . app . Activity; irnport android . app . Noti fication ; irnport android . app . Noti ficationМanager ; irnport android . app . Pending!ntent ; irnport android . content . Context ; irnport android . content . Intent ; irnport android . os . Bundle ; irnport android . view . View; irnport android . widget . Button ; irnport android . widget . RernoteViews ;

puЬl i c class CustornStatusBarNotificationActivity extends Act ivity irnplernents View . OnClickListener

private static final int NOT I FY I D Oxl O O l ;

private Button mВutton ; private Noti ficationМanager mNoti fyMgr;

Page 195: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

Уведомления

@ Override

puЬl i c void onCreate ( Bundle savedinstanceState )

supe r . onCreate ( savedinstanceStat e ) ;

setContentView ( R . layout . main ) ;

mNot i fyMgr = ( Not i ficationМanager ) getSystemService ( Context . NOTIFICATION_SERVICE ) ;

mВutton= (Button ) findViewByid ( R . id . button ) ;

mВutton . setOnClickListener ( this ) ;

puЬlic void onClick ( View view )

int icon R . drawaЫe . android_happy ; CharSequence t ickerText "Hello ! " ;

long when System . currentTimeMi l l i s ( ) ; Cha rSequence text

"Hi , I am Android ! This is custom Not i fication . " ;

Intent noti ficationintent new Intent (

thi s , CustomNotificationActivity . class ) ;

Pendingintent contentintent Pendingintent . getActivity (

thi s , О , noti fication!ntent , 0 ) ;

RemoteViews contentView = new RemoteViews (

getPackageName ( ) , R . layout . custom_layout ) ;

contentView . setimageViewResource ( R . id . image , R . drawaЫe . androidЗd) ;

contentView . setTextViewТext ( R . id . text , text ) ;

Noti fication noti fication new Noti fication (

icon , tickerText , when ) ;

noti fi cation . content!ntent content !ntent ;

noti fication . contentView contentView;

mNot ifyMgr . notify (NOТ I FY_I D , not i fication ) ;

189

Запустите проект на выполнение. При нажатии кнопки вызова уведомления в строке состояния должен отобразиться значок и текст уведомления. Если те­перь нажать значок уведомления в строке состояния, откроется расширенное уведомление с созданной нами разметкой (рис. 8 . 5 ) .

Page 196: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

190

Рис. 8.5. Пример создания собственного уведомления для строки состояния

Глава 8

Page 197: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

Г Л А В А 9

Диалоговые окна

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

Android поддерживает следующие типы диалоговых окон :

О AlertDialog - диалог с кнопками, списком, флажками или радиокноп-кам и;

О ProgressDialog - диалог с индикатором прогресса;

О DatePickerDialog - диалог выбора даты;

О TirnePickerDialog - диалог выбора времени .

Иерархия классов диалоговых окон представлена на рис. 9 . 1 .

Класс Dialog является базовым для всех классов диалоговых окон . Поскольку Progres sDialog, TirnePickerDialog и DatePickerDialog - расширение класса AlertDialog, они таюке могут иметь командные кнопки .

1 Object 1 Dialog 1

AlertDialog 1 г------, 1-----1 DatePickerDialog 1

1-----1 TimePickerDialog 1 ProgressDialog 1

Рис. 9.1 . Иерархия классов диалоговых окон

Page 198: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

192 Глава 9

9 . 1 . Создан ие диалоговых окон Диалоговое окно всегда создается и отображается как часть находящейся в фокусе деятельности . Диалоги обычно создают внутри метода обратного вы­зова oncreateDialog ( ) , который необходимо реализовать в вашей деятельно­сти . При этом система Andro id автоматически управляет состоянием диалога (или нескольких диалогов) и прикрепляет их к текущей деятельности, факти­чески делая ее владельцем каждого диалога.

ОБРА ТИТЕ ВНИМАНИЕ

Можно создавать диалог без onCreateDialog ( ) , например в обработч ике на­жатия кнопки вызова диалога , но тогда он не будет присоединен к текущей дея­тел ьности . Чтобы прикрепить его к деятел ьности , необходимо вызвать метод setOWnerAct i vi t у ( ) , передав ему в качестве параметра текущую деятельность.

Для отображения диалогового окна необходимо вызвать метод showDialog ( ) и передать ему в качестве параметра идентификатор диалога (константа, ко­торую надо объявить в коде программы), который вы хотите отобразить . На­пример:

private static final int IDD EXIT О ;

showDialog ( I DD_EXIT ) ;

Когда диалог вызывается впервые, система Android вызывает onCreateDialog ( ) из текущей деятельности . В onCreateDialog ( ) передается тот же самый идентификатор, который передавался в showDialog ( ) . После того как вы создали диалог, вы возвращаете объект в конце метода.

Если в деятельности должны вызываться несколько различных диалоговых окон, сначала необходимо определить целочисленный идентификатор для каждого диалога, например:

private s tatic final int IDD ALERT О ; private static final int IDD_EXIT

Эти идентификаторы потом можно использовать в вызове метода showDialog ( ) и в обработчике события onCreateDialog ( ) в операторе swi tch:

protected Dialog onCreateDialog ( int id) Dialog dialog; swi tch ( id) { case IDD ALERT :

break ; case I D D EXIT :

break ;

Page 199: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

Диалоговые окна 1 93

de faul t : dialog null ;

return dialog ;

В нутри оператора swi tch описывается сама процедура создания диалоговых окон, которая различна для каждого типа диалоговых окон и будет описана в следующих разделах этой главы .

Перед отображением диалогового окна Aпdroid вызывает дополнительный метод обратного вызова onPrepareDialog ( int , Dialog ) . Если требуется перед каждым вызовом диалогового окна изменять его свойства (например, тексто­вое сообщение или количество кнопок), это можно реализовать внутри этого метода. В этот метод передают идентификатор диалога и сам объект Dialog,

который был создан в методе обратного вызова onCreateDialog ( ) .

9 .2 . AlertDialog Диалог AlertDialog - расширение класса Dialog. Он используется при по­строении большинства диалоговых окон . В этих диалогах доступна для использования любая функциональность из нижеперечисленных:

О заголовок;

О текстовое сообщение;

О одна, две ил и три кнопки;

О список;

О флажки;

О радиокнопки.

9 .2 . 1 . AlertDia/og с кнопками

Для создания AlertDialog с кнопкам и используется группа методов set . . . Button ( ) класса AlertDialog . Bui lder:

О setPosit iveButton ( ) ;

О setNegat i veButton ( ) ;

О setNeutralButton ( ) .

Для создания диалогового окна сначала надо создать объект · класса вui lder,

nередав в качестве параметра контекст nриложения :

AlertDialog . Bui lder builder

new AlertDialog . Builder ( getAppl icationContext ( ) ) ;

Page 200: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

1 94 Глава 9

Затем, j1Спользуя методы класса Bui lde r, задать для создаваемого диалога необходи м ые свойства, например текстовое сообщение в окне методом setMessage ( ) :

bui lder . setMessage ( "Are you sure you want to exit ? " ) ;

После задания свойств диалога определяют командные кнопки диалога и об­работку событий на них. В AlertDialog можно добавить только по одной кнопке каждого типа: Pos itive, Negative и Neutral, т. с . максимал ьно возмож­ное количество кнопок в диалоге - три .

Для каждой кнопки используется один из методов set . . вutton ( ) , которые принимают в качестве параметров надпись для кнопки и интерфейс Dialoginterface . oncl ickListener, который определяет действие, когда поль­зователь нажимает кнопку. Например, для создания диалога с кнопками Yes и No код будет выглядеть приблизительно так:

bui lder . setPosi t iveButton ( "Yes " , new Dialoginterface . OnCl ickLi s tener ( )

puЬlic void onCl ick ( Dia loginterface dialog , int id)

} ) ;

1 1 закрьrnаем текущую деятельность

AlertDialogButtonActivity . this . finish ( ) ;

bui lde r . setNegativeButton ( "No " , new Dialoginterface . OnCl i ckListene r ( )

puЬlic void onCl ick ( Dialoginterface dialog , int id)

1 1 закрьmаем диалог и возвращаемся к текущей деятельности

dialog . cancel ( ) ;

Чтобы пользователь не мог закрыть диалог клавишей <Back> на клавиатуре мобильного устройства, вызывается метод setCancelaЬle ( ) :

builder . setCancelaЬle ( false ) ;

И наконец, отображаем диалог:

AlertDialog alert builder . create ( ) ;

Создайте новый проект и в диалоге Create New Project введите следующие значения :

О Project name - AlertDialogButtonApp;

О Application name - AlertDialogButton Sample;

О Package name - corn . samples . alertdialogbutton;

О Create Activity - AlertDialogButtonActi vi ty.

Page 201: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

Диалоговые окна 1 95

Откройте файл разметки и создайте структуру разметки с единственной кнопкой для вызова диалога подобно листингу 9 . 1 .

<?xml version= " l . O " encoding="utf- 8 " ?>

<LinearLayout xmlns : android="http : / /schemas . android . com/apk / res /android"

android : orientation="vertica l "

android : layout_width= " fi l l_parent " android : layout_height= " fi l l_parent "

<Button

android : id= " @ + id/button"

android : text=" Call Ale rtDialog with Buttons "

android : layout_width= " fi l l_parent "

android : layout_height="wrap_content " />

</LinearLayout>

В классе Ale rtDialogButtonActivity реализуйте последовательность создания диалога, приведеиную ранее. Полный код класса представлен в листинге 9.2 .

package com . samples . alertdialogbutton ;

import android . app . Activity;

import android . app . AlertDialog ;

import android . app . Dialog ;

import android . content . Dialoglnte rface ;

import android . os . Bundle ;

import android . view . View;

import android . view . View . OnCl ickListene r ;

import android . widget . Button ;

puЬlic class AlertDialogButtonActivity extends Activity

1 / идентификатор диалогового окна

private final int IDD EXIT О ;

@Override

puЬlic void onCreate ( Bundle savedinstanceState )

super . onCreate ( savedinstanceState ) ;

setContentView ( R . layout . main ) ;

Page 202: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

196 Глава 9

final Button callButton ( Button ) findViewByid ( R . id . button ) ;

добавляем обработчик события для кнопки вызова диалога

cal lButton . setOnClickListener ( new OnCl ickListener ( ) { @Ove rride

puЬlic void onClick (View v )

1 1 вызываем диалог

showDialog ( IDD_EXIT ) ;

@ Override

protected Dialog onCreateDialog ( int id)

switch ( id ) { case I DD EXIT :

AlertDialog . Builder builder new AlertDialog . Builder ( this ) ;

bui lder . setMessage ( "Are you sure you want to exit? " ) ;

1 / создаем кнопку "Ye s " и обработчик события

bui lder . setPositiveButton (

} ) ;

"Yes " , new Dialoginterface . OnClickListener ( )

puЬlic void onCl ick ( Dialoginterface dialog, int id)

AlertDialogButtonActivity . this . finish { ) ;

1 1 создаем кнопку "No" и обработчик события

bui lder . setNegativeButton (

"No" , new Dialoginterface . OnClickListener ( )

puЬlic void onCl ick ( Dialoginterface dialog , int id)

dialog . cancel ( ) ;

bui lder . setCancelaЬle ( false ) ;

return bui lde r . create ( ) ;

default :

return nul l ;

Запустите проект н а выполнение. П р и нажатии кнопки вызова диалога долж­но появиться окно AlertDialog с кнопками Yes и No. При закрытии диалога

Page 203: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

Диалоговые окна 197

кнопкой Yes приложение закончит работу. Внешний вид приложения показан на рис. 9 .2 .

Рис. 9.2. AlertDialog с кнопками Yes и N o

9.2 .2 . AlertDialog со списком

Чтобы создавать AlertDialog со списком выбираемых пунктов, необхо­димо использовать метод setrtems ( ) , параметрами которого является мас­сив данных для отображения в списке диалога и интерфейс Dialoginterface . OnClickListener, который определяет действие, когда поль­зователь выбирает элемент списка, например:

CharSequence [ ] colors { "Red" , "Green" , "Blue " } ;

builder . setitems ( color s , new Dialoginterface . OnCl ickLi stener ( )

puЫ ic void onCl ick ( Dialoginterface dialog , int i tem)

1 1 обрабатываем событие выбора элемента списка Toast . makeText ( getApplicat ionContext ( ) ,

"Color : + mColors [ i tem] , Toast . LENGTH SHORT ) . show ( ) ;

Для примера приложения с вызовом диалогового окна со списком создайте новый проект и в диалоге Create New Project введите следующие значения :

Page 204: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

198

О Project name - Ale rtDialogLis tApp;

О Application name - AlertDialog with List Sample;

О Package name - com . samples . alertdialoglist;

О Create Activity - AlertDialogLis tAct i vi ty.

Глава 9

Файл разметки main.xml сделайте аналогично листингу 9. 1 . В классе AlertDialogListActivity реализуйте последовательность создания диалога со списком, приведеиную ранее. Полный код класса представлен в листинге 9.3 .

package com . samples . alertdialogl i s t ;

import android . app . Activity;

import android . app . Ale rtDialog ; import android . app . Dialog ;

import android . content . Dialoginterface ;

import android . os . Bundle ;

import android . view . View;

import android . view . View . OnClickListene r ;

import android . widget . Button;

import android . widget . Toas t ;

puЫ ic class AlertDialogLi stActivity extends Activity

private final int I DD_COLOR О ;

final CharSequence [ ) mColors { "Red" , "Green" , "Blue "

@Override

puЫ ic void onCreate ( Bundle savedinstanceState )

super . onCreate ( savedinstanceState ) ;

setContentView ( R . layout . main ) ;

final Button cal lButton ( Button ) findViewByid ( R . id . button ) ;

добавляем слушатель события для кнопки вызова диалога callButton . setOnCl ickListener ( new OnCl ickLi stener ( ) {

@Override

puЫic void onClick (View v )

showDialog ( IDD_COLOR ) ;

Page 205: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

Диалоговые окна 1 99

@ Ove rride

protected Dialog onCreateDia log ( int id)

swit ch ( id ) {

case IDD COLOR :

Al ertDialog . Bui lder bui lder new AlertDi alog . Builder ( thi s ) ;

bui lde r . s etT i t l e ( " Pick а color " ) ;

bui lder . s e t i tems ( mColors ,

new Dialoginterface . OnCl i ckLis tener ( )

puЬ l i c void onCl i c k ( Dialoginte rface dialog , int item)

Toast . ma keText ( getApp l i cat ionContext ( ) , "Color :

mColors [ i tem] , Toast . LENGTH_SHORT ) . show ( ) ;

bui l de r . s etCance laЬle ( fa l se ) ;

return bui lder . create ( ) ;

defaul t :

return nul l ;

G) Pick а color

Red

Green

B l u e

Рис. 9.3. Al ertDialog со списком

Page 206: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

200 Глава 9

Запустите проект на выnолнение. При нажатии кноnки вызова диалога долж­но появиться окно AlertDialog со сnиском из трех nунктов для выбора цвета (рис. 9 .3) . При выборе одного из nунктов меню появится всnлы вающее уве­домление, показывающее выбранный цвет.

9.2 .3 . AlertDialog с радиокнопками

Для создания диалогового окна с радиокноnками nрименяется метод setSingleChoiceitems ( ) . Если диалоговое окно создается внутри onCreateDialog ( ) , система Android уnравляет состоянием сnиска с радио­кнопками . Пока текущая деятельность активна, диалоговое окно при nосле­дующих вызовах запоминает ранее выбранные nункты .

Создание AlertDialog с радиокноnками nохоже на создание диалога со списком, только вместо метода setitems ( )

setSingleChoice items ( ) :

CharSequence [ ] colors { "Red" , "Green" , "Blue " } ;

bui lde r . setS ingleChoiceitems ( colors , О ,

new Dialoginterface . OnCl ickListener ( )

puЬlic void onCl ick ( Dialoginterface dialog , int item)

Toast . ma keText ( getAppl icationContext ( ) , " Color :

Toast . LENGTH_SHORT ) . show ( ) ;

вызывается метод

+ mColors [ item] ,

Первый nараметр в методе setSingleChoiceitems ( ) - массив значений для радиокнопок, второй параметр - целочисленное значение индекса радио­кнопки, которая будет включена по умолчанию nри вызове диалога. Если требуется по умолчанию установить все радиокнопки в выкл юченное состоя­ние, необходимо установить значение второго параметра в - 1 .

ОБРА ТИТЕ ВНИМАНИЕ

П ри нажати и радиокнопки диалог закры ваться не будет. В отлич ие от диалога со списком , которы й закры вается после выбора элемента списка , диалог с ра­диокноп кам и требует добавления командных кнопок для управлен ия диалогом . Диалог закрывается только командны м и кнопками .

Для примера nриложения с вызовом диалогового окна с радиокноnками соз­дайте новый проект и в диалоге Create New Project введите следующие зна­чения:

О Project name - AlertDialogRadioButtonsApp;

О Application name - AlertDialogRadioButtons Sample;

Page 207: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

Диалоговые окна

О Package name - com . samples . alertdialogradiobuttons ;

О Create Activity - AlertDialogRadioButtonsActivity.

201

Файл разметки main .xml сделайте аналогично листингу 9. 1 . В классе

AlertDialogRadioButtonsActi vi ty реализуйте последовательность создания диалога с радиокнопками, как в показаинам ранее примере . Полный код класса представлен в листинге 9.4 .

package com . samples . alertdialogradiobuttons ;

import android . app . Activity;

import android . app . AlertDialog ;

import android . app . Dialog ;

import android . content . Dialoginterface ;

import android . os . Bundl e ;

import android . view . View;

import android . view . View . OnCl ickLis tene r ;

import android . widget . Button ;

import android . widget . Toast ;

puЬlic class AlertDialogRadioButtonsActivity extends Act ivity

private final static int I DD COLOR = О ; private final CharSequence [ ] mColors

@ Override

{ "Red" , "Green" , "Blue " ) ;

puЬlic void onCreate ( Bundle savedinstanceState )

supe r . onCreate ( savedinstanceState ) ;

setContentView ( R . layout . main ) ;

final Button callButton ( Button ) findViewByid ( R . id . button ) ;

добавляем слушатель события для кнопки вызова диалога cal lButton . setOnClickListener ( new OnCl ickListener ( ) {

@Override

puЬlic void onClick ( View v )

showDialog ( IDD_COLOR ) ;

Page 208: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

202 Глава 9

@ Ove rride protected Dialog onCreateDialog ( int id)

switch ( id ) { case IDD COLOR :

AlertDialog . Bui lder bui lder new AlertDialog . Builder ( this ) ; bui lder . setTitle ( " Pick а color' builde r . s etSingleChoiceitems (mColors , О ,

new Dialoginterface . OnClickLis tener ( ) puЫ ic void onCl ick ( Dialoginterface dialog , int item)

Toast . makeText ( getAppl icationContext ( ) , "Color : mColors [ item] , Toast . LENGTH_SHORT ) . show ( ) ;

bui lde r . setCancelaЬle ( fa l s e ) ; return builder . create ( ) ;

defaul t : return nul l ;

Запустите проект н а выполнение . При нажатии кнопки вызова диалога долж­но поя виться окно AlertDialog с тремя радиокнопкам и для выбора цвета. При

Green

B l ue

Рис. 9.4. AlertDialog с радиокнопками

Page 209: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

Диалоговые окна 203

выборе одной из кнопок появится всплывающее уведомление, показывающее выбранный цвет (рис. 9 .4) .

9 .2.4. AlertDialog с флажками

Для создания диалогового окна с радиокнопкам и применяется метод setS ingl eChoicertems ( ) . Если диалоговое окно создается внутри onCreateDialog ( ) , система Andro id управляет состоянием списка. Пока теку­щая деятел ьность активна, диалоговое окно при последующих вызовах запо­минает ранее выбранные пункты .

Создание диалогового окна с флажкам и очень похоже на создание диалога с радиокнопкам и, только вместо метода setS ingleChoicertems ( ) вызывается метод setMul t iChoiceitems ( ) :

Cha rSequence [ ] colors { "Red" , "Green" , "Blue " } ;

final boolean [ ] mCheckeditems { t rue , fal s e , false } ;

builde r . setMult iChoiceitems ( colors , checkeditems ,

new Dialoginterface . OnМul tiChoiceClickListener ( )

@Override

puЫ ic void onCl ick ( Dialoginterface dialog , int which , .

boolean isChecked ) mCheckeditems [ which ] isChecked ;

Первы й параметр в методе setMultiChoice rtems ( ) - массив значений для списка с флажками, второй параметр - булевый массив состояний флажков списка по умолчанию при вызове диалога.

ОБРА ТИТЕ ВНИМАНИЕ Так же , как и для диалога с радиокнопками , для диалога с флажкам и добавляют

командные кноп ки для его закрытия .

Для примера приложения с вызовом диалогового окна с флажкам и создайте новый проект и в диалоге Create New Project введите следующие значения :

D Project name - AlertDialogCheckBoxesApp;

D Application name - Al ertDialogCheckBoxes Sample;

D Package name - сот . samples . alertdialogcheckboxes ;

D Create Activity - AlertDialogCheckBoxesActi v i ty.

Файл разметки main.xml сделайте аналогично л истингу 9 . 1 . В классе AlertDia logCheckBoxesActivity реализуйте последовател ьность создания диа-

Page 210: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

204 Глава 9

лога с радиокнопками, приведеиную ранее. Полный код класса, реализующе­го деятельность, представлен в листинге 9 .5 .

package com . samples . alertdialogcheckboxes ;

import android . app . Activity;

import android . app . AlertDialog ;

import android . app . Dialog ;

import android . content . Dialoginterface ;

import android . os . Bundle ;

import android . view . View;

import android . view . View . OnClickListene r ;

import android . widget . Button ;

import android . widget . Toas t ;

puЬlic class AlertDialogCheckBoxesActivity extends Act ivity

private final static int I DD_COLOR О ;

final CharS�quence [ ] mColors

final boolean [ ] mCheckedi tems

@Override

"Red" , "Green " , "Blue " ) ;

{ t rue , false , false ) ;

puЬl ic void onCreate ( Bundle savedinstanceState )

super . onCreate ( savedinstanceState ) ;

setContentView ( R . layout . main ) ;

f inal Button callButton ( Button ) findViewByid ( R . id . button ) ;

добавляем слушатель события для кнопки вызова диалога cal lButton . setOnCl ickListener ( new OnClickListener ( ) {

@Override

puЬlic void onClick ( View v )

showDialog ( IDD_COLOR ) ;

@ Override

protected Dialog onCreateDialog ( int id) {

s.witch ( id ) {

case I DD COLOR :

Page 211: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

Диалоговые окна 205

AlertDialog . Builder builder = new AlertDialog . Builder ( this ) ; builde r . setTi tle ( " Pick а color " ) ;

bui lder . setMultiChoiceitems (mColors , mCheckeditems , new Dialoginterface . OnМult iChoiceClickListener ( )

@Override puЬlic void onCl ick ( Dialoginterface dialog , int which,

boolean i sChecked ) { mCheckeditems [ which ] isChecked ;

builder . setPositiveButton ( "Yes " , new Dialogint.erface . OnClickListener ( )

puЬlic void onCl ick ( Dialoginterface dialog , int id) StringBuilder s tate new StringBuilder ( ) ; for ( int i О ; i < mColors . length ; i++ )

state . append ( "Color : + mColors [ i ] +

i f (mCheckeditems [ i ] ) s tate . append ( " checked\n " ) ;

else s tate . append ( "unchecked\n" ) ;

state :

Toast . makeText ( getApplicationContext ( ) , state . toString ( ) , Toas t . LENGTH_LONG ) . show ( ) ;

builder . setNegativeButton ( "No" , new Dialoginterface . OnCl ickListener ( )

puЬlic void onCl ick ( Dialoginterface dialog, int id) dialog . cancel ( ) ; Toast . makeText ( getApplicationContext ( ) ,

" Dialog cancel " , Toast . LENGTH_SHORT ) . show ( ) ;

bui lder . setCancelaЬle ( false ) ; return builder . create ( ) ;

default : return nul l ;

Page 212: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

206 Глава 9

Заnустите nроект на вы nолнение . При нажатии кноnки вызова диалога долж­но nоявиться окно AlertDialog со сnиском из трех флажков для выбора цвета (рис. 9 . 5 ) . При закрытии диалогового окна кноnкой Yes nоя вится всnлываю­щее уведомлен ие, nоказывающее состоян ие флажков выбора цвета.

B l u e color: Blue, state: checked

Рис. 9.5. Al ertDialog с флажками

9 .3 . ProgressDialog Progre s s Di a log - nодкласс Al ertDia log, которы й nредставляет собой диало­говое окно с инди катором nрогресса. В диалог также можно добавить уnрав­ляющие кноnки, наnример для отмены вы nолняемой задачи .

Для создания диалога с и ндикатором nрогресса необходимо инициа­лизировать объект Prog re s s D ia log вызовом конструктора класса Progre s s Di a l og ( Context ) , nередав в качестве nараметра контекст текущей деятельности :

Progre s s D i a l og progre s s Di a l og new Progre s s Di alog ( Ac t ivity_Name . thi s ) ;

Далее надо установить требуемые свойства диалогового окна, наnример:

progre s s Di a l og . s et Progre s s Style ( Progre s s Di a l og . STYLE_HORIZONTAL ) ;

progre s s Di a log . s etMe s s age ( " Loading .

progre s s D i a l og . s etCance laЬle ( fa l s e ) ;

Page 213: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

Диалоговые окна 207

Обычно выпол нение длительных задач происходит в другом потоке, т. е. в нашем приложении необходимо создать второй поток и сообщать о прогрессе его выполнения назад, в основной поток деятельности через объект Handler

(создание потока мы рассматривали в главе 5):

Handler handler new Handler ( )

puЬl ic void handleMessage ( Mes sage msg )

progre s s Dialog . setProgres s ( total ) ;

В качестве примера приложения, в котором будет вызываться диалоговое окно с индикатором прогресса, создайте в Ecl ipse новый проект и в диалоге Create New Project введите следующие значен ия :

L] Project name - ProgressDialogApp;

L] Application name - ProgressDialog Sample;

О Package name - com . samples . progressdia log;

L] Create Activity - Progress DialogActivity.

Структура фаЙла разметки будет аналогична листингу 9 . 1 . В классе Progress DialogActivity реализуйте последовательность создания и задания свойств для диалога, приведен ную ранее. Код для запуска и работы второго потока реализован в классе SecondThread, который создается и запускается в методе обратного вызова onCreateDia log ( ) класса деятельности .

Полный код класса Progre s s Dia logActivity, реализующего деятельность для приложения, представлен в листинге 9 .6 . Код класса SecondThread для работы с потоком - в л истинге 9 .7

package com . samples . progres sdia log ;

import android . app . Act ivity ;

import android . app . Dia l og ;

import android . app . Progre s s Dialog ;

import android . os . Bundle ;

import android . os . Handle r ;

import android . os . Message ;

import android . view . View ;

Page 214: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

208

import android . view . View . OnClickListene r ; import android . widget . Button ; import android . widget . Toast ;

puЫic class ProgressDialogActivity extends Activity

static final int I DD PROGRESS О ;

private SecondThread mSecondThread ; private ProgressDialog mProgressDialog;

puЬlic void onCreate ( Bundle savedinstanceState ) supe r . onCreate ( savedinstanceState ) ;

setContentView ( R . layout . main) ;

Глава 9

final Button callButton = ( Button ) findViewByid ( R . id . button ) ;

callButton . setOnClickLis tener ( new OnClickLi stene r ( ) { puЬlic void onClick (View v ) {

showDialog ( IDD_PROGRESS ) ;

�rotected Dialog onCreateDialog ( int id)

switch ( id) { case I DD PROGRESS :

mProgress Dialog new ProgressDialog ( ProgressDialogActivity . thi s ) ;

mProgress Dialog . setProgres s Style ( ProgressDialog . STYLE_HORI ZONTAL ) ;

mProgress Dialog . setMessage ( " Loading . Please wai t . . . " ) ; mSecondThread new SecondThread ( handler ) ; mSecondThread . start ( ) ;

return mProgressDialog;

default : return nul l ;

1 1 обработчик, который получает сообщения от потока и

1 1 обновляет индикатор прогресса final Handle r handler new Handler ( )

puЬlic void handleMessage (Message msg )

int total = msg . getData ( ) . getint ( "Total " ) ;

Page 215: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

Диалоговые окна 209

rnProgress Dialog . setProgres s ( total ) ;

i f ( total >= 1 0 0 ) { di srni s s Dia1og ( IDD_PROGRESS ) ;

rnSecondThread . setState ( SecondThread . STATE_DONE ) ;

Toast . rnakeText ( getApplicationContext ( ) , "Task is finished" , Toast . LENGTH_SHORT ) . show ( ) ;

package corn . sarnples . progres sdialog ;

irnport android . os . Bundle ; irnport android . os . Handle r ; irnport android . os . Message ; irnport android . ut i l . Log ;

puЬlic class SecondThread extends Thread

Handler rnНandler ; ы final static int STATE DONE О ;

final static int STATE RUNNING 1 ;

int rnState ;

int rnTotal ;

SecondThread ( Handler hnd ) rnНandler hnd ;

puЬl ic void run ( ) {

rnState STATE_RUNNING ;

rnTotal О ; whi le (rnState

try {

STATE_RUNNING )

Thread . sleep ( 1 0 0 ) ; catch ( InterruptedExcept ion е )

Log . е ( "ERROR" , "Thread Interrupted" ) ;

Message rnsg rnНandler . obtainМessage ( ) ; Bundle Ь new Bundle ( ) ;

b . put !nt ( "Total " , rnTotal ) ;

Page 216: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

2 1 0

rns g . setData ( Ь ) ;

rnНandl e r . s endМes sage (rnsg ) ;

rnTotal++ ;

puЬl i c void setState ( int s tate )

rnState state ;

Глава 9

Запустите проект на выполнение . При нажатии кнопки вызова диалога долж­но появиться диалоговое окно с индикатором прогресса и надписями , ото­бражающими степень завершения задачи (рис. 9 .6) .

Р и с . 9 . 6 . Prog re s s Dialog с о стилем STYLE _ HORIZONTAL

Метод s e t Progre s s Style ( ) устанавл ивает стиль диалога. Стил и задаются кон­стантами, определен ными в классе Progre s s Dialog:

0 STYLE _ HORIZONTAL;

0 STYLE SPINNER.

Попробуйте поменять стиль ш калы и ндикатора прогресса в приложении . Из­мените в листинге 9 .6 строку с вызовом метода s e tProgre s s Style ( ) :

progres s Dialog . s e t P rogre s s S tyle ( Prog res s Di a log . STYLE_S PINNER ) ;

Page 217: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

Диалоговые окна 21 1

Измените код в классе и заnустите nроект на выnолнение . При нажатии кноnки вызова диалога должно nоя виться окно Progre s s Dialog, но уже не с л и нейным, а с круговым инди катором nрогресса (рис. 9 .7) .

Рис. 9 .7 . Progre s s Dialog со стилем STYLE _ S PINNER

9 .4. DatePickerDialog DatePicke rDialog nредназначен для выбора даты nользователем . Обычно nе­ред созданием диалога выбора даты надо nолучить текущий год, месяц и день из системы . Это можно сделать, создав экзем nляр класса Ca l endar и заnисав дату через метод get ( ) класса Cal enda r в nеременные, создан ные в нашем классе:

Calendar с Cal endar . get i nstance ( ) ;

�Year c . get ( Calenda r . YEAR ) ;

�onth c . get ( Cal enda r . MONTH ) ;

mDay c . ge t ( Calenda r . DAY_OF_MONTH ) ;

Затем в onCreateDia log ( ) надо создать объект DatePicke rDialog вызовом кон­структора класса:

�atePickerDialog dialog new Da tePi ckerDialog (

thi s , rnDateSetLis tene r , rnYe a r , rnМonth , rnDay ) ;

Page 218: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

212 Глава 9

Первый параметр, передаваемый в конструктор, - это контекст текущей дея­тельности, второй - имя метода обратного вызова для обработки события установки даты, остальные параметры содержат дату, которую отобразит за­пускаемый диалог.

Имя метода обратного вызова для обработки, события установки даты - это реализация вложенного интерфейса DatePickerDialog . OnDatesetLi stener, ко­торая, например, может модифицировать передаваемые переменные, храня­щие дату:

private DatePi ckerDialog . OnDateSetListener mDateSetListener

new DatePicke rDialog . OnDateSetListene r ( ) {

puЬlic void onDateSet ( DatePicker view, int year ,

int monthOfYear, int dayOfMonth ) {

mYear yea r ;

mМonth monthOfYea r ;

mDay = dayOfМonth ;

Вызов диалога производится обычным способом - через метод showDialog ( int dialogid) .

В качестве примера приложения с вызовом диалогового окна установки даты создайте новый проект и в диалоге Create New Project введите следующие значения :

D Project name - DatePickerDialogApp;

D Application name - DatePickerDialog Sample;

D Package name - сот . samples . datepickerdialog;

D Create Activity - DatePickerDialogActi vi ty.

Откройте файл разметки и создайте структуру разметки с текстовым полем и кнопкой вызова подобно листингу 9 .8 .

<?xml vers ion= " l . O " encoding="utf- 8 " ?>

<LinearLayout xmlns : android="http : / / schemas . android . com/apk/ res/android"

android : layout_width="wrap_content "

android : layout_he ight="wrap_content "

android : orientation="ve rt ica l " >

<TextView

android : id= " @ +id/text "

Page 219: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

Диалоговые окна

android : layout_width= "wrap content "

android : layout_height="wrap_content "

android : textS i ze= " 2 8px "

android : textStyle="bold"

android : text= " " />

<Button

android : id=" @ + id/button"

android : layout_width= "wrap_content "

android : layout_height="wrap_content"

android : text=" Change the date " / >

< /LinearLayout>

213

Полны й код класса деятельности, реализующий работу с DatePickerDialog,

приведен в листинге 9 .9 .

package com . samples . datepickerdialog ;

import j ava . ut i l . Calendar ;

import android . app . Activity;

import android . app . DatePickerDialog ;

import android . app . Dialog ;

import android . os . Bundle ;

import android . view . View;

import android . widget . Button;

import android . widget . DatePicke r ;

import android . widget . TextView ;

puЬlic class DatePickerDialogActivity extends Act ivity

private TextView mDateDisplay;

private Button mPickDate ;

private int mYear ;

private int mМonth;

private int mDay ;

static final i n t IDD DATE О ;

@Ove rride

protected void onCreate (Bundle savedinstanceState ) {

Page 220: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

2 1 4

super o onCreate ( savedinstanceState ) ;

setContentView ( R o layout o main ) ;

mDateDisplay ( TextView ) findViewByid ( R o id o text ) ;

mPickDate ( Button ) findViewByid ( R o id o button) ;

добавляем слушатель события для кнопки вызова диалога

mPickDate o setOnCl ickListene r ( new View o OnClickLis tener ( )

puЬlic void onClick (View v )

showDialog ( I DD_DATE ) ;

1 1 читаем текущую дату

final Calendar с Calendar o getinstance ( ) ;

mYear C o get ( Calendar o YEAR ) ;

mМonth c .. get ( Calendar о MONTH ) ;

mDay C o get ( Calendar o DAY_OF_MONTH ) ;

показываем текущую дату

updateDisplay ( ) ;

@ Override

protected Dialog onCreateDialog ( int id)

swi tch ( id ) {

case IDD DATE :

return new DatePickerDialog ( this ,

mDateSetListene r ,

mYear, mМonth, mDay ) ;

return nul l ;

обновляем дату, которая отображается в TextView

private void updateDisplay ( )

mDateDisplay o setText (

new St ringBui lder ( )

1 1 месяц отсчитывается с О , поэтому добавляем 1

o append (mМonth 1 ) o append ( " - " )

о append (mDay) о append ( " - " )

o append (mYear ) o append ( " " ) ) ;

Глава 9

Page 221: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

Диалоговые окна

private Dat e P i c ke rDialog . OnDateSet L i s t ener rnDateSetLis tene r

new Date P i c ke rDialog . OnDateSetLis tene r ( )

puЬl i c void onDateSet ( DatePicker view , int yea r ,

int monthOfYea r , int dayOfMonth )

mYear yea r ;

mМonth monthOfYear ;

rnDay dayOfМonth ;

updateDi splay ( ) ;

2 1 5

Запустите проект на выполнение . При нажатии кнопки вызова диалога долж­но появиться окно DatePickerDialog, в котором пол ьзователь может устано­вить дату. При закрытии диалога возвращаемый результат запишется в тек­стовое поле в верхней части экрана приложения .

Внешний вид приложения с вызван ным диалогом установки даты показан на рис. 9 . 8 .

Рис. 9.8. Диалог DatePickerDialog

Page 222: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

2 1 6 Глава 9

9 .5 . TimePickerDialog TimePickerDialog предназначен для выбора даты пользователем . В целом процедура создания диалога выбора времени аналогична созданию DatePickerDialog с небольшими отличиями в деталях.

Если необходимо прочитать текущее системное время, также используется класс Calendar, например:

Calendar с Ca lendar . get instance ( ) ; mНour c . get ( Calendar . HOUR_OF_DAY ) ; mМinute c . get ( Calendar . MINUTE ) ;

Затем в oncreateDialog ( ) надо создать объект TimePickerDialog вызовом кон­структора класса:

TimePickerDialog dialog new TimePickerDialog ( thi s , timeSetListener, mНour, mМinute , false ) ;

В последнем параметре конструктора указывается формат отображения вре­мени 1 2-часовой (АМ/РМ) - fal se или 24-часовой - t rue.

Имя метода обратного вызова для обработки события установки даты - это реализация вложенного интерфейса TimePickerDialog . OnTimeSetListener, на­пример:

private TimePickerDialog . OnTimeSetLi stener mTimeSetListener

new TimePickerDialog . OnTimeSetListener ( )

puЬlic void onTimeSet ( TimePicker view,

int йourOfDay, int minute ) {

mНour hourOfDay ;

mМinute minute ;

В качестве примера приложения с вызовом диалога установки времени соз­дайте новый проект и в диалоге Create New Project введите следующие зна­чения :

LJ Project name - TimePickerDialogAct i vi tyApp;

LJ Application name - TimePicke rDialogAct ivity Sample;

LJ Package name - com . samples . t imepicke rdialog;

LJ Create Activity - TimePickerDialogActivity.

Структура файла разметки аналогична листингу 9.9 для DatePickerDialog.

Код класса деятельности TimePickerDialogActivity приведен в листинге 9 . 1 О.

Page 223: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

Диалоговые окна

package com . samples . t imepickerdialog ;

import j ava . ut i l . Calenda r ;

import android . app . Act ivity;

import android . app . Dialog ;

import android . app . TimePickerDialog ;

import android . os . Bundle ;

import android . view . View;

import android . widget . Button ;

import android . widget . TextView ;

import android . widget . TimePicke r ;

puЬlic c l a s s TimePickerDialogActivity extends Act ivity

private TextView mTimeDisplay ;

private Button mPickTime ;

private int mНour ;

private int mМinut e ;

stat i c final i�t I DD ТIМЕ 0 ;

@Override

protected void onCreate ( Bundle s avedinstanceState )

super . onCreate ( savedinstanceState ) ;

setContentView ( R . layout . main ) ;

mTimeDi splay ( TextView ) findViewByid ( R . i d . tex t ) ;

mPickTime ( Button ) findViewByid ( R . id . button ) ;

mPickTime . setOnClickLi stene r ( new View . OnCl i ckListener ( )

puЬlic void onClick ( View v )

showDialog ( IDD_TIМE ) ;

1 1 читаем текущее время

final Ca lendar с Calendar . getinstance ( ) ;

mНour = c . get ( Ca lenda r . HOUR_OF_DAY ) ;

mМinute = c . get ( Calendar . MINUTE ) ;

2 1 7

Page 224: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

218

обновляем вывод времени на экран

updateDi splay ( ) ;

@Override

protected Dialog onCreateDialog ( int id)

swi tch ( id) {

case I DD ТIМЕ :

return new TimePicke rDialog (

thi s , mTimeSetListener , mнour, mМinut e , fal se ) ;

return nul l ;

обновление вьffiода времени на экран в поле TextView

private void updateDisplay ( )

mTimeDisplay . setText (

new StringBuilder ( )

. append (pad (mRour) ) . append ( " : " )

. append (pad (mМinute ) ) ) ;

private TimePicke rDialog . OnTimeSetListener mTimeSetListener

new TimePickerDialog . OnTimeSetListener ( )

puЬlic void onTimeSet ( TimePicker view,

int hourOfDay, int minute )

mнour hourOfDay ;

mМinute minute ;

updateDisplay ( ) ;

private static String pad ( int с )

i f ( с > = 1 0 )

return String . valueOf ( c ) ;

else

return " О " + String . valueOf ( c ) ;

Глава 9

Запустите проект на выполнение. При нажатии кнопки вызова диалога долж­но появиться окно Time PickerDialog, в котором пользователь может устано­вить время . При закрытии диалога возвращаемый результат запишется в тек­стовое поле в верхней части экрана приложения (рис. 9 .9) .

Page 225: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

Диалоговые окна 2 1 9

Рис. 9.9. Диалог T imePickerDialog

9 .6 . Создание собственных диалогов Если есть необходимость в создании оригинального дизайна для диалога, можно создать собственную разметку для диалогового окна. После создания разметки необходимо nередать корневой объект разметки в код создания диалога.

Чтобы nолучить корневой объект разметки, исnользуется класс Layout inflater. Этот класс нужен для nреобразования ХМL-разметки в соот­ветствующие объекты View в коде nрограммы .

Сначала необходимо инициализировать объект Layout inflater вызовом ме­тода getLayout inflater ( ) , затем nолучить корневое nредставление методом inflate ( int , ViewGroup ) , где nервый nараметр - идентификатор ресурса схемы размещения, второй - идентификатор корневого nредставления раз­метки :

Layout inflater inflater getLayout inflater ( ) ;

View layout inflate r . inflate ( R . layout . cus tom_layout ,

(ViewGroup ) findViewByid ( R . id . toast layout ) ) ;

Получив корневое nредставление, можно методом findViewByid ( ) инициал и­зировать все дочерние nредставления в разметке и задать для них информа-

Page 226: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

220 Глава 9

ционное наnолнение. Наnример, есл и в разметке оnределены виджеты TextView и ImageView, код может выглядеть так:

TextView text (TextView ) layout . findViewByid ( R . id . text ) ;

text . setText ( "Are you sure you want to exit ? " ) ;

ImageView image ( ImageView) layout . findViewByid ( R . id . image ) ;

image . setimageResource ( R . drawaЬle . androidЗd ) ;

Далее создается объект AlertDialog . Bui lder и методом setView ( ) для него устанавливается nолученная ранее разметка:

AlertDialog . Builde r builde r

bui lde r . setView ( layout ) ;

new AlertDialog . Bui lder ( this ) ;

Остальная инициал изация свойств диалога и работа с ним в коде nрограммы аналогична работе со стандартны м AlertDialog.

В качестве nримера nриложения с собственным диалоговым окном создайте новый nроект и в диалоге Create New Project введите следующие значения :

r:J Project name - CustomDialogApp;

r:J Application name - CustomDialog Sample;

r:J Package name - сот . samples . cus tomdialog;

r:J Create Activity - CustomDialogActivity.

Структура файла разметки для деятельности nриложения аналогична листин­гу 9 . 1 . Создайте также отдельный файл разметки для диалогового окна, как показано в листинге 9 . 1 1 .

<LinearLayout xmlns : android="http : / /schemas . android . com/apk/re s / android"

android : id= " @ +id/toast_layout "

android : orientation="hori zont a l "

android : layout_width= " fi l l_parent "

android : layout_height= " fi l l_parent "

android : padding=" l Odp"

android : background= " # DAAA" >

< ImageView android : id=" @+id/image"

android : layout_width="wrap_content "

android : layout_height=" f i l l_parent "

android : layout_marginRight=" l Odp " />

Page 227: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

Диалоговые окна

<TextView android : id=" @ +id/text "

android : layout_width="wrap_content "

android : layout_height= " fi l l_parent "

androi d : textColor= " # FFF" />

</LinearLayout>

221

В классе customDialogActivity реал изуйте создание и вызов диалогового окна с собственной разметкой, как было показано ранее в этом разделе. Полный код класса Cus tomDialogActivity показан в листинге 9 . 1 2 .

package com . samples . customdialog ;

import android . app . Activity;

import android . app . Ale rtDialog ;

import android . app . Dialog ;

import android . content . Dialoginterface ;

import android . os . Bundle ;

import android . view . Layout inflater ;

import android . view . View;

import android . view . ViewGroup ;

import android . view . View . OnClickListene r ;

import android . widget . Button ;

import android . widget . ImageView;

import android . widget . TextView;

import android . widget . Toast ;

puЬlic class CustomDialogActivity extends Act ivity

private final static int I DD CUSTOM 0 ;

@Override

puЬlic void onCreate ( Bundle savedinstanceState )

super . onCreate ( savedinstanceState ) ;

setContentView ( R . layout . main ) ;

final Button callButton ( Button ) findViewByid ( R . id . button ) ;

добавляем слушатель события для кнопки вызова диалога callButton . setOnClickListene r ( new OnClickListener ( ) {

@Override

Page 228: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

222

puЬlic void onClick (View v )

showDialog ( IDD_CUSTOM ) ;

@Override

protected Dialog onCreateDialog ( int id)

switch ( id ) { case I DD CUSTOM :

Layout inflater inflater getLayout inflate r ( ) ;

View layout inflate r . inflate ( R . layout . custorn_layout ,

(ViewGroup ) findViewByid ( R . id . toast_layout ) ) ;

Глава 9

TextView text ( TextView) layout . findViewByid ( R . id . text ) ;

text . setText ( "Are you sure you want to exit ? " ) ;

IrnageView irnage ( IrnageView) layout . findViewByid ( R . i d . irnage ) ;

image . set irnageResource ( R . drawaЬle . androidЗd) ;

new AlertDialog . Builde r ( thi s ) ; AlertDialog . Bui lder bui lder

bui lde r . setView ( layout ) ;

builde r . setMessage ( "This i s а custorn dialog ! " ) ;

bui lder . setPositiveButton (

"Yes " , new Dialoginterface . OnCl ickListener ( )

puЬlic void onCl ick ( Dialoginterface dialog, int id)

CustornDialogAct ivity . this . finish ( ) ;

builder . setNegativeButton (

"No " , new Dialoginterface . OnClickListener ( )

puЬlic void onCl ick ( Dialoginterface dialog, int id)

dialog . cancel ( ) ; }

bui lde r . setCancelaЬle ( fa l se ) ;

return bui lder . create ( ) ;

de fault :

return nul l ;

Page 229: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

Диалоговые окна 223

Запустите проект на вы пол нение . При нажатии кнопки вызова диалога долж­но поя виться окно AlertDia log с кнопкам и Yes и No и с созданн ы м нами не­стандартным информационным напол нением . При закрытии диалога кнопкой Yes приложение закончит работу (рис. 9 . 1 0) .

Рис. 9. 1 0 . Диалог с собственным дизайном

Page 230: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

Г Л А В А 1 0

Меню

Меню - важная часть любого приложения . Android предлагает простой ин­терфейс программ ирования для создания стандартизированных прикладных �еню для приложений с разнообразной функциональностью.

Android предлагает три базовых типа прикладных меню:

О Options Мепи (Меню выбора опций) - набор пунктов меню, прикрепляе­мый к деятельности . Меню появляется внизу экрана при нажатии клавиши <M ENU> на мобильном устройстве . Для меню выбора опций дополни­тельно существует еще две разновидности меню:

• Icon Menu (Меню со значками) - расширение меню выбора опций, до­бавляющее значки к тексту в пункты меню. Меню может содержать максимум шесть пунктов . Этот тип меню - единственный, который поддерживает значки;

• Expanded Menu (Расширетюе меюо) - вертикальный выпадающий список пунктов меню. Расширенное меню появляется при наличии бо­лее шести пунктов меню. При этом в меню выбора опций появляется дополнительны й пункт More. Расширенное меню добавляется автома­тически системой Aпdroid. При нажатии пункта More показы вается расширенное меню со списком пунктов, которые не поместились в ос­новной части меню выбора опций;

О Context Мепи (Коитекстное меню) - всплывающий список пунктов ме­ню, которые появляются при касании сенсорного экрана в течение двух и более секунд (событие loпg-press);

О SиЬтепи (Подменю) - всплы вающий список пунктов меню, который при­вязан к конкретному пункту в меню выбора опций или в контекстном ме­ню. Пункты подменю не поддерживают вложенные подменю.

Page 231: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

226 Глава 1 0

1 0 . 1 . Мен ю выбора оп ци й Меню выбора оnций - наиболее расnространенный тиn меню в nриложени­ях. Меню, как уже говорилось ранее, открывается nри нажатии на мобильном устрой<.:тве клавиши <MEN U>.

Когда это меню открывается вnервые, система Aпdroid вызы вает метод onCreateOptionsMenu ( ) , nередавая в качестве nараметра объект мenu. Этот ме­тод необходимо реализовать в классе деятельности, где nроисходит вызов меню, и создать информационное наnолнение для объекта мenu. Меню можно оnределить в ХМL-файле или использовать метод add ( J для nоследователь­ного nрисоединения каждого пункта меню, наnример:

сначала определяем идентификаторы для создаваемых пунктов меню private static final int I DM OPEN 1 0 1 ;

private static final int I DM SAVE 1 0 2 ;

puЬlic boolean onCreateOptionsMenu (Menu menu )

1 1 добавляем пункты меню menu . add (Menu . NONE , I DM_OPEN , Menu . NONE , "Open " ) ;

menu . add (Menu . NONE , I DM_SAVE , Menu . NONE , " Save " ) ;

Метод add ( J , испол ьзуем ый в этом примере, принимает четыре параметра:

r:J идентификатор группы - позволяет связывать этот пункт меню с груnпой других nунктов этого меню (о груnпах меню будет рассказано nозже в этой главе);

r:J идентификатор пункта для обработчика события выбора пункта меню (оn­ределяется в коде заранее);

r:J порядок расположения nункта в меню - позволяет нам определять пози­цию пункта в меню. По умолчанию (значение мenu . NONE или О) они будут отображены в соответствии с nоследовательностью добавления в коде;

r:J заголовок - текст на пункте меню (он может также быть строковым ре-сурсом , если необходимо создавать локализованные приложения) .

Этот метод возвращает объект мenurtem, который можно исnользовать для установки доnолнительных свойств, наnример значка, "горячих" клавиш и других nараметров настройки для этого nункта меню.

Метод onCreateOpt ionsMenu ( ) вызывается системой только один раз, nри соз­дании меню. Если требуется обновлять меню каждый раз nри его вызове из nрограммы, необходимо оnредел ить в nрограмме метод обратного вызова onPrepareOptionsMenu ( ) .

Page 232: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

Меню 227

При выборе пункта меню пользователем будет вызван метод onOpt ions itemSelected ( ) , который необходимо определить в классе, реали­зующем деятельность . Этот метод обратного вызова передает в программу объект мenuitem - пункт меню, который был выбран пользователем . Иден­тифицировать выбранный пункт меню можно методом get itemid ( ) , кото­рый возвращает целое ч исло, являющееся идентификатором пункта меню, который был назначен ему в методе add ( ) при создании меню в onCreateOpt ionsMenu ( ) . После идентификации пункта меню можно написать код, реализующий обработку события выбора меню.

Обработчик события выбора пункта меню будет выглядеть примерно так:

puЬlic boolean onOptions itemSelected ( Menuitem item)

switch ( item . geti temid ( )

case I DM OPEN :

return t rue ;

case I DM SAVE :

return t rue ;

return false ;

Дпя меню также возможно добавить "горячие" клавиши (или сочетания кла­виш) для быстрого доступа, используя символы клавиатуры . Дпя добавления "горячих" клавиш в меню существует несколько методов:

D setAlphabeticShortcut ( char ) - добавляет символ ;

D setNumericShortcut ( int ) - добавляет число;

D setShortcut ( char , int ) - добавляет комбинацию символа и ч исла.

Например:

setAlphabeticShortcut ( ' q ' ) ;

Теперь при открытии меню (или при удерживании клавиши <M ENU>) нажа­тие клавиши <q> выберет этот пункт меню. Эта быстрая клавиша (или соче­тание клавиш) будет показана как подсказка, отображающаяся н иже имени пункта меню.

Дпя примера приложения с меню создайте новый проект и в диалоге Create New Project введите следующие значения :

D Project name - Opt ionsMenuApp;

D Application name - OptionsMenu Sample;

Page 233: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

228

О Package name - сот . samples . opt ionsmenu;

О Create Activity - OptionsMenuActivity.

Глава 10

Откройте файл разметки и создайте структуру разметки подобно листин­гу 1 0 . 1 .

< ?xml vers ion= " l . O " encoding="utf- 8 " ?> <LinearLayout xmlns : android= "http : / /schemas . android . com/apk/ res /android"

android : orientation="vertical " android : layout_width= " fil l_parent " android : layout_height=" fi l l_parent "

android : gravity= " center " >

<TextView

android : layout_width= " fi l l parent " androi d : layout_height="wrap_content "

androi d : text= " Pres s МENU button . . . " android : gravity= " center"

android : textStyle= "bold" />

</LinearLayout>

В классе OptionsMenuActivity реализуйте процедуру создания и обработки пользовательского взаимодействия с меню, приведеиную ранее. Полный код класса Opt ionsMenuActivity приведен в листинге 1 0 .2 .

package com . samples . optionsmenu;

import android . app . Act ivity;

import android . os . Bundl e ; import android . view . Gravity; import android . view . Menu ; import android . view . Menuitem;

import android . widget . Toas t ;

puЬlic class Opt ionsMenuActivity extends Activity / 1 идентификаторы для пунктов меню

puЬl ic static final int I DM OPEN 1 0 1 ;

puЬl ic static final int I DM SAVE 1 02 ;

puЬl ic static final int I DM EDIT 1 0 3 ;

Page 234: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

Меню

puЬlic static fina1 int I DM HELP

puЬlic static fina 1 int I DM EXIT

1 0 4 ;

1 0 5 ;

@Override

puЬlic void onCreate ( Bund1e savedinstanceState )

super . onCreate ( savedinstanceStat e ) ;

setContentView ( R . 1ayout . main ) ;

@Override puЬlic boo1ean onCreateOpt ionsMenu ( Menu menu) {

menu . add (Menu . NONE , I DM_OPEN , Menu . NONE , "Open " )

. setA1phabeticShortcut ( ' o ' ) ;

menu . add ( Menu . NONE , I DM_SAVE , Menu . NONE , " Save " )

. setA1phabeticShortcut ( ' s ' ) ;

menu . add ( Menu . NONE , I DM_EDI T , Menu . NONE , "Edit " )

. setA1phabeticShortcut ( ' e ' ) ;

menu . add (Menu . NONE , I DM_HELP , Menu . NONE , " Не1р" )

. setA1phabeticShortcut ( ' h ' ) ;

menu . add (Menu . NONE , I DM_EXI T , Menu . NONE , " Exit " )

. setA1phabeticShortcut ( ' x ' ) ;

return ( supe r . onCreateOpt ionsMenu (menu ) ) ;

@Override

puЬlic boo1ean onOptions itemSe1ected (Menuitem item)

CharSequence message ;

switch ( item . getitemid ( ) )

case I DM OPEN :

mes sage

break ;

case I DM SAVE :

mes sage

break;

case I DM HELP :

mes sage

break ;

case I DM EDIT :

mes sage

break ; case I DM EXIT :

"Open item se1ected" ;

" Save item se1ected" ;

"Не1р item se1ected" ;

"Edit item se1ected" ;

mes sage = "Exit item se1ected" ;

break ;

229

Page 235: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

230 Глава 1 0

de faul t :

return fa l s e ;

Toast toa s t Toa s t . ma keText ( thi s , mes sage , Toas t . LENGTH_SHORT ) ;

toa s t . s etGravi ty ( Gravi ty . CENTER , О , 0 ) ;

toa s t . show ( ) ;

return t rue ;

Запустите проект на выпол нение. При нажати и клавиши <MENU> клавиату­ры эмулятора на экране должно поя виться меню из пяти пунктов : Open, Save, Edit, Help, Exit (рис. 1 0 . 1 ) .

Op<.m Save

Edlt Help EXIt

Рис. 1 0 . 1 . Вызов меню в деятельности

1 0 . 1 . 1 . Меню со значками

В меню можно также отображать значки для каждого пункта. Значк·и добав­ляются методом s e t i con ( ) При создании меню. Например:

menu . add ( Menu . NONE , I DM_OPEN , Menu . NONE , "Open " )

. se t i con ( R . drawaЫ e . ic_menu_open ) ;

menu . add ( Menu . NONE , I DM_SAVE , Menu . NONE , " Save " )

. s e t i con ( R . drawaЫ e . i c_menu_s ave ) ;

Page 236: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

Меню 23 1

В качестве примера приложения, имеющего меню со значками, создайте в Ecl ipse новый проект и в диалоге Create New Project заполните поля :

D Project name - I conМenuApp;

D Application name - IconМenu Samp1e;

D Package name - com . samp1es . iconmenu;

D Create Activity - I conМenuAct ivity.

Файл разметки для меню со значками оставьте таким же, как в предыдущем примере (см. листинг 1 0 . 1 ) . Примеры значков можно взять с пр илагаемо­го к книге CD-ROM, в каталоге Resources/Menu_Icons/ - это файлы ic_menu_open .png, ic_menu_save.png, ic_menu_edit, ic_menu_help и ic_menu_ exit.

Класс Opt ions i conМenuActivity, реализующий меню со значкам и, представлен в листинге 1 0 . 3 .

package com . samp1es . options iconmenu ;

import android . app . Activity; import android . os . Bund1e ; import android . view . Gravity; import android . view . Menu ; import android . view . Menuitem; import android . widget . Toast ;

puЬlic c1ass Opt ions iconМenuActivity extends 1 1 идентификаторы для пунктов меню puЬ1 ic static fina1 int I DM OPEN 1 0 1 ; puЬ1 ic static fina1 int I DM SAVE 1 02 ; puЬlic static fina1 int I DM EDIT 1 0 3 ; puЬ1 ic static fina1 int I DM HELP 1 0 4 ; puЬl ic static fina1 int I DM EXIT 1 0 5 ;

@Override

Activity

puЬ1 ic void onCreate ( Bund1e savedinstanceState ) super . onCreate ( savedinstanceState ) ; setContentView ( R . 1ayout . main ) ;

@Override

puЬ1ic boo1ean onCreateOpt ionsMenu ( Menu menu ) { menu . add (Menu . NONE , I DM_OPEN , Menu . NONE , "Open" )

. seticon ( R . drawaЬle . ic_menu_open ) ;

Page 237: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

232 Глава 10

menu . add (Menu . NONE , I DM_SAVE , Menu . NONE , " Save " ) . seticon ( R . drawaЬle . ic_menu_save ) ;

menu . add (Meвu . NONE , I DM_EDIT , Menu . NONE , "Edi t " ) . setlcon ( R . drawaЬle . ic_menu_edit ) ;

menu . add (Menu . NONE , I DM_HELP, Menu . NONE , "Help " ) . setlcon ( R . drawaЬle . ic_menu_help) ;

menu . add (Menu . NONE , I DM_EXIT, Menu . NONE , "Exit " ) . seticon ( R . drawaЬle . ic_menu_ex i t ) ;

return ( supe r . onCreateOptionsMenu (menu ) ) ;

@ Override puЬlic boolean onOptions ltemSelected (Menul tem item)

CharSequence message ; swi tch ( i tem . g'

etltemld ( ) ) case I DM OPEN :

mes s age break ;

case I DM SAVE : mes s age break;

case I DM HELP : mes sage brea k ;

case I DM EDIT : mes s age brea k ;

case I DM EXIT : mes s age brea k ;

defaul t :

"Open item selected" ;

" Save item selected" ;

"Help item selected" ;

"Edit item selected" ;

"Exit item selected" ;

return fal s e ;

Toast toast Toast . makeText ( thi s , mes s age , Toast . LENGTH_SHORT ) ;

toast . setGravity ( Gravity . CENTER , О , 0 ) ; toast . show ( ) ; return t rue ;

Запустите проект на вы полнение. При нажатии клавиши <MENU> клавиату­ры эмулятора должно появиться меню из пяти пунктов, такое же, как в пре­дыдущем при мере, но уже со значками для каждого пункта меню (рис. 1 0.2).

Page 238: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

Меню 233

ii � Open Sa·.re

� � 0 Edit Exlt

Рис. 1 0.2 . Мен ю со знач ками

1 0 . 1 .2 . Расш и рен ное меню

Расширенное меню, как уже было сказано, появляется при количестве пунк­тов меню больше шести . Это меню добавляется автоматически системой Andro id при отображении меню на экране.

Для примера приложения с расширенным меню создайте новый проект и в диалоге Create New Project введите следующие значения :

D Project name - Opt ionsExpandedМenuApp;

D Application name - OptionsExpandedМenu Sample;

D Package name - с от . samples . opt ionsexpandedmenu;

D Create Activity - OptionsExpandedМenuActivity.

Файл разметки для расширенного меню оставьте таким же, как в предыду­щем примере (см. листинг 1 0 . 1 ) . Значки для пунктов меню возьм ите из пре­дьщущего примера, можно взять из прилагаемого к книге CD-ROM, в катало­ге Resources/Menu Icons/.

Для класса, реал изующего деятельность, возьмите код из предыдущего при­мера и добавьте в него три дополнительных идентификатора для пунктов меню:

private static final int I DM FIND REPLACE 1 0 6 ; private static fina1 int I DM FIND NEXT 1 0 7 ; private static fina1 int I DM FIND PREV = 1 0 8 ;

Page 239: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

234 Глава 1 0

В методе onCreateOpt ionsMenu ( ) добавьте новые пункты меню (теперь в меню будет восемь пунктов) :

puЬ1ic boo1ean onCreateOpt ionsMenu ( Menu menu )

menu . add (Menu . NONE , I DM_FIND_RE PLACE , Menu . NONE , " Find/Rep1ace " ) ;

menu . add (Menu . NONE , I DM_FIND_NEXT , Menu . NONE , " Find Next " ) ;

menu . add (Menu . NONE , I DM_FIND_PREV, Menu . NONE , " Find Previous " ) ;

return ( supe r . onCreateOptionsMenu (menu ) ) ;

ОБРА ТИТЕ ВНИМАНИЕ

Знач ки для доnол нительных nунктов меню не добавля ются , nоскольку они все равно не будут отображаться в nунктах расширенного меню.

Добавьте также в метод onOpt ions itemSe1ected ( ) обработку событий выбора новых пунктов меню. Полный код класса OptionsExpandedМenuActivity приве­ден в листин ге 1 0 .4 .

package com . samp1es . optionsexpandedmenu ;

import android . app . Activity;

import android . os . Bund1e ;

import android . view . Gravity;

import android . view . Menu;

import android . view . Menul tem;

import android . widget . Toast ;

puЬ1ic c1ass OptionsExpandedМenuActivity extends Act ivity

puЬlic static fina1 int I DM OPEN 1 0 1 ;

puЬlic stat ic puЬ1 ic static

puЬ1 ic stat ic

puЬl ic static

puЬlic static

puЬlic static

puЬ1 ic static

@Override

fina1 int I DM SAVE 1 0 2 ;

fina1 int I DM EDIT 1 0 3 ;

fina1 int I DM HELP 1 0 4 ;

fina1 int I DM EXIT 1 0 5 ;

fina1 int I DM FIND REPLACE 1 0 6 ;

fina1 int I DM FIND NEXT 1 0 7 ;

fina1 int I DM FIND PREV 1 0 8 ;

puЬ1 ic void onCreate ( Bund1e savedinstanceState )

supe r . onCreate ( savedlnstanceState ) ;

Page 240: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

Меню

setContentView ( R . layout . main ) ;

@Override puЬlic boolean onCreateOpt ionsMenu ( Menu menu )

1 1 пункты основного меню menu . add (Menu . NONE , I DM_OPEN , Menu . NONE , "Open" )

. set icon ( R . drawaЬle . ic_menu_open ) ; menu . add (Menu . NONE , I DM_SAVE , Menu . NONE , " Save " )

. set icon ( R . drawaЬle . ic_menu_save ) ; menu . add (Menu . NONE , I DM_EDIT , Menu . NONE , "Edi t " )

. set icon ( R . drawaЬle . ic_menu_edit ) ;

menu . add (Menu . NONE , I DM_HELP , Menu . NONE , "Help " ) . set icon ( R . drawaЬle . ic_menu_help) ;

menu . add (Menu . NONE , I DM_EXI T , Menu . NONE , "Exit " ) . set icon ( R . drawaЬle . ic_menu_exit ) ;

пункты расширенного меню . Значки не добавляем,

235

т . к . в_ расширенном меню они не отображаются menu . add (Menu . NONE , I DM_FIND_REPLACE , Menu . NONE , " Find/Replace " ) ; menu . add (Menu . NONE , I DM_FIND_NEXT , Menu . NONE , " Find Next " ) ; menu . add (Menu . NONE , I DM_FIND_PREV, Menu . NONE , " Find Previous " ) ;

return ( supe r . onCreateOpt ionsMenu (menu ) ) ;

@Override puЬlic boolean onOpt ionsitemSelected (Menuitem item)

CharSequence message ; switch ( item . get itemid ( ) )

case I DM OPEN : message "Open item selected" ; brea k ;

c a s e I DM SAVE :

mes s age " Save item selected" ; break ;

case I DM HELP : mes sage break;

case I DM EDIT : mes sage break;

case I DM EXIT : mes s age

break;

"Help item selected" ;

"Edit item selected" ;

"Exit item selected" ;

Page 241: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

236

ca s e I DM FIND REPLACE :

me s sage

brea k ;

" Find/Replace item selected " ;

case I DM FIND NEXT :

me s sage

brea k ;

" Find Next i t em s e lected " ;

ca s e I DM FIND PREV :

me s sage

break ;

de faul t :

" Find Previous i t em selected " ;

return fa l s e ;

Глава 1 0

Toa s t toas t Toa s t . ma keText ( th i s , me s sage , Toa s t . LENGTH SHORT ) ;

toas t . setGravity ( Gravity . CENTER , О , 0 ) ;

toa s t . show ( ) ;

return t rue ;

Запустите проект на выполнение. При нажатии клавиши <M ENU> клавиату­ры эмулятора должно появиться меню из пяти nунктов и дополн ительным пунктом More для расширенного меню. При выборе пункта More появится расширенное меню с допол н ительными пун ктами (рис . 1 0 .3 ) .

F i nd/Rep lace

• � 11 F ind N e xt Open sav� Edl t

о G> е F ind P revious Exlt Mor e

Рис. 1 0.3 . Расширенное меню

Page 242: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

Меню 237

1 0 .2 . Контекстное меню Контекетое меню в Aпdroid напоминает контекстное меню в настол ьных сис­темах, появляющееся при нажатии правой кнопки мыши . Меню вызывается при нажатии на объект в течение двух секунд (событие \oпg-press) .

ОБРА ТИТЕ ВНИМАНИЕ

Пун кты контекстного мен ю н е п омержива ют значки или быстрые клавиш и (со­четан ия клав иш) .

Для создания контекстного меню необходимо реализовать в классе деятел ь­ности метод обратного вызова меню oncreateContextMenu ( ) . В методе onCreateContextMenu ( ) можно добавить пункты меню, используя один из методов add ( ) и метод обратного вызова onContext i temSelected ( ) .

Код для создания контекстного меню может выглядеть следующим образом:

puЬlic void onCreateContextMenu ( ContextMenu menu, View v, ContextMenuinfo menuinfo )

super . onCreateContextMenu (menu , menuinfo ) ;

menu . add (Menu . NONE , I DM_OPEN , Menu . NONE , " Open" ) ; menu . add (Menu . NONE , I DM_SAVE , Menu . NONE , " Save " ) ;

При выборе пользователем пункта меню будет вызван метод onContextitemSelected ( ) , который необходимо определить в классе, реали­зующем деятельность. Этот метод обратного вызова передает в программу объект Menui tem - пункт меню, который был выбран пол ьзователем. Для об­работки события используются те же процедуры идентификации выбранного пун кта меню, что и в предыдущих примерах меню.

puЬlic boolean onContext itemSelected (Menuitem item) CharSequence message ; swi tch ( item . geti temid ( ) )

case I DM OPEN :

break ; case I DM SAVE :

break ;

de fault : return supe r . onContext itemSelected ( item) ;

Page 243: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

238 Глава 1 0

Для примера приложения с контекстны м меню создайте новый проект и в диал�ге Create New Project введите следующие значения :

D Project name - contextMenuApp;

D Application name - ContextMenu arnple;

D Package name - сот . sarnples . contextmenu;

D Create Activity - ContextMenuActivity.

Откройте файл разметки и создайте структуру разметки подобно листин­гу 1 0 . 5 .

< ?xml version= " l . O " encoding= " ut f-8 " ?>

<LinearLayout xmlns : android="http : / /schemas . android . com/apk/ re s / android"

android : id= " @ +id/Root "

android : orientation="vertica l "

android : layout_width= " fi l l_parent "

android : layout_height= " fi l l_parent "

android : gravity=" center " >

<TextView

android : layout_width= "wrap content "

android : layout_height="wrap_content "

android : text= " Long-press for cal l а ContextMenu" / >

< /LinearLayout>

В классе ContextMenuActi vity напишите код, как в листинге 1 0.6 .

package com . sarnples . contextmenu ;

import android . app . Activity;

import android . os . Bundle ;

import android . view . ContextMenu ;

import android . view . Gravit y ;

import android . view . Menu;

import android . view . Menuitem;

import android . view . View;

import android . view . ContextMenu . ContextMenuinfo ;

Page 244: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

Меню

import android . widget . LinearLayout ;

import android . widget . Toast ;

puЬlic class ContextMenuActivity extends Activity

puЬl ic static final int IDM OPEN 1 0 1 ;

puЬlic static final int I DM SAVE 102 ;

puЬlic static final int I DM EDIT 1 0 3 ; puЬlic static final int IDM HELP 104 ;

puЫ ic static final int I DM EXIT 1 0 5 ;

@ Override

puЫ ic void onCreate ( Bundle savedinstanceState )

super . onCreate ( savedinstanceState ) ;

setContentView ( R . layout . main ) ;

239

final LinearLayout edit ( LinearLayout ) findViewByid ( R . id . root ) ;

regi sterForContextMenu ( edit ) ;

@ Override

puЬlic void onCreateContextMenu ( ContextMenu menu, View v,

ContextMenuinfo menuinfo ) { super . onCreateContextMenu (menu , v, menuinfo ) ;

menu . add (Menu . NONE , I DM_OPEN , Menu . NONE , "Open" ) ;

menu . add (Menu . NONE , I DM_SAVE , Menu . NONE , " Save " ) ;

menu . add (Menu . NONE, I DM_EDIT, Menu . NONE , "Edit " ) ;

menu . add (Menu . NONE , I DM_HELP, Menu . NONE , "Help" ) ;

menu . add (Menu . NONE , IDM_EXI T , Menu . NONE , "Exit " ) ;

@ Override

puЬl i c boolean onContextitemSelected (Menuitem item)

CharSequence message ;

switch ( item . getitemid ( ) ) case I DM OPEN :

message

break ;

case I DM SAVE :

mes sage

break ;

case I DM HELP :

"Open item selected" ;

" Save i tem selected" ;

rnes sage = "Help item selected" ;

break ;

Page 245: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

240

case I DM EDIT :

mes sage

brea k ;

case I DM EXIT :

mes s age

break ;

default :

"Edit item selected" ;

"Ex i t item selected" ;

return super . onContext itemSelected ( item) ;

Глава 1 0

Toast toast Toast . ma keText ( thi s , message , Toast . LENGTH_SHORT ) ;

toast . setGravity (Gravi ty . CENTER, О , 0 ) ;

toast . show ( ) ;

return t rue ;

Заnустите nроект на выnолнение. Внешний вид nриложения с контекстным меню nо казан на рис . 1 0 .4 .

Edit

Hel p

Exit

Рис. 1 0.4. Пример контекстного меню

1 0.3 . Подмен ю Подменю можно добавить в любое меню, кроме другого nодменю. Они очень nолезны, когда ваше nриложение имеет много функций, которые должны

Page 246: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

Меню 24 1

быть организованы в разделы подобно пунктам в главном меню приложений для настольных систем (File, Edit, View и т . д . ) .

Подменю создается в методе обратного вызова onCreateOptionsMenu ( ) , опре­деляемого в классе деятел ьности . Подменю добавляется для уже существую­щего пун кта меню с помощью метода addSubMenu ( ) , который возвращает объект SubMenu. В объект SubMenu можно добавить дополнител ьные пункты к этому меню, испол ьзуя метод add ( ) . Например:

puЬlic boolean onCreateOptionsMenu (Menu menu )

SubMenu subMenuFi le menu . addSubMenu ( " Fi l e " ) ;

subMenuFi le . add (Menu . NONE , I DM_NEW , Menu . NONE , "New" ) ;

subMenuFi le . add (Menu . NONE , I DM_OPEN , Menu . NONE , "Open" ) ;

subMenuFi le . add (Menu . NONE , I DM_SAVE , Menu . NONE , " Save " ) ;

Для примера приложения с подменю создайте новый проект и в диалоге Create New Project введите следующие значения :

О Project name - suЬмenuApp;

О Application name - SubMenu Sample;

О Package name - com . samples . suЬmenu;

О Create Activity - SubMenuActivity.

Файл разметки для приложения будет аналогичен разметке, приведеи ной в листинге 1 0 . 1 В примере будет меню из трех пунктов : File, Edit и Help. Для первых двух пунктов определим подменю:

О File - New, Open, Save;

О Edit - Cut, Сору, Paste .

Полный код класса suЬмenuActivity представлен в листинге 1 0 .7 .

package com . samples . submenu ;

import android . app . Activity;

import android . os . Bundle ;

import android . view . Gravity;

import android . view . Menu ;

import android . view . Menuitem;

import android . view . SubMenu ;

import android . widget . Toas t ;

Page 247: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

242

puЬlic class SubMenuActivity extends Act ivity

puЬl ic static final int I DM HELP 1 0 1 ;

puЬlic static final int I DM NEW 2 0 1 ; puЬlic stat i c final int I DM OPEN 2 0 2 ; puЬlic static final int I DM SAVE 2 0 3 ;

puЬlic static fina l int I DM CUT 3 0 1 ; puЬlic static final int I DM СОРУ 302 ; puЬl ic static final int I DM PASTE 3 0 3 ;

@Override

puЬl i c void onCreate ( Bundle savedlnstanceState ) super . onCreate ( savedinstanceState ) ; setContentView ( R . layout . rnain ) ;

@Override puЬl ic boolean onCreateOptionsMenu ( Menu rnenu )

SuЬMenu suЬMenuFi le rnenu . addSuЬMenu ( " Fi le" ) ; suЬMenuFile . add (Menu . NONE , I DM_NEW , Menu . NONE , "New" ) ; suЬMenuFi le . add (Menu . NONE , I DM_OPEN , 'Menu . NONE , "Open" ) ; suЬMenuFi le . add (Menu . NONE , I DM_SAVE , Menu . NONE , " Save " ) ;

SuЬMenu suЬMenuEdit = rnenu . addSubMenu ( "Edit " ) ; suЬMenuEdit . add (Menu . NONE , I DM_CUT , Menu . NONE , "Cut " ) ;

suЬMenuEdit . add (Menu . NONE , I DM_COPY , Menu . NONE , " Сору" ) ; suЬMenuEdit . add (Menu . NONE , I DM_PASTE , Menu . NONE , "Paste " ) ;

rnenu . add (Menu . NONE, I DM_HELP, Menu . NONE , "Help" ) ;

return super . onCreateOpt ionsMenu (rnenu ) ;

@Override

puЬl i c boolean onOptions lternSelected (Menultern itern) CharSequence rnessage ; swi tch ( itern . getlternid ( ) )

case I DM NEW :

rnes sage break;

case I DM OPEN :

"New itern selected" ;

rnes sage = "Open itern selected" ; break;

Глава 1 0

Page 248: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

Меню

case I DM SAVE :

mes sage

brea k ;

c a s e I DM CUT :

mes s age

brea k ;

c a s e I DM СОРУ :

mes sage

brea k ;

" Save item selected " ;

" Cut i t em selected" ;

" Сору item selected " ;

case I DM PASTE :

mes sage

brea k ;

case I DM HELP :

mes sage

brea k ;

de faul t :

" Pa s t e i t em s e l ected" ;

"Help item s e l ected " ;

return fa l s e ;

вьrnодим уведомление о выбранном пункте меню

243

Toa s t toa s t Toas t . ma keText ( thi s , mes s age , Toas t . LENGTH_SHORT ) ;

toas t . s etGravi ty ( Gravity . CENTER , О , 0 ) ; toas t . show ( ) ;

return t rue ;

е ешt

C u t

Сору

Paste

Рис. 1 0.5 . Меню и его подменю в приложе н и и

Page 249: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

244 Глава 1 0

Запустите проект на выполнение. При нажатии клавиши <MENU> клавиату­ры эмулятора должно появиться меню из трех пун ктов . При выборе пункта File появится его подменю (рис. 1 0 .5) . Пункт меню Edit также имеет собст­венное подменю.

1 0 .4 . Добавле н ие флажков и первкл ючателей в мен ю Для расширения функционал ьности в пункты меню возможно добавление флажков ил и переключателей.

Чтобы добавить флажок для отдел ьного элемента меню, необходимо исполь­зовать метод setCheckaЫe ( )

Menui tern itern rnenu . add ( O , I DM_FORМAT_BOLD, О , "Bold" ) itern . setCheckaЬle ( t rue ) ;

Если есть необходимость добавить несколько пунктов меню с флажками или радиокнопками, целесообразно объединять их в группы меню.

Группа меню определяется идентификатором (целым числом) . Пункт меню можно добавить к группе, используя один из вариантов метода add ( ) , передав ему в качестве первого параметра идентификатор группы меню. Например. пусть в коде объявлены идентификаторы для группы меню Color и элементов меню для установки цвета:

puЫ ic static final int

puЫ ic static final int puЬlic static final int

puЬlic static final int

I DM COLOR GROUP - -

I DM COLOR RED - -

I DM COLOR GREEN - -

I DM COLOR BLUE - -

2 0 0 ; 2 0 1 ;

2 0 2 ;

2 0 3 ;

Тогда для создания группы меню с флажками необходимо назначить тот же самый идентификатор группы на каждый пункт меню и вызвать метод setGroupCheckaЬle ( ) для всей группы . В этом случае нет необходимости вы­зывать метод setCheckaЬle ( ) для каждого пункта меню:

SubMenu suЬMenuFi le rnenu . addSubMenu ( " Color" ) ;

suЬMenuFi le . add ( I DM_COLOR_GROUP, IDM_COLOR_RED, Menu . NONE , " Red" ) ; subMenuFi le . add ( IDM_COLOR_GROUP, IDM_COLOR_GREEN , Menu . NONE , "Green" ) ; subMenuFi le . add ( IDM_COLOR_GROUP, IDM_COLOR_BLUE , Menu . NONE , "Blue " ) ;

subMenuFi le . setGroupCheckaЬle ( IDM_COLOR_GROUP, true , false ) ;

В метод setGroupCheckaЬle ( ) передаются три параметра:

О первый - идентификатор группы меню;

О второй - t rue, если в группе разрешены переключатели или флажки;

Page 250: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

Меню 245

О третий - устанавливает единствен ный (true) или множественный ( false) выбор пунктов меню. Этот параметр фактически определяет внешний вид меню - это будет меню с радиокнопками ил и флажками .

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

puЬlic boolean onOpt ions i temSelected (Menuitem item)

switch ( item . getitemid ( ) )

case I DM COLOR RED :

1 1 инвертируем состояние флажка

item . setChecked ( ! item . i sChecked ( ) ) ;

break ;

Для примера использования групп меню в приложении создайте новый про­ект и в диалоге Create New Project введите следующие значения :

О Project name - CheckaЬleSubMenuApp;

О Application name - CheckaЬleSuЬMenu Sample;

О Package name - com . samples . checkaЬlesubmenu;

О Create Activity - CheckaЬleSubMenuActi vi ty.

Файл разметки main .xml используйте из листинга 1 0 . 1 . В приложении создай­те меню из трех пунктов : Color, Font Style, Help. Пункты Color и Font Style являются группам и меню. Для этих групп определим подменю:

О Color - Red, Green, Blue;

О Font Style - Regular, Bold, Italic.

Полный код класса CheckaЫeSuЬMenuActi vi ty представлен в листинге 1 0 . 8 .

package com . samples . checkaЫesuЬmenu ;

import android . app . Act ivity;

import android . os . Bundle ;

import android . view . Gravity;

import android . view . Menu ;

import andro id . view . Menui tem;

import android . view . SubMenu ;

import android . widget . Toast ;

Page 251: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

246 Глава 1 0

puЬlic class CheckaЬleSuЬMenuActivity extends Activity

puЬlic static final int I DM HELP 1 0 1 ;

puЬlic static final int I DM COLOR GROUP 2 0 0 ;

puЬlic static final int I DM COLOR RED 2 0 1 ;

puЬlic static final int I DM COLOR GREEN 2 02 ;

puЬl i c s tatic final int I DM COLOR BLUE 2 0 3 ;

puЬlic static final int I DM FONT GROUP 3 0 0 ;

puЬl ic static final int I DM REGULAR 3 0 1 ;

puЬlic static final int I DM BOLD 3 02 ;

puЬlic static final int I DM ITALIC 3 0 3 ;

@ Override

puЫ ic void onCreate ( Bundle savedins tanceState )

supe r . onCreate ( savedinstanceState ) ;

setContentView ( R . layout . main ) ;

@Override

puЬlic boolean onCreateOptionsMenu (Menu menu )

SuЬMenu suЬMenuFi le menu . addSuЬMenu ( "Color" ) ;

suЬMenuFi le . add ( IDM_COLOR_GROUP , I DM_COLOR_RED , Menu . NONE , "Red" ) ;

suЬMenuFile . add ( I DM_COLOR_GROUP, I DM_COLOR_GREEN , Menu . NONE ,

"Green " ) ;

suЬMenuFi le . add ( I.DM_COLOR_GROUP, IDM_COLOR_BLUE , Menu . NONE, "Blue" ) ;

suЬMenuFile . setGroupCheckaЬle ( I DM_COLOR_GROUP, t rue , false ) ;

SuЬMenu suЬMenuEdit menu . addSuЬMenu ( " Font Style " ) ;

suЬMenuEdi t . add ( I DM _ FONT _ GROUP I DM _ REGULAR, Menu . NONE , "Regular" )

. setChecked ( true ) ;

suЬMenuEdit . add ( IDM_FONT_GROUP I DM_BOLD, Menu . NONE , "Bold" ) ;

suЬMenuEdit . add ( I DM_FONT_GROUP I DM_ITAL�C , Menu . NONE , " I talic" ) ;

suЬMenuEdit . setGroupCheckaЬle ( IDM_FONT_GROUP t rue , t rue ) ;

menu . add (Menu . NONE , I DM_HELP, Menu . NONE , "Help" ) ;

return super . onCreateOpt ionsMenu (menu ) ;

Page 252: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

Меню

@Override

puЬlic boolean onOptionsitemSelected (Menuitem item)

CharSequence message ;

switch ( item . get itemid ( ) )

)

case I DM COLOR RED :

item . setChecked ( ! item . i sChecked ( ) ) ;

mes sage break ;

"Red item selected" ;

case I DM COLOR GREEN :

item . setChecked ( ! item . i sChecked ( ) ) ;

mes sage "Green item se lected" ;

break; case I DM COLOR BLUE :

item . setChecked ( ! item . i sChecked ( ) ) ;

mes sage

break ;

"Blue item selected" ;

case I DM REGu�q :

item . setChecked ( t rue ) ;

mes sage

brea k ;

"Regular item selected" ;

case I DM BOLD :

item . setChecked ( t rue ) ;

mes sage

break;

"Bold item selected" ;

case I DM ITALIC :

item. setChecked ( t rue ) ;

mes sage

break ;

case I DM HELP :

mes sage

break ;

default :

" Italic item selected" ;

"He lp item selected" ;

return fal s e ;

1 1 выводим уведомление о выбранном пункте меню

24 7

Toast toast Toast . makeText ( thi s , message , Toas t . LENGTH_SHORT ) ;

toas t . setGravity ( Gravity . CENTER, О , 0 ) ;

toast . show ( ) ;

return t rue ;

Запустите проект на выпол нение. При нажатии клавиши <M ENU> клавиату­ры эмулятора на экране должно появиться меню из трех пунктов . При выборе

Page 253: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

248 Глава 1 0

пункта Color появится его подменю выбора цвета с флажками, а для Foпt Style - подменю с радиокнопкам и . Состояние флажков и радиокнопок обра­батывается в коде программ ы и сохраняется при повторных вызовах меню.

Внешний вид приложен ия показан на рис . 1 0 .6 .

Red Regu l a r

Gree r1 Bo ld

B l u e Ita l i c

Рис. 1 0.6 . Группы подменю с флажкам и и рад иокнопками

Page 254: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

Г Л А В А 1 1

Уп равлен ие деятел ьностя м и

В предыдущих главах все приложения состоял и из одной деятел ьности . Реальные приложения, как правило, имеют несколько окон . Они состоят из нескольких деятел ьностей, которыми надо уметь управлять и которые могут взаимодействовать между собой .

Как правило, одна из деятельностей приложения (окно которой открывается при запуске приложения) помечена как главная . Также из текущей деятел ь­ности можно запустить другую деятельность, даже если она определена в другом приложении . Пользователю будет казаться, что все запускаемые им деятельности я вляются частями одного приложения, хотя на самом деле они могут быть определены в разных приложениях и работают в разных про­цессах.

1 1 . 1 . Жизнен н ы й ци кл деятел ьности Деятельности имеют жизненный цикл - начало, когда Aпdroid создает эк­земпляр деятел ьности, промежуточное состояние, и конец, когда экземпляр уничтожается системой и освобождает ресурсы . Деятел ьность может нахо­диться в трех состояниях:

О активная (active wru running) - деятельность находится на переднем пла� не экрана. Это деятельность, которая является центром для интерактивно­го взаимодействия с пользователем ;

О прuостаиовлеиная (paused) - деятельность потеряла фокус, но все еще видима пользователю. То есть другая деятел ьность находится сверху и частично перекрывает данную деятельность . Приостановленная деятель­ность может быть уничтожена системой в критических ситуациях при не­хватке памяти;

О остановлеиная (stopped) - есл и данная деятел ьность полностью закрыта другой деятельностью. Она больше не видима пользователю и может быть

Page 255: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

250 Глава 1 1

уничтожена системой, если память необходима для другого, более важно­го процесса.

Если деятельность, которая была уничтожена системой, снова нужно отобра­зить на экране, она должна быть полностью перезапущена и восстановлена в своем предыдущем состоянии .

При переходе деятел ьности от одного состояния к другому, она получает уведомления через защищенные методы :

CJ protected void onCreate ( Bundle savedinstanceState ) ;

CJ protected void onStart ( ) ;

[J protected void onRes tart ( ) ;

[J protected void onResume ( ) ;

[J protected void onPaus e ( ) ;

[J protected void onStop ( ) ;

[J protected void onDest roy ( ) .

Эти методы - обработчики событи й изменения состояния деятел ьности, ко­торые можно реализовать в вашем классе деятельности, чтобы выпол н ить определенные действия при изменении состояния .

И з перечисленных методов обязательным в вашем классе деятельности явля­ется метод onCreate ( ) , чтобы задать начальную установку параметров при инициализации деятел ьности . Таюке часто надо реализовы вать метод onPause ( ) , чтобы сохранить пол ьзовательские настройки деятел ьности и под­готовиться к пре�ращению взаимодействия с пользователем.

При реализации любого из этих методов необходимо всегда сначала вызы­вать версию этого метода из суперкласса. Например:

protected void onPause ( )

super . onPause ( ) ;

Эти семь перечисленных методов определяют весь жизненный цикл деятел ь­ности . Есть три вложенных цикла, которые вы можете отслеживать в классе деятел ьности :

CJ полтюе время :жизни (enti1·e lifetime) - время с момента первого вызова метода onCreate ( ) др вызова onDestroy ( ) . Деятельность делает всю на­чальную установку своего глобал ьного состоя ния в. методе onCreate ( ) и освобождает все остающиеся ресурсы в onDestroy ( ) . Например, если дея­тельность порождает допол �ительный поток, вы полняющийся в фоновом

Page 256: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

Управление деятельностями 251

режиме, можно создать этот поток в методе onCreate ( ) и затем остановить пото� в методе onDest roy ( ) ;

D видимое время жизни (visiЬ/e lifetime) - время между вызовом метода onstart ( ) и вызовом onStop ( ) . В это время пользователь может видеть ок­но деятел ьности на экране, хотя окно может не быть на переднем плане и может не взаимодействовать с пользователем . Между этими двумя ме­тодами вы можете поддерживать в коде ресурсы, которые необходимы, чтобы отображать деятельность пол ьзователю;

D активное время жизни (foregroиnd lifetime) - время между вызовом onResume ( ) и вызовом onPause ( ) . В это время окно деятельности находится на переднем плане и взаимодействует с пользователем . Деятельность в процессе работы приложения может часто переходить между состояниями active и paиsed, поэтому код в этих двух методах должен быть или не­большим по объему (чтобы не замедлять работу приложения во время вы­полнения), или порождать дополнительные потоки, если требуется выпол­нение задач , занимающих длительное время .

Рисунок 1 1 . 1 демонстрирует цикл ы и пути, которые деятельность проходит при смене своего состояния . Главные состояния , в которых деятельность мо­жет находиться, изображены в четырехугольниках с закругленными сторона­ми . Прямоугол ьники представляют методы обратного вызова, которые вы можете реализовать в коде класса деятельности, чтобы выпол н ить необходи­м ые операции, когда деятельность переходит между состояниями .

Следующий список описывает каждый из этих методов более подробно и оп­ределяет местонахождение методов в пределах полного жизненного цикла деятел ьности :

D onCreate ( ) - в ызывается при создании деятел ьности . Внутри этого мето­да настраивают статический интерфейс деятел ьности - создают пред­ставления, связывают данные со спискам и и т. д. Этот метод принимает один параметр - объект вundle, содержащий предыдущее состояние дея­тел ьности (если это состояние было сохранено);

D onRestart ( ) - вызы вается после того, как деятел ьность была остановлена и снова была запущена пользователем. Всегда сопровождается вызовом метода onStart ( ) ;

D onStart ( ) - вызы вается непосредственно перед тем , как деятельность становится видимой пользователю. Сопровождается вызовом метода onResume ( ) , если деятельность получает передний план, или вызовом ме­тода onstop ( ) , есл и становится скрытой;

D onResume ( ) - вызывается непосредственно перед тем , как деятел ьность начинает взаимодействие с пол ьзователем . Всегда сопровождается вызо­вом метода onPause ( ) ;

Page 257: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

252

Пользователь закрывает деятельность кнопкой "Back" с-. ___ __L ___ -,

Другим Приложениям требуется память

Другая деятельность получает передний план

1

Деятельность долгое время не видима

oпRestart()

Деятельность возвращает

передний план

Деятельность возвращает

передний план

Рис. 1 1 . 1 . Жизнен н ы й цикл деятельности

Глава 1 1

О onPause ( ) - вызывается, когда система собирается запустить другую дея­тельность. Обычно этот метод испол ьзуется, чтобы передать несохранен­н ые изменения на сохранение и остановить выполнение задач, требующих ресурсов центрального процессара и не нужных nосле nриостановки дея­тел ьности . Соnровождает любой метод onResume ( ) , если деятельность воз­вращается снова на nередний nлан, или метод onstop ( J , есл и окно дея­тельности становится невидимым для nол ьзователя ;

Page 258: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

Управление деятельностями 253

О onStop ( ) - вызывается , когда окно деятельности становится невидимым для пользователя . Это может произойти при ее уничтожении, или если была запущена другая деятельность (существующая ил и новая), пере­крывшая окно текущей деятельности . Всегда сопровождает любой вызов метода onRestart ( ) , если деятел ьность возвращается, чтобы взаимодейст­вовать с пользователем, или метода onDestroy ( ) , если эта деятел ьность уничтожается;

О onDestroy ( ) - вызывается перед уничтожением деятельности . Это - по­следний запрос, который получает деятел ьность от системы . Этот метод вызывается по окончании работы деятельности, при вызове метода finish ( ) ил и в случае, когда система разрушает этот экземпляр деятельно­сти для освобождения ресурсов . Эти два сценария уничтожения можно определ ить вызовом метода is Fini shing ( ) .

В трех последних случаях система может уничтожить деятел ьность, чтобы освободить ресурсы для других процессов .

1 1 . 1 . 1 . Сохранение состоя н ия деятел ьности

Когда система завершает деятел ьность в nринудител ьном nорядке, чтобы освободить ресурсы для других приложений, пользовател ь может снова вы­звать эту деятел ьность с сохраненны м предыдущим состоянием.

Чтобы зафиксировать состояние деятел ьности перед ее уничтожением, в классе деятельности необходимо реализовать метод onSaveinstanceState ( ) . Android вызывает этот метод перед созданием деятел ьности, т. е . раньше вы­зова onPause ( ) .

Система nередает методу объект вundle, в который можно записать парамет­ры, динамическое состояние деятельности как пары имя-значение. Когда дея­тельность будет снова вызвана, объект вundle передается системой в качестве параметра в метод onCreate ( ) и в метод onRestore instanceState ( ) , который вызывается nосле onstart ( ) , чтобы один из них ил и они оба могли устано­вить деятельность в предыдущее состояние.

В отличие от метода onPause ( ) и других методов, рассмотренных ранее, ме­тоды onSave ins tanceState ( ) и onRestoreinstanceState ( ) не относятся к мето­дам жизненного цикла деятел ьности . Система будет вызы вать их не во всех случаях. Например, Android вызывает onSaveinstanceState ( ) прежде, чем деятел ьность становится уязвимой к уничтожению системой, но не вызывает его, когда экземпляр деятел ьности разрушается пользовател ьским действием (при нажатии клавиши <ВАСК>) . В этом случае нет никаких причин для со­хранения состояния деятельности .

Page 259: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

254 Глава 1 1

Поскольку метод onSaveinstanceState ( ) вызывается н е во всех случаях, его необходимо использовать тол ько для сохранения промежуточного состояния деятельности . Для сохранения данных лучше использовать метод onPause ( ) .

1 1 . 1 .2 . Стек деятел ьностей

Когда одна деятел ьность запускает другую, новая деятел ьность помещается в стек и становится активной деятел ьностью. Предыдущая деятел ьность остается в стеке. Когда пользовател ь нажимает клавишу <ВАСК>, текущая деятел ьность выталкивается из стека, и ее замещает предыдущая деятель­ность, которая снова отображается на экране.

Стек с находящим ися в нем деятел ьностя ми называется заданием . Все дея­тельности в задании перемешаются вместе, как один модуль . Все задание (весь стек деятел ьностей приложения) может находиться на переднем плане ил и в фоне.

Стек содержит объекты, и если задание имеет бол ьше одного открытого экземпляра того же самого подкласса Activity, стек имеет отдел ьный вход для каждого экземпляра. Деятел ьности в стеке никогда не перестраиваются, тол ько помещаются и вытал киваются. Если пользовател ь оставляет задание в течение долгого времени, система очищает задание от всех деятельностей, кроме корневой деятельности.

1 1 .2 . Намерен ия Новые деятельности (а также службы и прием ники широковещател ьных на­мерен ий, о которых будет рассказано позже) запускаются через сообщения, назы ваемые намерениями . Намерения - средство для позднего связывания во время выпол нения между компонентами одного или нескол ьких прило­жений .

Непосредственно намерение, объект Intent, является пассивной структу­рой данных, содержащей абстрактное описание выполняемой операции . Объект Intent передают в метод Context . startActi vi ty ( ) или в метод Acti vi ty . startActi vi tyForResul t ( ) , чтобы запустить деятел ьность или заста­вить существующую деятельность делать что-нибудь новое. Объект Intent

можно также передать в метод Act i vi ty . setResul t ( ) , чтобы возвратить информацию деятельности, которая была вызвана через метод startActivi tyForResult ( ) .

В каждом случае система Andro id находит соответствующую деятельность, чтобы ответить на намерение, инициализируя ее в случае необходимости .

Page 260: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

Управление деятельностями 255

Объект Intent - связка информации . Он содержит информацию, представ­ляющую и нтерес для ком понента, который получает намерение, и дан ные, которые передаются этому ком поненту. Кроме того, объект Intent содержит информацию, представляющую интерес для системы Aпdroid , - имя компо­нента, который должен обработать намерение и набор параметров запуска этого компонента. Как правило, объект Intent может содержать следующие поля :

О имя компонента. Имя компонента, который должен обработать намере­ние. Это поле - объект ComponentNarne - комбинация полного имени класса целевого компонента (например, "MainAct ivity" ) и набор имени па­кета в файле манифеста приложения, где компонент постоянно находится (например, " com . sarnples . application" ) . Составляющее имя является до­полнительным . Если оно установлено, объект Intent поставляют образцу определяемого класса. Если имя не установлено, Aпdroid использует дру­гую информацию в объекте Intent, чтобы определ ить местонахождение подходящего адресата. Составляющее имя устанавливается методами setComponent ( ) , setClass ( ) или setClas sNarne ( ) и читается методом getComponent ( ) ;

О действие. Это действие, которое будет выполнено. Класс Intent определя­ет м ножество констант действия, например:

• ACTION _ CALL - инициализирует обращение по телефону;

• ACT ION _ EDIT - отображает данные для редактирован ия пользователем;

• ACT ION_МAIN - запускается как начал ьная деятельность задания, без ввода дан ных и без возвращаемого значения;

• ACT ION _ SYNC - синхронизирует данные сервера с данными мобильного устройства.

Действие в значительной степени определяет, как остальная часть намерения структурирована, особенно данные и поля возвращаемых значений , посколь­ку название метода определяет ряд параметров и возвращаемого значения . Вы можете также определ ить ваши собственные действия для активизации деятельности . Те, которых определяете сами, должн ы включать имя пакета приложения в качестве префикса,. например com . sarnples . proj ect . сusтом _

ACT ION. Действие в объекте Intent устанавливается в методе setAction ( ) и читается методом getAction ( ) ;

О данuые. Это URI данн ых и тип M I M E для этих данных. Разные деятел ьно­сти соеди нены с разными видами спецификаций данных . Работа с полями данных будет рассмотрена в главе 15;

О категория . Это строка, содержащая дополнительную информацию о виде компонента, которы й должен обработать намерение. В объект Intent мо-

Page 261: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

256 Глава 1 1

жет быть помещено любое количество описаний категорий . Класс Intent

определяет несколько констант CATEGORY, например:

• CATEGORY_BROWSAВLE - целевая деятельность может быть безопасно вы­звана браузером , чтобы отобразить ссылочные данные, например изо­бражение или почтовое сообщение;

• CATEGORY _ номЕ - деятельность отображает Ноте Screen, первый экран, который пол ьзователь видит после включения устройства и загрузки системы, или когда нажимает клавишу <НОМ Е>;

• CATEGORY _ LAUNCHER - деятельность может быть начальной деятель­ностью задания из списка приложений в группе Application Launcher устройства (это выдвижная паиел ь с установленными на устройстве приложениями) .

Для работы с категориями в классе Intent определена группа методов :

• addCategory ( ) - помещает категорию в объект Intent;

• removeCategory ( ) - удаляет категорию, которая была добавлена ранее;

• getCategories ( ) - получает набор всех категорий, находящихся в настоящее время в объекте Intent;

D дополнения. Это пары ключ-значения для дополнител ьной информации, которую нужно поставить компоненту, обращающемуся с намерением. Например, действие ACTION _ TIMEZONE_ CНANGED имеет дополнение time-zone,

которое идентифицирует новый часовой пояс, ACTION_HEADSET_PLUG имеет дополнен ие s tate, указывающее, включены ли наушники или откл ючены, а также дополнение name для типа наушников. Объект Intent имеет ряд методов put • • • ( ) для вставки различных типов дополнительных данных и подобного набора методов get . ( ) для чтения данных. Допол нения уста­навливаются и читаются как объекты вundle с испол ьзованием методов putExtras ( ) И getExtras ( ) ;

D флаги. Флаги указывают системе, как запускать деятельность (например, какому заданию должна принадлежать деятельность) и как обработать это после того, как деятельность запустили (например, принадлежит л и она списку недавних деятельностей) . Все эти флаги определены в классе Intent .

Система Android и приложения, кQторые идут в комплекте с платформой, таюке испол ьзуют объекты Intent для активизации определенных системой компонентов (например, различных приложений и служб при загрузке сис­темы) .

Page 262: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

Управление деятельностями 257

1 1 .3 . Груп п ы намерени й Намерения могут быть разделены на две группы:

О явные на'Иерения - определяют целевой компонент по имени (состав­ляющее поле имени, упомянутое ранее, имеет набор значения);

О неявпые иаиереиия - не называют адресата (поле для составляющего имени - пробел) . Неявные намерения часто используются, чтобы активи­зировать компоненты в других приложениях.

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

Неявные намерения используют для запуска ком понентов других приложе­ний . В файле манифеста приложений декларируется фильтр намерений (ко­торы й описывается далее в разд. 1 1 . 5) . В отсутствие оnределяемого адресата система Andюid просматривает фильтры намерений всех приложений и на­ходит компонент (деятельность, службу или приемник широковещательных намерений), фильтр намерений которого я вляется наиболее подходящим для выполнения данного неявного намерения .

1 1 .4 . За пуск деятел ьностей и обмен да н н ы м и между деятел ьностя м и Чтобы запустить новую деятельность, которая будет помещена наверху стека деятельности, используется, как уже говорилось, метод startActi vi ty ( Intent ) . Этот метод принимает единственный параметр ­объект rntent, описывающий деятельность, которая будет запускаться .

Иногда требуется вернуть результат деятельности, когда она закры вается. Например, можно запустить деятельность, которая позволяет пользователю выбирать человека в списке контактов. При закрытии деятельность возвра­щает данные человека, который был выбран : его полное имя и телефон . Что­бы сделать это, необходимо вызвать метод s tartActivityForResult ( Intent ,

int ) со вторым параметром, идентифицирующим запрос . Результат возвра­щается через метод обратного вызова onAct ivityResult ( int , int , Intent ) ,

определенный в родительской деятельности.

1 1 идентификатор запроса

private static final int IDM ADD 1 0 1 ;

Intent intent = new Intent ( ) ;

Page 263: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

258

определение класса запускаемой деятельности

intent . setClas s ( this , NewContactActivity . class ) ;

1 / вызов деятельности

sta rtActivityForResult ( intent , I DM_NEW ) ;

Глава 1 1

Когда деятельность завершится, она может вызвать метод setResult ( int ) ,

чтобы возвратить данные назад в родительскую деятельность . Этот метод возвращает код результата закрытия деятельности, которы й может быть стандартными результатами RESULT _ CANCELED, RESULT _ ок или определяемым пользователем результатом RESULT FIRST USER.

private EditText mName ;

private EditText mPhone ;

Intent intent new Intent ( ) ;

1 1 вставляем имя человека

intent . putExtra ( ContactLis.tActi vi ty . NАМЕ , mName . getText ( ) . toString ( ) ) ;

вставляем телефон intent . putExtra ( ContactListActivity . PHONE,

mPhone . getText ( ) . toString ( ) ) ;

возвращаем результат в вызывающую деятельность

setResul t ( RESULT_OK , intent ) ;

finish ( ) ;

Кроме того, дочерняя деятельность может произвольно возвратить назад объ­ект Intent, содержащий любые дополнительные данные. Вся эта информация в родительской деятельности появляется через метод обратного вызова Act i vity . onActi vityResult ( ) , наряду с идентификатором, который она перво­начал ьно предоставила:

protected void onActivityResult (

int requestCode , int resultCode , Intent data ) {

super . onActivityResult ( reques tCode , resultCode , data ) ;

i f ( resultCode RESULT_OK)

Bundle extras data . getExtras ( ) ;

switch ( requestCode ) case I DM ADD :

String name extras . getString ( Contactitem . NAМE ) ,

String phone extras . getSt ring ( Contactitem . PHONE ) ) ) ;

brea k ;

Page 264: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

Управление деятельностями 259

Если дочерняя деятельность завершится неудачно или будет закрыта пользо­вателем без подтверждения ввода, то родительская деятельность получит ре­зультат С КОДОМ RESULT _ CANCELED.

Реализуем все это в практическом приложении . Создайте в Ecl ipse новый проект и в окне Create New Project введите следующие значения :

D Project name - ContactEdi tor;

D Application name - Contacts Sample;

D Package name - с от . samples . contactedi tor;

D Create Activity - ListContactAct ivity.

Приложение будет представлять собой список контактов, который можно редактировать: добавлять новые контакты, вносить изменения и удалять не­нужные контакты . За основу возьмем созданное в разд. 7. 5 приложение, ото­бражающее список контактов .

В приложении будут три деятельности :

D ContactListActivity - главное окно со списком контактов и меню для редактирования;

D NewContactActivity - окно добавления нового контакта;

D EditContactActivity - окно редактирования контакта.

В файле манифеста необходимо будет добавить помимо главной деятельно­сти еще и NewContactActivity и Edi tContactAct ivity, как показано в листин­ге 1 1 . 1 . Для этих деятел ьностей фильтры намерений не требуются, устанав­ливаются только атрибуты android : name и android : label .

< ?xml version= " . 0 " encoding= "ut f-8 " ?> <man i fest xmlns : android="http : / /schemas . android . com/apk/res /android"

package= " com . samples . contacteditor "

android : versionCode=" l "

android : ve rsionName= " l . O " > <appl ication

android : icon= " @ drawaЬle/icon "

android : label= " @ s t ring/app_name " > <act ivity android : name= " . Lis tContactActivity"

android : label= " @ s tring/app_name " >

Page 265: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

260 Глава 1 1

<intent-fi lter>

<action android : narne=" android . intent . action . МAIN"

<category android : narne="android . intent . category . lAUNCНER"

</ intent- filter>

</activity>

<activity android : narne=" . NewContactActivity"

android : label=" @ st �ing/title_add">

< /activity>

<activity

android : narne=" . EditContactActivity"

android : label= " @ string/title_edi t " >

< /activity>

</appl ication>

<uses-sdk android : minSdkVersion= " З "

< /mani fest>

Файл разметки main .xml будет такой же, как в листинге 7 . 1 9 из разд. 7. 5 . Просто скопируйте его в новый проект.

Поскольку в приложении будет довольно много виджетов с надписями , упо­рядочим строкавые ресурсы, поместим их в файл res/values/strings.xm l , кото­рый представлен в листинге 1 1 .2 . Кроме того, этот файл нам пригодится в разработке локализованного приложения в главе 16.

< ?xrnl version= " . 0 " encoding="ut f-8 " ?>

<resources> <string narne=" app_narne " >Contacts sarnple</string> <string narne="btn_create" >Create</string>

<string narne="btn_save ">Save</string>

<string narne="btn_cancel " >Cancel</string>

<st ring narne=" field_narne " >Narne : </string>

<string narne=" field_phone " >Phone : < / string>

<string narne=" t itle_add" >Add new Contact</string>

<string narne= " title_edit " >Edit Contact</string> <string narne=" t itle delete">Delete this Contact ?</st ring> <string narne="menu_add" >Add< / s t ring> <string narne="menu_edit " >Edit</ string>

<string narne="menu_delete " > Delete< /string>

<st ring narne=" toast_notify">Please select Contact ! </string>

< / resources>

Page 266: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

Управпение деятельностями 261

Для деятел ьностей NewContactActivity и EditContactActivity необходим свой файл разметки, в котором будут текстовые nоля для ввода или редактирова­ния контактных данных и две командные кноnки для nодтверждения или отмены ввода. Эти деятельности будут исnользовать общий файл разметки, изменяя только соответствующие надnиси на кноnках.

Код файла разметки nредставлен в листинге 1 1 .3 .

< ?xml version= " . 0 " encoding= " utf-8 " ?>

<LinearLayout xmlns : android=" http : / / schemas . android . com/apk/res/android"

android : layout_height="wrap_content "

android : layout_width= " fi l l_parent "

android : orientation="vertica l " >

<LinearLayout

android : layout_height="wrap_content "

android : layout_width=" fill_parent "

android : orientation= " hori zontal "

android : padding= " l Opx " >

<TextView

android : layout_width= "wrap content "

android : layout_height="wrap_content "

and.roid : text= " @ st ring/ field _ name "

android : paddingRight= " l Opx " / >

<EditText

android : layout_height="wrap_content"

android : layout_width= " fi l l_parent "

android : id=" @ +id/edit name " />

< /LinearLayout>

<LinearLayout

android : layout_height= "wrap content "

android : layout_width= " fi l l_parent "

android : orientation= " horizontal "

android : padding= " l Opx " >

<TextView

androi d : layout_width= "wrap content "

android : layout_height= "wrap_content"

android : text= " @ st ring/field_phone " />

Page 267: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

262

<EditText

android : layout_height="wrap_content"

android : layout_width= " fi l l_parent "

android : id= " @ + id/edit_phone " />

< /LinearLayout>

<LinearLayout

android : layout_height= "wrap_content "

android : layout_width= " fi l l_parent "

android : orientation= " hori zontal "

android : padding= " l Opx " >

<Button

androi d : layout_height="wrap content "

android : layout_width= " fill_parent "

android : layout_weight="

android : id= " @ +id/button save " / >

<Button

android : layout_height="wrap_content "

android : layout_width= " fill_parent "

android : layout_weight= " l "

android : text= " @ s t ring/btn_cancel "

android : id=" @ +id/button cancel " / >

< / Linea rLayout>

</LinearLayout>

Глава 1 1

Сnисок контактов будет создаваться nрямо в коде, как в главе 7 ( в главе 15 м ы рассмотрим "нормальные" сnособы сохранения и выборки данн ых, в на­стоящем nриложении это не актуал ьно). Мы немного усовершенствуем класс contactitem, добавив в него методы для чтения и редактирования nолей класса.

О Код класса Contacti tem nредставлен в листинге 1 1 .4 .

package com . samples . contacteditor ;

import j ava . ut i l . HashМap ;

puЬlic class Contact item extends HashМap<St ring , St ring>

private static final long serialVersionUI D l L ;

puЬlic static final String NАМЕ "name " ;

puЬlic static final String PHONE = "phone " ;

Page 268: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

Управление деятельностями

puЬlic Contacti tem ( String nате , String phone )

super ( ) ;

super . put (NAМE , nате ) ;

super . put ( PHONE, phone ) ;

puЬlic String getNaтe ( ) {

return super . get (NAМE ) ;

puЬlic String getPhone ( ) {

return super . get ( PHONE ) ;

puЬl ic void setNaтe ( String nате )

super . put (NAМE , nате ) ;

puЬlic void set Phone ( String phone )

super . put (NAМE , phone ) ;

263

В классе главной деятельности ContactListActivity будет отображаться ели­сок контактов и меню вызова дочерних деятельностей для добавления нового или модификации существующего контакта.

Полный код класса contactListAct ivity nредставлен в листинге 1 1 . 5 .

package com . saтples . contacteditor ;

import j ava . util . ArrayList ;

import android . app . Ale rtDialog ;

import android . app . ListActivity;

import android . content . Dialoginterface ;

import android . content . Intent ;

import android . os . Bundle ;

import android . view . Menu ;

import android . view . Menuitem;

import android . widget . ListAdapter ;

import android . widget . SimpleAdapter ;

import android . widget . Toast ;

Page 269: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

264 Глава 1 1

puЬ1ic c1ass ListContactActivity extends ListActivity

private static fina1 int I DM ADD 1 0 1 ;

private static fina1 int I DM EDIT 102 ; private static fina1 int I DM DELETE 1 0 3 ;

private 1ong mid - 1 ;

ArrayLi st<Contact i tern> mLi st ;

private ListAdapter mAdapte r ;

@ Override

puЬ1ic void onCreate ( Bund1e savedinstanceState )

super . onCreate ( savedinstanceState ) ;

mList new ArrayList<Contacti tem> ( ) ;

1 1 заполняем список контактов тестовь� значениями

fillContacts ( ) ;

updateLi st ( ) ;

private void updateList ( ) {

mAdapter new S imp1eAdapter ( this , mList , R . 1ayout . main,

new String [ ] { Contact item . NAМE , Contacti tem . PHONE } ,

new int [ ] { R . id . name , R . id . phone } ) ;

setListAdapte r (mAdapter ) ;

@ Override

puЫ ic boo1ean onCreateOptionsMenu ( Menu menu)

menu . add (Menu . NONE , I DM_ADD , Menu . NONE , R . string . menu_add)

. seticon ( R . drawaЬle . ic_menu_add )

. setA1phabeticShortcut ( ' a ' ) ; menu . add (Menu . NONE , I DM_EDIT , Menu . NONE , R . string . menu_edi t )

. seticon ( R . drawaЬle . ic_menu_edi t )

. setA1phabeticShortcut ( ' e ' ) ; menu . add ( Menu . NONE , I DM_DELETE , Menu . NONE , R . string . menu_de1ete )

. seticon ( R . drawaЬle . ic_menu_de1ete )

. setA1phabeticShortcut ( ' d ' ) ;

return ( supe r . onCreateOptionsMenu (menu ) ) ;

@Override

puЬli c boo1ean onOptions i temSe1ected (Menui tem item) {

mid = this . getSe1ecteditemid ( ) ;

Page 270: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

Управпение деятепьностями

switch ( item . get itemid ( ) ) case I DM_ADD : {

Intent intent new Intent ( ) ; intent . setClass ( this , NewContactActivity . class ) ; 1 1 запускаем деятельность startActivityForResult ( intent , I DM_ADD ) ;

break ; case I DM EDIT :

if (mid >= 0 ) Contactitem mitem = mList . get ( ( int ) mid) ;

265

Intent intent new Intent ( ) ; intent . putExtra ( Contactitem . NAМE , mi tem . getName ( ) ) ; intent . putExtra ( Contact item . PHONE , mitem . getPhone ( ) ) ;

intent . setClass ( this , EditContactActivity . class ) ; 1 1 запускаем деятельность startActivityForResult ( intent , I DM_EDIT ) ;

else Toast . makeText (

break ;

this , R . string . toast_notify, Toast . LENGTH_SHORT ) . show ( ) ;

case I DM DELETE : if (mid >= 0 )

AlertDialog . Builder bui lder new AlertDialog . Builder ( this ) ;

Contact item mitem = mList . get ( ( int ) mid) ; builder . setMessage ( R . st ring . t itle_delete + " \n "

+ mi tem . getName ( ) + " \n " + mitem . getPhone ( ) ) ;

builde r . setPosi t iveButton ( "Yes " , new Dialoginterface . OnCl ickListener ( )

puЬl ic void onClick ( Dialoginterface dialog, int id) mList . remove ( ( int ) mid ) ; updateLi st ( ) ;

} ) ; builder . setNegat iveButton (

"No " , new Dialoginterface . OnCl ickLis tene r ( ) puЬlic void onClick ( Dialoginterface dialog, int id)

dialog . cancel ( ) ;

}

Page 271: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

266

e1se

bui1der . setCance1aЬle ( fa1se ) ;

bui 1der . show ( ) ;

Toast . makeText ( this , R . string . toast_not i fy ,

Toast . LENGTH SHORT )

. show ( ) ;

updateList ( ) ;

break ;

return ( super . onOptions itemSe 1ected ( item) ) ;

protected void onActivityResu1t (

int requestCode , int resu1tCode , Intent data )

super . onActivityResu1t ( requestCode , resu1tCode , data ) ;

i f ( resu1tCode RESULT_OK )

Bund1e extras data . getExt ras ( ) ;

switch ( requestCode )

case I DM ADD :

mList . add ( new Contacti tem ( ext ras . getString ( Contact item . NAМE ) ,

ext ras . getString ( Contactitem . PHONE ) ) ) ;

break;

case I DM EDIT :

mList . set ( ( int ) mid, new Contactitem (

extras . getString ( Contacti tem . NAМE ) ,

extras . getString ( Contactitem . PHONE ) ) ) ;

break;

updateLi st ( ) ;

puЬl ic void fi1 1Contacts ( )

Глава 1 1

mList . add ( new Contacti tem ( " Jacob Anderson " , " 4 12 4 12 4 1 1 " ) ) ; mList . add ( new Contacti tem ( "Emi1y Duncan" , " 1 61 8 63 1 8 7 " ) ) ;

mList . add ( new Contact i tem ( "Michae1 Ful ler " , " 8 9 6 4 4 3 65 8 " ) ) ;

mList . add ( new Contacti tem ( "Emma Greenman" , " 9 64 9 9 0 5 4 3 " ) ) ;

mList . add ( new Contacti tem ( " Joshua Harrison" , " 7 5 92 8 5 0 8 6 " ) ) ;

mList . add ( new Contacti tem ( "Madison Johnson " , " 95 0 2 8 5 7 7 7 " ) ) ;

Page 272: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

Управление деятельностями

rnList . add ( new Contact itern ( "Matthew Cotrnan" , " 68 7 6 9 9 9 9 9 " ) ) ;

rnList . add ( new Contact i tern ( "Olivia Lawson" , " 1 61 8 6 3 1 8 7 " ) ) ;

rnList . add ( new Contactitern ( "Andrew Chaprnan" , " 5 4 6 5 9 9 64 5 " ) ) ;

rnList . add ( new Contact i tern ( " Danie1 Honeyrnan " , " 8 7 654 5 64 4 " ) ) ;

rnList . add ( new Contact i tern ( " Isabella Jackson" , " 9.0 7 8 6 8 7 5 6 " ) ) ;

rnList . add ( new Contact itern ( "Wi11iarn Patterson" , " 68 7 6 9 9 6 9 3 " ) ) ;

rnList . add ( new Contact itern ( " Joseph Godwin" , " 9 65 4 6 7 5 7 5 " ) ) ;

rnList . add ( new Contact itern ( " Sarnantha Bush" , " 9 0 7 8 65 6 4 5 " ) ) ;

rnList . add ( new Contact itern ( " Christopher Gaternan " , " 8 9 6 8 7 4 55 6 " ) ) ;

267

Класс деятельности NewcontactActivity предоставляет функционал ьность для ввода нового контакта и командные кнопки для добавления нового контакта в список ил и отмены ввода. Код класса NewContactActivity представлен в л истинге 1 1 .6 .

package corn . sarnples . contactedi tor ;

irnport android . app . Act ivity;

irnport android . content . Intent ;

irnport android . os . Bund1e ;

irnport android . view . View;

irnport android . widget . Button ;

irnport android . widget . EditText ;

puЬl ic c1ass NewContactActivity extends Act ivity

private Edit}ext rnNarne ;

private EditText rnPhone ;

@ Ove rride

puЬl ic void onCreate ( Bund1e savedinstanceState )

supe r . onCreate ( savedinstanceStat e ) ;

setContentView ( R . 1ayout . contact_itern) ;

rnNarne ( EditText ) findViewByld ( R . id . edit narne ) ;

rnPhone ( EditText ) findViewByid ( R . id . edit_phone ) ;

fina1 Button btnOK ( Button ) findViewByid ( R . id . button_save ) ;

fina1 Button btnCancel ( Button) findViewByid ( R . id . button_cance1 ) ;

btnOK . setText ( R . string . btn_create ) ;

Page 273: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

268

btnOK . setOnCl ickListener ( new View . OnClickLi stener { )

@Override puЬlic void onCl ick ( View v )

Intent intent new Intent { ) ; intent . putExtra ( Contactitern . NAМE ,

rnNarne . getText ( ) . toString { ) ) ; intent . putExt ra ( Contact i tern . PHONE ,

rnPhone . getText ( ) . toString ( ) ) ; setResult ( RESULT_OK, intent ) ; finish ( ) ;

btnCancel . setOnCl ickListener (new View . OnClickListene r ( ) @ Override puЬlic void onClick (View v ) {

setResult ( RESULT_CANCELED ) ; finish ( ) ;

Глава 1 1

Класс деятельности EditContactActivity представляет функционал ьность для редактирования контакта и командные кнопки для добавления нового контакта в список и отмены ввода. Однако, в отличие от класса NewContactActivity, он должен принимать от вызывающей деятельности дан­ные редактируемого контакта. Код класса EditContactAct ivity представлен в листинге 1 1 .7 .

package corn . sarnples . contacteditor ;

irnport android . app . Activity ; irnport android . content . Intent ; irnport android . os . Bundle ; irnport android . view . View ; irnport android . widget . Button ; irnport android . widget . EditText ;

puЬlic class EditContactActivity extends Activity {

private EditText rnNarne ;

private Edi tText rnPhone ;

Page 274: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

Управление деятельностями

@ Override puЬlic void onCreate ( Bundle savedinstanceState )

supe r . onCreate ( savedinstanceState ) ; setContentView ( R . layout . contact_item) ;

mName ( EditText ) findViewByid ( R . id . edit_name ) ; mPhone ( EditText ) findViewByid ( R . id . edit_phone ) ;

final Button btnOK ( Button ) findViewByid ( R . id . button_save ) ; final Button btnCancel

( Button ) findViewByid ( R . id . button_cancel ) ; btnOK . setText ( R . string . btn_save ) ; Bundle ext ras getintent ( ) . getExt ras ( ) ;

mName . setText ( extras . getString ( Contact item. NAМE ) ) ; mPhone . setText ( extras . getString ( Contactitem . PHONE ) ) ;

btnOK . setOnCl ickListener ( new View . OnClickListene r ( )

@Override puЬlic void onCl ick (View v )

Intent intent new Intent ( ) ; intent . putExt ra ( Contact i tem . NAМE ,

mName . getText ( ) . toString ( ) ) ; intent . putExtra ( Contact i tem . PHONE ,

mPhone . getText ( ) . toString { ) ) ; setResult ( RESULT_OK, intent ) ; finish ( ) ;

btnCancel . setOnCl ickListene r ( new View . OnClickListene r ( ) @Override puЬlic void onClick ( View v) {

setResult ( RESULT_CANCELED ) ; finish ( ) ;

269

При запуске приложения на экране устройства появляется окно главной дея­тельности со списком контактов (рис. 1 1 .2).

Из меню можно откры вать дочерние деятельности для ввода и редактирова­ния контактов, передавая (при редактировании) данные выбранного контакта (рис. 1 1 .3 ) .

Page 275: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

270 Глава 1 1

Рис. 1 1 .2 . Главное окно приложения

Рис. 1 1 .3 . Окна дочерних деятел ьностей приложения

Page 276: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

Управление деятельностями 271

При закрытии дочерние деятельности возвращают резул ьтат закрытия (RESULT_oк или RESULT_CANCELED) и данные контакта в родител ьскую деятель­ность, добавляя новый контакт в конец списка или изменяя поля выбранного контакта.

1 1 .5 . Фил ьтры намерен ий и запуск задан и й Фильтры намерений декларируют возможности ком понента и разграничива­ют намерения, которые он может обработать. Фильтры открывают компонент для возможности получения неявных намерений декларируемого типа. Если ком понент не имеет никаких фильтров намерений, он может получить тол ько я вные намерения . Компонент с фильтрами моЖет получить и явные, и неяв­ные намерения .

В фил ьтре намерений декларируется только три составляющих объекта rntent : действие, данные, категория . Дополнения и флаги не играют никакой роли в принятии решения, какой компонент получает намерение.

В манифесте приложения фильтр намерений объявляется в элементе < intent­

filter>. Например, в любом приложении есть главная деятельность, которая устанавливается как точка входа для задания :

<activity

android : name=" . ContactListActivity"

android : label= " @ string/app_name " >

<intent-fi lter>

<action android : name=" android . intent . action . МAIN "

<category android : name=" android . intent . category . LAUNCHER" </ intent-fi lter>

</act ivity>

Фильтр такого вида в элементе <act ion> помечает деятельность, как запус­каемую по умолчанию. Элемент <category> заставляет значок и метку для деятел ьности отображаться на панели Application Launcher, давая пользова­телям возможность запускать задание и возвращаться к этому задан ию в лю­бое время после того, как оно было запущено.

0БРА ТИТЕ ВНИМАНИЕ

Фильтр намерен и й - экземпля р класса Intent Filter. Одн ако , т. к . систем а Aп droid должна знать о возможностях компонента п режде, ч ем она сможет за­пустить этот ко м п о нент, фильтры на м ерен и й всегда устан авливаются тол ько в файле м а н ифеста п риложен ия как эл ементы <intent- fi lter> , а н � в коде п риложен ия .

Page 277: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

272 Глава 1 1

У фильтра есть поля, которые соответствуют действию, данным и категориям объекта Intent. Неявное намерение проверяется в фильтре по всем трем по­лям . Чтобы намерение запустило компонент, которому принадлежит фильтр, оно должно пройти все три теста. Если один из них не проходит, то система не запустит этот компонент - по крайней мере, на основе этого фильтра. Однако, т. к. у ком понента могут быть несколько фильтров, намерение, кото­рое не проходит через один из фильтров компонента, может пройти через другой . Каждый фильтр описывает возможность ком понента и набор намере­ний, которые компонент желает получать.

Для вызова через неявное намерение деятельности contactListActivity

из другого приложения сделаем изменения в файле манифеста примера Contacts, добавив дополнительный фильтр намерений к деятельности ContactLi stAct ivity, как показано в листинге 1 1 . 8 .

<activity

android : name=" . ContactListActivity"

android : label= " @ st ring/app_name " >

<intent-fi lter>

<action android : name=" android . intent . act ion . МAIN "

<category android : name= " android . intent . category . LAUNCHER"

< / intent-filte r> < intent-filte r>

<action android : name= "coт . samples . contact . VIEW_CONTACTS "

<category android : name= " android . intent . category . DEFAULT " </ intent- fi lter>

</ activity>

Строка act ion android : name=" coт . samples . contact . VIEW _ CONTACTS " определяет имя действия . Для вызова деятельности ContactListAct ivity из другого при­ложения необходимо создать объект Intent и передать ему в качестве пара­метра строку " сот . samples . contact . VIEW _ CONTACTS " , определенную в фильтре намерений компонента вызываемого приложения.

Для вызова деятельности contactListAct ivity создадим новый проект:

О Project name - ContactLauncher;

О Application name - Contact Launcher Sample;

О Package name - сот . samples . contact launcher;

О Create Activity - ContactLauncherAct ivity.

Page 278: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

Управление деятельностями 273

Приложение будет представпять окно с одной кнопкой . Файл разметки при­ложения приведен в листинге 1 1 .9 .

<?xml ve rsion= " l . O " encoding= " ut f-8 " ?>

<LinearLayout xmlns : android="http : / /schernas . android . com/apk / res/android"

android : orientation="vert ica l "

android : layout_width= " fill_parent "

android : layout_height=" fil l_parent "

android : gravity=" center">

<Button

android : id=" @ +id/btn launch" android : layout_width= "wrap_content "

android : layout_height= "wrap_content "

android : text= " Launch Contacts Appl icat ion " / >

</LinearLayout>

ПолнЬIЙ код класса ВЬIЗЬIВающей деятельности представлен в листинге 1 1 . 1 О.

package com . samples . contactlauncher ;

import android . app . Activity;

import android . content . Intent ;

import android . os . Bundle ;

import android . view . View ;

import android . widget . Button ;

puЬlic class ContactLauncherActivity extendэ Act ivity

/ / константа , идентифицирующая вызываемую деятельность private final stat ic String ACTION_VIEW_CONTACTS

"com . samples . contact . VIEW_CONTACTS " ;

@ Override

puЬl ic void onCreate ( Bundle savedinstanceStat e )

supe r . onCreate ( savedinstanceStat e ) ;

setContentView ( R . layout . main ) ;

final Button btnLaunch = ( Button ) findViewByid ( R . id . btn_launch ) ;

Page 279: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

274

btnLaunch . s etOnC l i c kListene r ( new View . OnC l i c kLis tene r ( )

@Ove rr ide

puЬ l i c void onC l i c k ( View v )

вызов деятель ности приложения Contacts

sta rtAct ivi ty ( new Intent (ACTION_VIEW_CONTACTS ) ) ;

Глава 1 1

Запустите проект на вы полнение . При нажатии кнопки должна запуститься главная деятел ьность приложения ContactEdi tor (рис. 1 1 .4 ) .

Рис. 1 1 .4 . Запуск деятел ьности из другого приложения

Page 280: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

Г Л А В А 1 2

Службы

Службы в Aпdroid работают как фоновые процессы . Они не имеют пользова­тел ьского интерфейса, что делает их идеальными для задач, не требующих вмешател ьства пользователя . Служба может быть запущена и будет продол­жать работать до тех пор, пока кто-нибудь не остановит ее или пока она не остановит себя сама. Клиентские приложения устанавливают подключение к службам и испол ьзуют это подключение для взаи модействия со службой . С одной и той же службой могут связы ваться множество клиентских прило­жений .

1 2 . 1 . Жизнен н ы й ци кл служб Подобно деятел ьностям (см. главу 1 1) служба имеет свои методы жизнен ного цикла, которые вы можете реализовать, чтобы контролировать изменения в состоянии службы при ее работе. Этих методов только три :

О void onCreate ( ) ;

О vbid onStart ( Intent intent ) ;

О void onDest roy ( ) .

Реализовывая эти методы обратного вызова в своей службе, вы можете кон­трол ировать вложенные жизненные циклы службы.

В полном жизненном цикле службы существует два вложенных цикла:

О полная целая Jfсизиь слу:жбы - промежуток между временем вызова ме­тода onCreate ( ) и временем возвращения onDestroy ( ) Подобно деятел ь­ности, для служб производят начал ьную инициализацию в oncreate ( ) и освобождают все остающиеся ресурсы в onDest roy ( ) ;

О активная целая :JICUЗТIЬ слу:J1сбы - начинается с вызова метода onStart ( )

Этому методу передается объект rntent, которы й передавал и в startService ( ) .

Page 281: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

276 Глава 12

Из клиентского приложения службу можно запустить вызовом метода Context . startService ( ) , остановить через вызов Context . stopServi ce ( ) Служба может остановить сама себя, вызывая методы Service . stopSel f ( ) или Service . stopSel fResult ( ) .

Можно установить подключение к работающей службе и использовать это подключение для взаимодействия со службой. Подключение устанав­

ливают вызовом метода Context . bindservice ( ) и закры вают вызовом Context . unЬindService ( ) . Если служба уже была остановлена, вызов метода ЬindService ( ) может ее запустить .

Методы onCreate ( ) и onDestroy ( ) вызываются для всех служб независимо от того, запускаются ли они через Context . startService ( ) или Context . ЬindService ( ) . Однако метод обратного вызова onstart ( ) вызывается только для служб, запущенных вызовом метода startService ( ) .

Рис. 1 2 . 1 покаЗывает жизненный цикл службы . Хотя жизненный цикл служб, которые запускаются через метод startService ( ) , отличается от запускаемых методом bindService ( ) , очевидно, что любая служба, независимо от того, как

Остановка службы клиентом

Клиент взаимодействует

Рис. 1 2. 1 . Жизнен ный цикл служб

onReЬind()

Page 282: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

Службы 277

она стартовала, может потенциально позволить клиентам связываться с со­бой, т. е . любая служба может получать кл иентские запросы onвind ( ) и onUnЬind ( ) .

Если служба разрешает другим Приложениям связываться с собой, то привяз­ка осуществляется с помощью дополнительных методов обратного вызова:

CJ IBinder onBind ( Intent intent ) ;

CJ boolean onUnЬind ( Intent intent ) ;

CJ void onRebind ( Intent intent ) .

В метод обратного вызова onвind ( ) передают объект Intent, который был па­раметром в методе ЬindService ( ) , а в метод обратного вызова onUnЬind ( ) -объект Intent, который передавали в метод unЬindService ( ) . Если служба разрешает связывание, метод onвind ( ) возвращает канал связи, которы й ис­пользуют клиенты, чтобы взаимодействовать со службой. Метод обратного вызова onReЬind ( ) может быть вызван после onUnЬind ( ) , если новый клиент соединяется со службой .

1 2 .2 . Создан ие службы Чтобы определить службу, необходимо создать новый класс, расширяющий базовый класс Service. В создаваемом классе надо будет определить методы обратного вызова onBind ( ) и oncreate ( ) , как показано далее:

import android . app . Service ;

import android . content . Intent ; import android . os . IBinde r ;

puЬlic class MyService extends Service

@Override puЬlic IBinder onBind ( Intent intent )

1 1 действия при связывании клиента со службой

@Override

puЬl ic void onCreate ( )

1 1 инициализация службы при создании

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

Page 283: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

278 Глава 1 2

кается вызовом метода startService ( ) , таким образом, он может быть выпол­нен несколько раз в пределах целой жизни службы :

@Override

puЬlic void onStart ( Intent intent , int startid)

11 действия при запуске .службы

Как только вы создали новую службу, ее необходимо зарегистрировать в ма­нифесте приложения . Для этого используется элемент <service> внутри эле­мента <application> . Вы можете использовать атрибуты элемента <service>,

чтобы запускать или останавливать службу и определять любые разрешения, требуемые обращения к ней из других приложений, используя флаги в эле­менте <requ i res -penni s s ion> . Например, зарегистрировать службу с именем MyService можно так:

< ? xrnl ve rs ion= " . 0 " encoding= " ut f- 8 " ?>

<mani fest xrnlns : android= "http : / / schemas . androi d . com/apk/ res /android "

<appl ication

android : icon= " @drawaЬle/icon"

android : label= " @ s t ring/app_name " >

<service

android : enaЬled= " t rue "

android : name= " . MyService ">

< / s e rvi ce>

< /appl icat ion>

< /manifest>

Чтобы запустить службу, в кл иентском приложении необходимо вызывать метод s tartService ( ) Существует два способа вызова службы :

D явный вызов;

D неявный вызов.

Пример явного вызова службы с именем MyService может выглядеть следую­щим образом :

startService ( new Intent ( this , MyService . clas s ) ) ;

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

Пример неявного вызова службы выглядит так :

startService ( new Intent (MyService . SERVICE_ACTION ) ) ;

Page 284: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

Службы 279

Чтобы использовать этот пример, необходимо вкл ючить константу SERVICE _ ACTION, идентифицирующую службу, в класс MyService, например:

private static String SERVICE_ACTION " сот . samples . тedia . PLAYER" ;

и использовать фильтр намерений, чтобы зарегистрировать его как провайде­ра SERVICE _ ACT ION.

Если служба потребует разрешений, которые не имеет ваше приложение, то этот запрос вызовет исключение SecurityException.

Чтобы остановить службу, необходимо вызвать метод stopService ( ) и пере­дать намерение, которое определено службой для остановки:

stopService ( new Intent ( thi s , service . getClass ( ) ) ) ;

Если метод startService ( ) вызывают для службы, которая уже запущена, ме­тод обратного вызова onstart ( ) службы будет вы полнен заново . Клиентские вызовы метода startService ( ) не являются вложенными, таким образом, единственный вызов метода stopService ( ) остановит службу независимо от того, сколько было вызовов метода startService ( ) .

Теперь создадим практическое приложение-службу. Наша служба будет за­пускать на воспроизведение музыкальный файл, который будет проигрывать­ся в фоновом режиме. Управлять службой можно будет из деятельности. Создайте новый проект и в окне Create New Project введите следующие зна­чения :

О Project name - ServiceLauncher;

О Application name - Service Launcher Sample;

О Package name - сот . samples . servicelaunch;

О Create Activity - LaunchActivity.

Для службы создайте отдельный класс PlayService. Служба будет загружать музыкальный файл sample.mpЗ из каталога res/raw/ (разместите там файл с вашей любимой музыкой). Полный код класса службы приведен в листин­ге 1 2 . 1 .

package coт . samples . servicelaunch ;

iтport android . app . Service ;

iтport android . content . Intent ;

iтport android . тedia . MediaPlaye r ;

iтport android . os . IBinde r ;

iтport android . widget . Toast ;

Page 285: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

280

puЬlic class PlayService extends Service {

MediaPlayer mPlaye r ;

@OVerride

puЬlic IBinder onBind ( Intent intent ) {

return nul l ;

@OVerride

puЬlic void onCreate ( ) {

Toast . makeText ( thi s , " Se rvice Created" , Toast . LENGTH_SHORT ) . show ( ) ;

mPlaye r = MediaPlayer . create ( this , R . raw . sample ) ;

mPlayer . setLooping ( false ) ;

@OVerride

puЬlic void onStart ( Intent intent , int startid)

Toast . makeText ( this , " Service Started" , Toast . LENGTH_SHORT ) . show ( ) ;

mPlaye r . start ( ) ;

@OVe rride

puЬlic void onDestroy ( ) {

Toast . makeText ( thi s , " Se rvice Stopped" , Toast . LENGTH_SHORT ) . show ( ) ;

mPlayer . stop ( ) ;

Глава 12

В файле манифеста приложеимя необходимо зарегистрировать службу, как было рассказано ранее (листинг 1 2 .2).

< ?xml ve rsion= " l . O " encoding= "utf-8 " ?>

<manifest xmlns : android="http : / / schemas . android . com/apk/res /android"

package="com . samples . servicelaunch"

android : versionCode=" l "

android : vers ionName= " l . O " >

<appl ication

android : icon= " @drawaЬle/ icon"

android : label= " @ s t ring/app_name ">

Page 286: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

Службы

<activity

android : name=" . LaunchActivity"

android : label=" @ string/app_name " >

<intent-fi lter>

281

<action androi d : name=" android . intent . action . МAIN" / >

<category android : name="android . intent . category . LAUNCНER" / > </ intent-filter>

< /activity>

<service

android : enaЬled="true "

android : name=" . PlayService " >

</service>

< / application>

<uses-sdk android : minSdkVersion= " З "

< /mani fest>

В файле разметки для деятельности определим две кнопки, Start Player и Stop Player (листинг 1 2 .3) .

<?xml version= " l . O " encoding= "utf- 8 " ?>

<LinearLayout xmlns : android="http : / / schemas . android . com/apk/res /android"

android : orientation="vertica l "

android : layout_width= " fi l l_parent"

android : layout_height= " fi l l_parent "

android : gravity= " cente r " >

<Button

android : layout_height= "wrap content "

android : id=" @ +id/btn_start "

android : text=" Start Player"

android : layout_width= " fi l l_parent " />

<Button

android : id= " @ +id/btn_stop"

android : layout_height="wrap_content "

android : text=" Stop Player"

android : layout_width= " fil l_parent " / >

< /LinearLayout>

В классе деятельности в обработчиках событий кнопок будем вызывать ме­тоды startService ( ) и stopService ( ) для управления службой . Полный код класса приведен в листинге 1 2 .4 .

Page 287: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

282

package com . samples . se rvice launch ;

import android . app . Activity;

import android . content . Intent ;

import android . os . Bundle ;

import android . view . View;

import android . widget . Button ;

puЬlic class LaunchActivity extends Activity

@ Override

puЬl i c void onCreate ( Bundle savedinstanceState )

super . onCreate ( savedinstanceState ) ;

setContentView ( R . layout . main ) ;

Глава 12

final Button btnStart ( Button ) findViewByid ( R . id . btn_start ) ;

final Button btnStop ( Button ) findViewByi d ( R . id . btn_stop ) ;

1 1 запуск службы

btnStart . setOnClickListener ( new View . OnCl ickListene r ( )

@Override

puЬlic void onCl ick (View v )

1 1 исполь зуем явный вызов службы startService (

new Intent ( LaunchActivity . thi s , PlayService . class ) ) ;

1 1 остановка службы btnStop . setOnClickLis tene r ( new View . OnCl ickListener ( )

@Override

puЬlic void onClick (View v )

stopSe rvice (

new Intent ( LaunchActivity . this , PlayService . class ) ) ;

Внешний вид созданного приложения со службой приведен на рис. 1 2 .2 . За­пуЩенная служба будет выполняться независимо от состояния деятельности,

Page 288: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

Службы 283

несмотря на то что эти компоненты находятся в одном приложении : если ее завершить, служба все равно останется работать .

Рис. 1 2.2 . Приложение для вызова службы

Page 289: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

Г Л А В А 1 3

П рием ники широковещател ьных намерений

Как уже говорилось ранее, приемник широковещательных намерений - это компонент для получения внешних событий и реакции на них. Инициализи­ровать передачи могут другие приложения или службы .

Класс BroadcastRecei ver является базовым для класса� в котором должны происходить получение и обработка намерений, посылаемых кл иентским приложеннем с помощью вызова метода sendВroadcast ( ) . Вы можете или ди­намически зарегистрировать экземпляр класса BroadcastRecei ver с помощью метода Context . registerReceiver ( ) , или статически создать его в элементе < rece iver> в файле манифеста приложения .

Есть два основных класса сообщений, которые могут быть получены прием­ником :

О нормальные сообщения о намерениях (Normal broadcasts) - посылаемые вызовом метода Context . sendВroadcast и я вляющиеся полl-/остью асин­хронными. Все получатели сообщения выполняются в неопределенном порядке, часто в одно и то же время. Это более эффективно, но означает, что получатели не могут использовать результат или прервать сообщение;

О порядковые сообщения о намерениях (Ordered broadcasts), которые посы­лаются методом Context . sendOrderedВroadcast ( ) . Эти сообщения посыла­ются одному получателю за один раз. Поскольку каждое полученное со­общение выполняется по очереди, он может в случае необходимости пол­ностью прервать сообщение, чтобы его не успели передать другим приемникам . Приемниками намерений можно управлять с помощью атри­бута androi d : priority фильтра намерений; приеминки намерений, имею­щие одинаковый приоритет, будут выполнены в произвольнам порядке.

Хотя класс Intent используется для посылки и получения этих широковеща­тельных намерений, сам механизм широковещательных намерений пол-

Page 290: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

286 Глава 1 3

ностью отделен от намерений, используемых, например, чтобы запустить

деятельность методом Context . startAct i vi ty ( ) .

Для объекта BroadcastReceiver нет никаких возможностей видеть или фикси­ровать намерения, используемые в методе startActi vi ty ( ) . Аналогично, ко­гда вы передали намерение для запуска деятельности через объект Broadcas tReceiver, вы не сможете найти или запустить требуемую деятель­ность. Эти две операции семантически полностью различаются : запуск дея­тельности через намерение я вляется приоритетной операцией для системы, изменяющей содержимое экрана устройства, с которым в настоящее время взаимодействует пользователь. Передача намерения для системы я вляется фоновой работой, о которой обычно не знает пользователь и которая, соот­ветственно, имеет более низкий приоритет.

Класс BroadcastReceiver (когда он запускается как компонент через элемент манифеста < recei ver>) я вляется важной частью полного жизненного цикла приложения .

1 3 . 1 . Жизне н н ы й ци кл п рием н и ков ш и роковещател ьных намерений Приемник широковещательных намерений имеет единственный метод обрат­ного вызова:

void onRece ive ( Context curContext , Intent broadcas tMs g )

Когда широковещательное сообщение прибывает для получателя сообщения, система Android вызывает его методом onRecei ve ( ) и передает в него объект Intent, содержащий сообщение. Приемник широковещательных намерений я вляется активным только во время выполнения этого метода. Процесс, кото­рый в настоящее время выполняет вroadcastReceiver, т. е. выполняющийся в настоящее время код в методе обратного вызова onRecei ve ( ) , как полагает система Android, я вляется приоритетным процессом и будет сохранен, кроме случаев критического недостатка памяти в системе.

Когда программа возвращается из onRecei ve ( ) , приемник становится неак­тивны м и система полагает, что работа объекта вroadcas tReceiver закончена. Процесс с активным широковещательным получателем защищен от уничто­жения системой. Однако процесс, содержащий неактивные ком поненты, мо­жет быть уничтожен системой в любое время , когда память, которую он по­требляет, будет необходима другим процессам .

Это представляет проблему, когда ответ на широковещательное сообщение

занимает длительное время . Есл и метод onRecei ve ( ) порождает отдельный

Page 291: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

Приемники широковещательных намерений 287

поток, а затем возвращает управление, то полный процесс, включая и порож­денный поток, система Android считает неактивным (есл и другие компонен­ты приложения не активны в процессе), и считает этот процесс кандидатом на уничтожение.

В частности, вы не можете отобразить диалог или осуществить связывание со службой внутри экземпляра вroadcastReceiver. Дnя первого случая необхо­димо вместо этого использовать методы класса Noti ficationМanager. Во вто­ром случае можно использовать вызов метода Context . s tartService ( ) , чтобы послать команду для запуска службы .

Решение этой проблемы возможно, если запустить в методе onRecei v e ( ) от­дельную службу вместе с BroadcastReceiver и позволить службе выполнять задание, чтобы сохранить содержание процесса активным в течение всего времени вашей операции .

1 3 .2 . П рием н и ки систем ных событи й Система Aпdroid использует широковещател ьные намерения для системных событий, таких как уровень зарядки батареи, сетевые подключения, входя­щие звонки, изменения часового пояса, состояние подключения данных, вхо­дящие сообщения SMS или обращения по телефону. Вы можете использовать эти сообщения, чтобы добавлять к вашим собственным проектам новые функциональные возможности, основанные на системных событиях.

Следующий список показывает некоторые из встроенных действий, пред­ставленных как константы в классе Intent. Эти действия используются преж­де всего для того, чтобы проследить изменения состояния мобильного уст­ройства:

О ACTION_вooт_cOMPLETED - передается один раз, когда устройство заверш и­ло свою загрузку. Требует разрешения RECEIVE_вooт_coмPLETED;

О ACT ION _ САМЕRА _ вuттоN - передается при нажатии пользователем клавиши <Camera>;

0 ACT ION _DATE _ CНANGED И ACT ION _ ТIМЕ _ CНANGED - запускаЮТСЯ при ИЗМенеНИИ даты или времени на устройстве вручную пользователем;

0 ACT ION_SCREEN_OFF И ACT ION_SCREEN_ON - передаются, КОГДа экран устроЙ­СТВа выключается или включается;

О ACT ION _ TIМEZONE _ CНANGED - передается при изменении текущего часового пояса телефона.

Page 292: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

288

1 3 .3 . Испол ьзование широковещател ьных намерений

Глава 13

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

В главах 11 и 12 мы рассматривали использование намерений для запуска новых прикладных компонентов приложений. Эти компоненты могут также реагировать на анонимные ш ироковещательные сообщения между компонен­тами через вызов метода sendВroadcast ( ) . Можно реализовать приемники широковещательных намерений, чтобы проелушивать намерения, посылае­мые другими компонентами, и отвечать на эти широковещательные намере­ния в рамках вашего приложения.

Широковещательные намерения также используются для уведомления слу­шателей системных или прикладных событий . Широковещательные намере­ния делают приложение более открытым; передавая события, использующие намерения, вы открываете компоненты своего приложения для сторонних приложений, и сторонние разработчики реагируют на события, не имея необ­ходимости изменять ваше оригинальное приложение. В вашем приложении вы можете проелушивать широковещательные намерения других приложе­ний, заменить или улучш ить функциональность собственного (или сторонне­го) приложения или реагировать на системные изменения и события прило­жений .

1 3.3 . 1 . Передача событий через намерения

Фактически передача намерений весьма проста в реализации . В вашем при­ложении необходимо создать намерение, которое вы хотите передать, и ис­пользовать вызов метода sendВroadcast ( ) , чтобы послать это намерение. У с­тановите поля action, data и category (действие, данные и категорию) вашего намерения и путь, который позволяет Приемникам ш ироковещательных на­мерений точно определять "свое" намерение.

В этом намерении строка действия используется, чтобы идентифицировать передаваемое действие, таким образом, это должна быть уникальная строка­идентификатор действия. В соответстви и с соглашением строки действия создаются, используя те же правила именования, как и правила именования пакетов Java. Например, для намерения для взаимодействия с медиаплеером (см . пример службы в предыдущей главе) можем объявить идентификатор:

private static String ACTION " corn . sarnples . rnedia . PLAYER" ;

В коде, посылающем широковещательные намерения с использованием идентификатора действия ACTION и с включением дополнительной информа-

Page 293: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

Приемники широковещательных намерений 289

ции, необходимо создать объект Intent, загрузить в него нужную информа­цию и вызвать метод sendВroadcast ( ) , передав ему в качестве параметра соз­данный объект Intent:

pri vate sta tic final String ТУРЕ = " type " ;

private static final int ID_ACTION_PLAY = О ;

Intent intent = new Intent (ACTION ) ;

intent . putExtra ( TYPE , ID_ACTION_PLAY ) ;

sendВroadcast ( intent ) ;

1 3.3.2. П роелушиван ие событий п риемниками широковещател ь н ых намерений Чтобы создать приемник широковещательных намерений, его необходимо зарегистрировать в манифесте приложения. Регистрируя приемник широко­вещательных намерений, вы должны использовать фильтр намерений, чтобы определить, какие намерения приемник должен прослушивать. Для этого на­до в элементе <applicat ion> добавить элемент <receiver>, определяющий имя класса приемника широковещательных намерений для его регистрации. Эле­мент <receiver> должен также включать фильтр намерений <intent-fi lter>,

который определяет строку действия. Например, для регистрации приемника широковещательных намерений для взаимодействия с медиаллеером (см. предыдущую главу) файл манифеста будет имеет следующий вид:

<appl ication

< receiver android : name=" . Playe rReceiver">

<intent-fi lter>

<action android : name=" com. samples . media . PLAYER" />

< / intent- filter>

< / rece iver>

< / applicat ion>

Чтобы создать новый приемник широковещательных намерений в коде при­ложения, необходимо создать класс, расширяющий базовый класс BroadcastRecei ver, и реализовать метод обратного вызова onRecei ve ( ) обра­ботчика событий, как показано в примере:

puЬlic clas s PlayerReceive r extends BroadcastRece iver {

private static final String ТУРЕ = "type " ;

private static final int ID ACTION PLAY = 0 ;

private static final int I D ACTION STOP = 1 ;

Page 294: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

290

@Override

puЬlic void onReceive ( Context context , Intent intent ) {

int type intent . getintExtra ( TYPE , I D_ACTION_STOP ) ;

switch ( type )

case I D ACTION PLAY :

/ 1 выполнение полученного намерения

Глава 13

context . start Service ( new Intent ( context , PlayService . clas s ) ) ;

brea k ;

Метод onReceive ( ) будет выполнен при получении широковещательного на­мерения. Приложения с зарегистрированными приемниками широковеща­тельных намерений будут заnущены автоматически при nолучении соответ­ствующего намерения.

1 3 .3 .3 . П ример приложения-приемника намерен ий

Для создания nриложения с приемником широковещательных намерений возьмем за основу nриложение, запускающее службу фонового воспроизве­дения музыки, созданную в предыдущей главе, удалив из него класс деятель­ности LaunchActivity, который будет вынесен в отдельное приложение, опи­санное далее в этой главе. Создайте в Ecl ipse новый проект без определения главной деятельности nриложения:

О Project name - BroadcastRecei ver;

О Package name - сот . sarnples . broadcast receiver.

Добавьте в файл манифеста регистрацию приемника широковещательных намерений PlayerReceiver с фильтром намерений и службы PlayService, как показано в листинге 1 3 . 1

<?xrnl version= " . 0 " encoding= " ut f-8 " ?>

<rnani fest xrnlns : android="http : / / schernas . android . com/apk/res/android"

package= " corn . sarnples . broadcast receiver"

android : vers ionCode=" l "

android : versionNarne= " l . O " >

<application

android : icon= " @drawaЬle/icon"

android : label= " @st ring/app_narne " >

Page 295: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

Приемники широковещательных намерений

<service

android : enaЬled= " t rue "

android : name= " . PlayService " >

</service>

<receive r android : name=" . PlayerReceive r " >

<intent-fi lter> <act ion android : name=" corn . samples . rnedia . PLAYER"

< / intent- filter>

</receiver>

< / application>

<uses-sdk android : rninSdkVers ion= " З "

< /rnanifest>

29 1

Создайте новый класс, расширяющий класс вroadcastReceiver, и напишите код, приведенный в листинге 1 3 .2 .

package corn . samples . broadcast receive r ;

irnport android . content . BroadcastReceiver ;

irnport android . content . Context ;

irnport android . content . Intent ;

irnport android . widget . Toas t ;

puЬlic class PlayerReceive r extends BroadcastReceiver {

private static final String ТУРЕ " type " ;

private static final int I D ACTION PLAY О ;

private static final int I D ACTION STOP 1 ;

@ Override

puЬlic void onRece ive ( Context context , Intent intent )

int type intent . getintExtra ( TYPE , I D_ACTION_STOP ) ;

switch ( type ) {

case I D ACTION PLAY :

Toast . rnakeText ( context,

"Received action : play" , Toas t . LENGTH_LONG ) . show ( ) ;

запускаем службу context . startService ( new Intent ( context , PlaySe rvice . clas s ) ) ;

break ;

Page 296: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

292 Глава 13

case I D ACTION STOP :

Toast . rnakeText ( context ,

" Received action : stop " , Toas t . LENGTH_LONG ) . show ( ) ;

останавливаем службу

context . stopService ( new Intent ( context , PlayService . class ) ) ;

break;

Добавьте в приложение класс Playservice, код которого приведен в главе 12,

в листинге 1 2 . 1 .

Мы создали приложение-приемник широковещательных намерений . Теперь необходимо создать приложение, посылающее широковещательное наме­рение.

1 3.3.4. П ример приnожен ия-передатчика намерен и й

Для приложения-передатчика также можно взять за основу приложение, за­пускающее службу для работы с медиаплеером. Для этого создайте в Ecl ipse новый проект:

D Project name - BroadcastSender;

D Application name - Music Launcher Sample;

D Package name - сот . samples . broadcastsender;

D Create Activity - LaunchActivity.

Файл разметки возьмите из листинга 1 2 .3 . Класс LaunchActivity необходимо переделать для вызова широковещательного намерения, используя методику, приведеиную ранее в этом разделе. Полный код измененного класса LaunchActivity приведен в листинге 1 3 .3 .

package com . samples . broadcastsende r ;

import android . app . Activity;

import android . content . Intent ;

import android . os . Bundle ;

import android . view . View;

import android . widget . Button ;

Page 297: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

Приемники широковещательных намерений puЬlic class LaunchActivity extends Act ivity

private static String ACТION = " сот . sarnples . rnedia . PLAYER" ;

private static final St ring ТУРЕ = " type" ;

private static final int ID ACTION PLAY О ; private static final int ID ACТION STOP = 1 ;

@Override

puЬlic void onCreate ( Bundle savedinstanceStat e )

super . onCreate ( savedinstanceState ) ;

setContentView ( R . layout . rnain ) ;

final Button btnStart ( Button ) findViewByid ( R . i d . btn_s tart ) ;

final Button btnStop = ( Button ) findViewByid ( R . id . btn_stop ) ;

btnStart . setOnClickListener ( new View . OnCl ickListener ( )

@Override

puЬlic void onClick (View v) {

1 1 посылаем сообщение для запуска службы Intent intent = new Intent (ACTION ) ;

intent . putExtra ( TYPE , I D_ACTION_PLAY ) ;

sendВroadcast ( intent ) ;

btnStop . setOnClickListener ( new View . OnClickLis tener ( )

@Override

puЬlic void onClick (View v) { 1 1 посылаем сообщение для остановки службы Intent intent = new Intent (ACTION ) ;

intent . putExt ra ( TYPE , ID_ACTION_STOP) ;

sendВroadcast ( intent ) ;

293

Внешний вид созданного приложения для запуска службы останется таким же, как и в главе 12 (см . рис. 1 2 .2), только теперь служба фонового воспроиз­ведения музыки будет запускаться или останавливаться из приложения через посылку широковещательного намерения.

Page 298: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

Г Л А В А 1 4

Работа с фа йлами и сохранение п ол ьзовател ьских настроек

Платформа Aпdroid обесnечивает следующие механизмы для сохранения и чтения данных:

О файлы ;

О nредnочтения (Prefereпces);

О базы данных.

В этой главе мы рассмотрим работу с файлами и nредnочтениям и - сохра­нение и изменение nользовательских настроек nриложения . Базы данных будут рассмотрены в следующей главе.

1 4. 1 . Чтен ие и запись файлов В Aпdroid можно сохранять файлы неnосредственно н а мобильном устройст­ве ил и на внешнем носителе данных (наnример, SD-карте). По умолчанию другие nриложения не могут обращаться к этим файлам .

Оnерации ввода-вывода в Aпdroid аналогичны оnерациям в стандартных Jаvа-nрограммах. Aпdroid реал изует nотоки с nомощью иерархии классов, оnределенных в nакете java. io (рис. 1 4 . 1 ) . Кроме этих классов в nакете java. io оnределено множество сnециал изированных классов для оnераций ввода­вывода.

Чтобы nрочитать данные из файла, необходимо вызвать метод Context . openFi leinput ( ) и nередать в качестве nараметра имя файла. Метод возвращает стандартный Jаvа-объект FileinputStream. Наnример, код для чтения данных из текстового файла может выглядеть так:

InputStream inSt ream openFi leinput ( fi l e . txt ) ;

InputStreamReader s r = new InputStreamReader ( inStream) ;

Page 299: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

296

11 создаем буфер для чтения файла

BufferedReader reader new BufferedReader ( s r ) ;

String str ;

StringBuffer buffer new StringBuffer ( ) ;

1 1 читаем данные в буфер

while ( ( str reade r . readLine ( ) )

buffer . append ( str + " \n " ) ;

null )

inStrearn. close ( ) ;

1 O bject 1 l n p u t S tre a m

O u tp u tS tre a m

R e a d e r

1 F i le l n p u tS tre a m

1 F ileO u tp u tS tre a m

1

1

1

l n p u tS trea m R e a d e r 1 В uffe red R e a d e r 1

S trin g R e a d e r 1 W r ite r 1

O u tp u tS tre a m W rite r 1 B uffe re d W rite r 1

S trin g W rite r 1 Рис. 1 4.1 . Классы для файлового ввода-вывода в Android

Глава 14

Чтобы записывать в файл, необходимо вызвать метод context .

openFi leOutput ( ) , передав ему имя файла как параметр. Этот метод возвраща­ет объект FileOutputSt rearn. Вызов этих методов для данного файла из друго­го приложения не будет работать, обратиться вы можете только к своим фай­лам . Пример записи строки данных в файл file .txt может быть следующим:

String data ;

OutputSt rearn outStrearn = openFileOutput ( file . txt , 0 ) ;

OutputStrearnWriter sw

sw . write ( data ) ;

sw . close ( ) ;

new OutputStrearnWriter ( outStrearn) ;

Page 300: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

Работа с файлами и сохранение пользовательских настроек 297

Если имеется статический файл, который надо уnаковать с вашим nриложе­ннем во время комnиляции nроекта, можно сохранить его в каталоге nроекта в паnке res/raw/, а затем открыть его методом Resources . openRawResource ( ) . Он возвращает объект Inputst rearn, который можно исnользовать для чтения файла. После окончания работы с nотоком не забудьте его закрыть, вызвав метод close ( ) .

0БРА ТИТЕ ВНИМАНИЕ

Методы openFi leinput ( ) и openFileOutput ( ) не п ри нимают пол ного пути к файлу (например , pathlfileslfile . txt) , только простые имена файла.

В качестве nримера nриложения, заnисывающего и читающего данные из файлов, создадим nростейший текстовый редактор с виджетом Editтext и меню для открытия файла и сохранения его nосле редактирования. Создайте в Ecl ipse новый nроект, заnолнив nоля в окне New Android Project:

D Project name - ContactEditor;

D Application name - Read-Write File Sample;

D Package name - com . samples . filesrw;

D Create Activity - EditorActivity.

Код ХМL-схемы разметки main.xml, в которой находится единственный эле­мент Editтext, nрив'?дится в листинге 1 4 . 1 .

<?xml version= " l . O " encoding= " utf-8 " ?>

<LinearLayout xmlns : android= "http : / / schemas . android . com/apk/res/android"

android : layout_width=" fill_parent " android : layout_height=" fi l l_parent " android : orientation="vertica l " >

<EditText

android : id= " @ + id/edi t " android : layout_width= " fi l l_parent " android : layout_height= " f i l l_parent " android : s ingleLine=" false " />

</LinearLayout>

В классе деятельности nриложения EditorAct ivity оnределим меню из трех nунктов - Open, Save и Exit. Во внутренних методах openFi le ( ) и saveFi le ( ) реализуем оnерации по открытию и сохранению файла, nриведеи­ные ранее. Код класса EditorAct ivity nредставлен в листинге 1 4 .2 .

Page 301: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

298

package com . samples . fi lesrw ;

import j ava . io . BufferedReader ;

import j ava . io . InputStream;

import j ava . io . InputSt reamReader ;

import j ava . io . OutputStreamWrite r ;

import android . app . Activi t y ;

import android . os . Bundle ;

import android . view . Menu ;

import android . view . Menuitem;

import android . widget . EditText ;

import android . widget . Toas t ;

puЬlic class EditorActivity extends Activity

puЫ ic static final int I DM OPEN 1 0 1 ; puЬl ic s tat ic final int I DM SAVE 1 0 2 ;

puЬl ic stat i c final int I DM EXIT 1 0 3 ;

private final static String FILENAМE

private EditText mEdit ;

@ Override

puЬlic void onCreate ( Bundle icicle )

supe r . onCreate ( icic1e ) ;

setContentView ( R . layout . main ) ;

" f i le . txt " ;

mEdit ( EditText ) findViewByid ( R . id . edit ) ;

@ Override

puЬlic boolean onCreateOptionsMenu ( Menu menu ) {

menu . add (Menu . NONE , I DM_OPEN , Menu . NONE , " Open" )

. seticon ( R . drawaЬle . ic_menu_open)

. setAlphabeticShortcut ( ' o ' ) ;

menu . add (Menu . NONE , I DM_SAVE , Menu . NONE , " Save " )

. seticon ( R . drawaЬle . ic_menu_save )

. setAlphabeticShortcut ( ' s ' ) ;

menu . add (Menu . NONE , I DM_EXI T , Menu . NONE , "Exit " )

. seticon ( R . drawaЬle . ic_menu_exi t )

. setAlphabeticShortcut ( ' x ' ) ;

Глава 14

Page 302: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

Работа с файлами и сохранение пользовательских настроек

return ( super . onCreateOptionsMenu (menu ) ) ;

@ Override

puЬlic boolean onOptions itemSelected (Menuitem item)

switch ( item . getitemid ( ) )

case I DM OPEN :

openFi le ( FILENAМE ) ;

break;

case I DM SAVE :

saveFile ( FILENAМE ) ;

break;

case I DM EXIT :

finish ( ) ; brea k ;

default :

return fal s e ;

return true ;

private void openFile ( String fileName )

try {

InputSt ream inStream openFileinput ( FILENAМE ) ;

i f ( inStream nul l )

InputStreamReader s r

new InputStreamReade r ( inStream) ;

BufferedReader reader new BufferedReader ( s r ) ;

String s t r ;

StringBuffer buffer new StringBuffe r ( ) ;

whi le ( ( str reader . readLine ( ) )

buffe r . append ( str + " \n" ) ;

inStream . close ( ) ;

mEdit . setText ( buffe r . toString ( ) ) ;

catch ( ThrowaЬle t )

Toas t . makeText ( getApplicationContext ( ) ,

null )

"Exception : " + t . toString ( ) , Toast . LENGTH_LONG)

299

Page 303: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

300

. show ( ) ;

private void save Fi l e ( String Fi leName )

t ry

Глава 14

OutputStream outS t ream = openFi leOutput ( FI LENAМE , 0 ) ;

Output S t reamWriter sw = new Output StreamWrite r ( out St ream) ;

sw . write (mEdit . getText ( ) . toString ( ) ) ;

sw . close ( ) ;

catch ( ThrowaЬle t )

Toas t . makeText ( getApplicationContext ( ) ,

" Except ion : + t . toSt ring ( ) , Toast . LENGTH_LONG )

. show ( ) ;

Внешний вид приложения, позволяющего читать и записывать текст в файл, приведен на рис. 1 4 .2 .

1 234567890qwerty

Рис. 1 4.2. Текстовый редактор с возможностью сохранения содержимого в файле

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

Page 304: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

Работа с файлами и сохранение пользовательских настроек 301

вершенствовать приложение, добавив возможность создания новых файлов, их открытия и сохранения, а также в случае необходимости удаления файлов.

1 4.2 . П редпочтен ия Предпочтение - облегченный механизм для сохранения и восстановления пары ключ-значение для примитивных типов дан ных. Предпочтения обычно используются для сохранения установок приложения, типа приветствия, раз­меров и стилей шрифта, звукового сопровождения, которые будут загружены при запуске приложения . В любом мобильном устройстве обязательно при­сутствует интерфейс для установки предпочтений (на панели Application Launcher - значок Settings). Пример установки предпочтений и внешний вид окон по казан на рис. 1 4 .3 .

Рис. 1 4.3 . Установка пред почтений для мобильного устройства

Aпdroid предоставляет в распоряжение разработчиков Prefereпces Framework, с помощью которого можно создавать индивидуальный набор предпочтений и встраивать их в приложения . Prefereпces Framework представляет собой на­бор классов для разработки . Иерархия классов предпочтений nредставлена на рис. 1 4 .4 .

Предпочтения - это отдельный экран в приложении, вызы ваемый из дея­тельности . Предпочтения определяются в отдельном ХМL-файле. Корнем предпочтений в XML является элемент <Prefe rence Screen>, который пред­ставляет собой контейнер для предпочтений и также может содержать дочер­ние элементы < Prefe rence Screen>. Элемент <PreferenceCatego ry> также явля-

Page 305: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

302 Глава 14

ется контейнерным элементом и предназначен для объединения предпочте­ний в группы .

Всего для сохранения предпочтений разных типов используется четыре класса:

CJ CheckBoxPreference;

CJ EditTextPreference;

CJ ListPreference;

CJ RingtonePreference .

O bj e c t 1 г------,

P re fe re n c e 1 .-----------, P re fe re n c e G ro u p 1

P re fe re n ce C a te g o ry 1 1 Р refe re n ce S c re e n 1

D i a l o g Р refe re n c e 1 Е d itт extP refe r e n с е 1

1 L i s t P refe re n c e 1 C h e c k B o x P refere n c e 1

R i n g to n e P refe re n c e 1 Рис. 1 4.4. Иерархия классов предпочтений

Работа с этими предпочтениями и использование их в приложениях будет подробно описана далее в этой главе.

Если набор предпочтений будет совместно употребляться с другими ком по­нентами данного приложения, необходимо присвоить имя этому набору предпочтений. Если набор предпочтений будет использоваться только в од­ной деятельности, имя можно не присваивать и применять вызов метода Act i vi ty . getPreferences ( ) . Нельзя использовать предпочтения для обмена данными между Приложениями (для этого существует контент-провайдер, который будет рассмотрен в следующей главе).

1 4.2 . 1 . Испол ьзование п редпочтений

Aпdroid позволяет действиям и приложениям сохранять предпочтение в виде пары ключ-значение. В предпочтении можно сохранять любые данные, если они имеют тип String или являются примитивными типам и данных (boolean,

int и т. д.) .

Page 306: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

Работа с файлами и сохранение пользовательских настроек 303

Предпочтение может быть доступно для единственной деятельности, а может быть общим для всех деятельностей приложения. Предпочтение возможно также сделать общим для нескольких приложений .

Для получения доступа к предпочтению в коде приложения используются три метода:

D getPre ferences ( ) - внутри деятельности, чтобы обратиться к определен­ному для деятельности предпочтению;

D getSharedPreferences ( ) - внутри деятельности, чтобы обратиться к пред­почтению на уровне приложения;

D getDefaul tSharedPre ferences ( ) - из объекта Prefe rencesManager, чтобы получить общедоступное предпочтение, предоставляемое системой Android .

Первые два берут параметр режима безопасности, обычно установленный в О . Метод getSharedPre ferences ( ) также принимает название ряда предпочте­ния - getPreferences ( ) . Метод getDefaul t Sha redPreferences ( ) в качестве параметра принимает объект Context (например, текущей деятельности) .

Все эти методы возвращают экземпляр класса SharedPreferences, из которого можно получить соответствующее предпочтение с помощью ряда методов:

D getBoolean ( String key, boolean de fValue ) ;

D getFloat ( St ring key, float de fValue ) ;

D getint ( St ring key, int de fValue ) ;

D getLong ( String key , long de fValue ) ;

D getString ( St ring key, String defValue ) .

Второй параметр в методах get . ( ) - это значение по умолчанию, возвра­щаемое при невозможности прочитать выбранное значение предпочтения.

Например, так можно получить значение для предпочтения с типом boolean:

SharedPreferences prefs Pre ferenceManager . getDefaultSha redPreferences ( this ) ;

boolean val prefs . getBoolean ( getString ( R . string . pre f_item) , false ) )

Создание предпочтений для приложения мы опробуем на практике, взяв за основу предыдущий проект для чтения-записи файла, и постепенно будем совершенствовать его, добавляя различные виды предпочтений .

1 4.2 .2 . CheckBoxPreference

Это предпочтение сохраняет Ьооlеаn-переменную в Sha redPrefe rences . Это самое простое в использовании предпочтение. Для примера приложения

Page 307: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

304 Глава 14

с установкой предпочтений создайте новый проект и в окне Create New Project введите следующие значен ия :

D Project name - Preferences ;

D Application name - Preferences Sample;

D Package name - com. samples . preferences;

D Create Activity - LaunchAct ivity.

Файл разметки главной деятельности main.xml будет таким же, как и в пре­дыдущем приложении с текстовым редактором (см . листинг 1 4 . 1 ) . Просто скопируйте его в новый проект.

Так как предпочтения имеют имена, к которым будут обращаться из файла предпочтений и программнога кода, эти имена целесообразно хранить в фай­ле res/values/strings.xml . Наше первое предпочтение назовем OpenMode. По­скольку в это приложение мы будем постепенно добавлять предпочтения других типов, можете сразу записать их имена в файл . Содержимое файла striпgs.xml для полного набора предпочтений, которые будут добавлены в этой главе, показано в листинге 1 4 .3 .

< ?xml ve rsion= " . 0 " encoding= "utf-8 " ?>

<resources>

<string name= " app_name " > Preferences Sample</st ring>

<string name="pr_openmode " >OpenМode</st ring>

<string name="pr_color" >Color</ s tring>

<string name="pr_color_Ьlack" >ColorBlack< /string>

<string name="pr_color_red" >ColorRed< /string>

<string name="pr_color_green" >ColorGreen< /string>

<string name="pr_color_Ьlue " >ColorBlue</string>

<string name= "pr_s i z e " > S i ze</string>

<string name="pr_styl e " >Style< / s tring>

<string name="pr_style_regular" >StyleRegular< / s tring>

<s tring name="pr_style_bold" >StyleBold< /string>

<string name="pr_style_itali c " >Styleitalic</st ring>

<string name="pr_tone " >Tone< / string>

< / resources >

Это предпочтение будет или сразу загружать файл в поле редактирования, если установлен флажок, или открывать пустое поле, если флажок не уста­новлен. Код файла предпочтений preferences.xml показан в листинге 1 4 .4 .

Page 308: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

Работа с файлами и сохранение пользовательских настроек

<PreferenceScreen

xmlns : android= " http : / / schernas . android . com/apk/res/android" >

<CheckВoxPreference

android : key= " @ string/pr_openmode " android : ti t le="Open file"

android : surnrnary="To open а file at start appl icat ion " />

</PreferenceScreen>

305

Учитывая, что предпочтения объявляются в ХМL-файле, для отображения предпочтения необходимо использовать встроенную деятельность. В классе деятельности для предпочтений внутри метода обратного вызова onCreate ( )

нужно только вызвать метод addPreferencesFromResource ( ) и загрузить XML­pecypc (в нашем примере - файл preferences.xml), содержащий предпочте­ния. Код класса деятельности PreferencesActivity для вызова предпочтений представлен в листинге 1 4 . 5 .

package com . samples . preferences ;

import android . os . Bundle ;

import android . preference . Pre ferenceActivity;

puЬlic class Pre ferencesActivity extends PreferenceAct ivi ty

@Override

puЬlic void onCreate ( Bundle savedinstanceState )

supe r . onCreate ( savedinstanceState ) ;

1 1 загружаем предпочтения из ресурсов

addPreferences FromResource ( R . xml . pre ferences ) ;

Не забудьте добавить объявление деятельности PreferencesActivity в файл манифеста приложения (листинг 1 4 .6).

<?xml version= " l . O " encoding= "ut f-8 " ?>

<rnani fest xmlns : android="http : / / schernas . android . com/apk/ res /android"

package="com . samples . preferences " >

<application android : label=" @ string/app_name " >

Page 309: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

306

<activity

android : name= " . EditorActivity"

android : labe l= " @ s tring/app_name " >

<intent-fi lter>

Глава 14

<action android : name=" android . intent . action . МAIN "

<category android : name="android . intent . category . IAUNCНER" </intent- filter>

< /activity>

<activity

android : name=" . PreferencesEdit "

android : label= " @ s tring/app_name " >

< /activity>

</appl ication>

< /mani fest>

За основу класса главной деятельности возьмем класс EditorActivity из nре­дыдущего nримера (см . листинг 1 4 .2). В класс добавим новый nункт меню ­Settings, который будет открывать окно nредnочтений . В метод обратного вызова onOptions i temSelected ( ) добавим в структуру switch новый элемент case для вызова окна nредnочтений :

case I DM PRE F :

Intent intent new Intent ( ) ;

intent . setClas s ( this , Pre ferencesActivity . clas s ) ;

startActivity ( intent ) ;

break ;

Чтение установок предnочтений nроизводится в методе onResшne ( ) . Этот ме­тод вызывается системой Android как во время заnуска nриложения, так и после закрытия окна предпочтений и возврата главной деятельности на пе­редний план . Код для чтения установки предnочтения в onResшne ( ) должен выглядеть так:

SharedPre ferences prefs

Pre ferenceManager . getDefaultSha redPre ferences ( thi s ) ;

1 1 читаем установленное значение из CheckВoxPreference

if (prefs . getBoolean ( getString ( R . string . pr_openmode ) , fa lse ) )

openFile ( FILENAМE ) ;

В методе getвoolean ( ) второй параметр (false) означает значение по умолча­нию для возвращаемого значения предnочтения, если заnрос на чтение уста­новленного значения закончится неудачей .

Полный код класса главной деятельности приложения EditorActivity nред­ставлен в листинге 1 4 .7 .

Page 310: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

Работа с файлами и сохранение пользовательских настроек

package corn . samples . preferences ;

irnport j ava . io . BufferedReader ;

irnport j ava . io . InputStream;

irnport j ava . io . InputStreamReader ;

irnport j ava . io . OutputStreamWrite r ;

irnport android . app . Activity;

irnport android . content . Intent ;

irnport android . content . SharedPre ferences ;

irnport android . graphics . Color ;

irnport android . graphics . Typeface ;

irnport android . os . Bundle ;

irnport android . pre ference . PreferenceManager ;

irnport android . text . rnethod . NumЬerKeyListene r ;

irnport android . view . Menu ;

irnport android . view . Menuitern;

irnport android . widget . EditText ;

irnport android . widget . Toast ;

puЬlic class EditorActivity extends Activity

static final int I DM OPEN 1 0 1 ; static final int I DM SAVE 1 0 2 ;

static final int I DM PREF 1 0 3 ;

static final int I DM EXIT 1 0 4 ;

private final static String FILENAМE

private EditText rnEdit ;

@ Override

puЬ1ic void onCreate ( Bund1e icic1e )

supe r . onCreate ( icic1e ) ;

setContentView ( R . 1ayout . rnain ) ;

" fi1e . txt " ;

rnEdit ( EditText ) findViewByid ( R . id . edit ) ;

@ Override

puЬlic void onResurne ( )

supe r . onResurne ( ) ;

307

Page 311: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

308

SharedPreferences prefs

PreferenceManager . getDe faultSharedPre ferences ( this ) ;

1 1 читаем установленное значение из CheckBoxPreference

Глава 14

if (prefs . getBoolean ( getString ( R . string . pr_openmode ) , false ) )

openFi le ( FILENAМE ) ;

@ Override

puЬlic boolean onCreateOptionsMenu (Menu menu) {

menu . add (Menu . NONE , I DM_OPEN , Menu . NONE , "Open" )

. seticon ( R . drawaЬle . ic_menu_open )

. setAlphabeticShortcut ( ' o ' ) ;

menu . add (Menu . NONE , I DM_SAVE , Menu . NONE , " S ave " )

. seticon ( R . drawaЬle . ic_menu_save )

. setAlphabeticShortcut ( ' s ' ) ;

menu . add (Menu . NONE , I DM_PREF, Menu . NONE , " Settings " )

. seticon ( R . drawaЬle . ic_menu_pre ferences )

. setAlphabeticShortcut ( ' t ' ) ;

menu . add (Menu . NONE , I DM_EXIT, Menu . NONE , " Exit " )

. seticon ( R . drawaЬle . ic_menu_exi t )

. setAlphabeticShortcut ( ' x ' ) ;

return ( supe r . onCreateOptionsMenu (menu ) ) ;

@ Ove rride

puЬl i c boolean onOptions itemSelected (Menuitem item)

switch ( item. getitemid ( ) )

case I DM OPEN :

openFi le ( FILENAМE ) ;

break; case I DM SAVE :

saveFile ( FI LENAМE ) ;

break ;

case I DM PREF :

Intent intent new Intent ( ) ;

intent . setCla s s ( this , PreferencesActivity . class ) ;

sta rtActivity ( intent ) ;

break;

case I DM EXIT :

finish ( ) ;

break ;

Page 312: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

Работа с файлами и сохранение пользовательских настроек

default :

return false ;

return t rue ;

private void openFile ( String fileName )

try

InputS tream inStream = openFileinput ( FI LENAМE ) ;

i f ( inStream null ) {

InputStreamReader tmp

new InputStreamReader ( inStream) ;

BufferedReader reader new BufferedReader ( tmp) ;

String str ;

StringBuffer buffer new StringBuffer ( ) ;

while ( ( str = reade r . readLine ( ) )

buffer . append ( str + " \n" ) ;

inStream . close ( ) ;

mEdit . setText ( buffer . toString ( } ) ;

catch ( ThrowaЬle t )

Toast . makeText ( getApplicationContext ( ) ,

nul l )

" Exception : " + t . toString ( ) , Toast . LENGTH_LONG )

. show ( ) ;

private void save File ( String Fi leName )

t ry {

OutputStreamWriter outStream =

new OutputStreamWriter ( openFileOutput ( FILENAМE , 0 ) ) ;

outStream . write (mEdit . getText ( ) . toString ( ) ) ;

outStream . close ( ) ;

catch ( ThrowaЬle t )

Toast . makeText ( getApplicationContext ( ) ,

" Exception : " + t . toString ( ) , Toast . LENGTH_LONG)

309

Page 313: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

310 Глава 14

. show ( ) ;

Скомпилируйте и запустите проект. В результате у вас получилась записная книжка с пока единственной опцией установки предпочтений (рис. 1 4 .5) .

Some text . . .

Sorпe text . . .

Sdve

0 Exlt

Рис. 1 4.5. Установка nред почтения-флажка CheckВoxPre ference

1 4.2 .3 . EditTextPreference

Каркас предпочтений в Aпdro id предоставляет также предпочтение с тексто­вым полем - EditText Preference. Это предпочтение позволяет фиксировать текст, вводим ый пользователем в свободной форме. Чтобы продемонстриро­вать работу этого элемента, добавим в наше приложение дополнительные возможности - в текстовом поле пользователь будет устанавливать размер шрифта для редактора.

Файл предпочтений для нашего приложения с дополнительным элементом <Edi tTextPreference> представлен в листинге 1 4 . 8 .

<Preference Screen

xmlns : android= "http : / / s chemas . android . com/apk/res/android">

Page 314: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

Работа с файлами и сохранение пользовательских настроек

<CheckBoxPreference

android : key= " @ string/pr_ope�ode "

android : title="Open file"

android : summary= " To open а file at start appl ication " / >

<EditTextPreference

android : key= " @ string/pr_s i z e "

android : title="Text S i z e "

android : summary= " Set text s i ze "

android : de faultValue= " l 4 "

android : dialogTitle="Enter text size ( from 1 0 to 32 ) " / >

< / PreferenceScreen>

31 1

В метод onResume ( ) добавим код для чтения установленного значения размера шрифта (листинг 1 4 .9).

@ Override

puЫ ic void onResume ( )

super . onResume ( ) ;

SharedPrefe rences prefs

PreferenceManager . get De faultSharedPreferences ( this ) ;

1 1 читаем открытия файла из CheckBoxPre ference

if ( pre fs . getBoolean ( getString ( R . string . pr_openmode ) , false ) )

openFile ( FILENAМE ) ;

1 1 читаем размер текста из EditTextPre ference

float fSize Float . parseFloat (

prefs . getString ( getString ( R . string . pr_s ize ) , " 2 0 " ) ) ;

/ 1 меняем настройки в EditText

mEdit . setTextSize ( fS i z e ) ;

Скомпилируйте и запустите проект. Теперь в нашем редакторе появилась оп­ция установки размера текста в виде диалогового окна с текстовы м полем ввода (рис. 1 4 .6) .

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

Page 315: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

312 Глава 1 4

Рис. 1 4.6 . Вызов nредnочтения EditText Preference

1 4.2 .4. ListPreference

Предпочтение ListPreference представляет собой диалоговое окно со спи­ском . Для формирования предпочтения требуется строкавый ресурс для заго­ловка диалогового окна и массив строк для списка значений . Индекс выбран­ной строки списка определяет, какое значение сохранено как предпочтение В SharedPreferences .

Для нашего приложения сделаем список для выбора стиля текста. В списке будет четыре опции : Regular, Bold, Italic, Bold+Italic. Для масси ва значений списка List Preference необходимо создать новый файл arrays .xml в каталоге res/values/. Содержимое файла представлено в листинге 1 4 . 1 О .

< ?xml version=" . 0 " encoding= " ut f- 8 " ?>

<resources >

<string-array name=" text_styl e " >

< itern>Regular< / item>

<item>Bold< / item>

<itern>Italic</ item>

<item>Bold+ Italic</ itern>

</string-array>

< / resources>

Page 316: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

Работа с файлами и сохранение пользовательских настроек 313

В файл preferences.xml добавим доnолнительный элемент <ListPreference>,

в котором оnределим атрибуты заголовка окна, nривязку к массиву значений и значение по умолчанию (листинг 1 4 . 1 1 ) .

<PreferenceScreen

xrnlns : android= "http : / /schemas . android . com/apk/ res /android" >

<CheckВoxPreference

android : key=" @ string/pr_openmode "

android : title="Open f i l e "

android : surmnary="To open а f i l e at start appl ication " / >

<EditTextPre ference android : key= " @ string/pr_s i z e "

android : title="Text S i z e "

android : surmnary=" Set text s i z e "

android : de faultValue=" 1 4 "

android : dialogTitle="Ente r text size ( from 1 0 t o 32 ) " />

<ListPre ference

android : key= " @ string/pr_style "

android : tit le="Text Styl e "

android : surmnary=" Set text style "

android : de faultValue=" l "

android : ent ries= " @ array/text_style "

android : entryValues=" @ array/text_styl e "

android : dialogTitle="Choose text styl e " / >

</ Pre ferenceScreen>

В листинге 1 4 . 1 2 nриводится код метода onResume ( ) .

@Override

puЬlic void onResume ( )

supe r . onResume ( ) ;

SharedPreferences prefs

PreferenceManager . getDefaultSharedPre ferences ( this ) ;

1 1 читаем открытия файла из CheckВoxPre ference

if ( prefs . getBoolean ( getString ( R . string . pr_openmode ) , false ) ) {

openFi le ( FILENAМE ) ;

Page 317: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

3 1 4

1 1 читаем размер текста из EditTextPreference

float fSize Float . parseFloat (

prefs . getString ( getSt ring ( R . st ring . pr_s i ze ) , " 2 0 " ) ) ;

1 1 читаем стили текста из ListPreference

St ring regular prefs . getString ( getString ( R . s t ring . pr_style ) ,

int type face Typeface . NORМAL ;

i f ( regular . contains ( "Bold" ) )

typeface += Typeface . BOLD ;

! i f ( regular . contains ( " Italic" ) )

type face += Typeface . ITALIC ;

меняем настройки в EditText

mEdit . setTextS i z e ( fS i ze ) ;

mEdit . setTypeface ( nul l , typeface ) ;

Флажок может быть включен ил и выключен пользователем.

Глава 1 4

Теперь при запуске приложения и выборе опции TextStyle появляется диалог выбора предпочтения для стиля текста (рис. 1 4 .7) .

Обратите внимание, что в диалоговом окне нет кнопки сохранения, только кнопка Cancel. Изменения сохраняются сразу при выборе опции списка.

Regu l a r

Bo ld

Рис . 1 4.7. Использование ListPrefe rence для выбора стиля текста

Page 318: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

Работа с файлами и сохранение пользовательских настроек 3 1 5

1 4.2 .5 . RingtonePreference

Предпочтение RingtonePreference - это специализированное предпочтение для установки мелодии звонка. В нашем приложении в использовании этого предпочтения особой необходимости нет, мы его добавим только для приме­ра (листинг 14 . 1 3 ) .

<PreferenceScreen

xmlns : android= " http : / /schernas . android . com/apk/ res /android" >

<CheckВoxPreference

android : key= " @ string/pr_openmode "

android : tit le= "Open f i l e " android : swnmary="To open а f i l e a t start application " / >

<EditTextPreference

android : key= " @string/pr_s i z e "

android : title="Text S i z e "

android : swnmary=" Set text s i ze "

android : de faultValue=" l 4 "

android : dialogTitle= " Enter text s i ze ( from 1 0 to 3 2 ) " / >

<ListPre ference

android : key= " @ s tring /pr_styl e "

android : t itle="Text Style"

android : swnma·ry=" Set text styl e "

android : de faultValue=" l "

android : entries=" @array/text_styl e "

android : entryValues=" @array/text_styl e "

android : dialogTitle= " Choose text styl e " / >

<RingtonePreference

android : key=" @string/pr_tone "

android : t itle= "Tone "

android : showDefault= " t rue"

android : showSi l ent= " t rue "

android : swnmary= " Set tone ( on or off ) " />

</PreferenceScreen>

Предпочтение <RingtonePre ference> предоставляет диалоговое окно выбора мелодии звонка со списком опций (рис. 1 4 . 8) .

Список в диалоговом окне отображает мелодии для звонка, уведомлений, то­нового набора, доступные на мобильном устройстве. При необходимости до­бавить тихий режим в элементе <RingtonePreference> предусмотрен атрибут

Page 319: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

3 1 6 Глава 1 4

android : showSilent, если его значение выставить в t rue, в списке мелодий появится дополнител ьная опция Silent.

Defa u l t r i ngtone

Рис. 1 4.8. Список RingtonePrefe rence

1 4.2 .6 . PreferenceCategory

Если приложение содержит м ного пользовательских предпочтений, иметь их всех в одном большом списке может стать неудобным для восприятия . Preferences Framework позволяет группировать предпочтения, распределяя их по категориям .

Категории добавляются через элемент <Preferencecategory> в ХМL-файле предпочтений и используются для группировки связанных предпочтений. Вместо того, чтобы иметь все предпочтения как дочерние записи корневого элемента <Preferencescreen>, можно поместить в ХМL-файл предпочтений дополнительные элементы <Prefe rencecategory> под корневым элементом <Preferencescreen>, а затем установить предпочтения в соответствующие ка­тегории .

Файл предпочтений, сгруппированный по категориям предпочтений, пред­ставлен в листинге 1 4 . 1 4 .

<PreferenceScreen xmlns : android= "http : / / s chemas . android . com/apk/res / android">

<Pre ferenceCategory android : t itle= " Open file rnode preferences " >

Page 320: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

Работа с файлами и сохранение пользовательских настроек

<CheckBoxPreference

android : key= " @ s tring/pr_openrnode "

android : title= " Open file"

android : sUI!U11ary="To open а file at start appl ication " / >

</ Prefe renceCategory>

<Pre ferenceCategory android : title= "Text preferences " > <EditTextPrefe rence

android : key= " @ string/pr_size"

android : title="Text S i ze "

android : sUI!U11ary= " Set text s i z e "

android : de faultValue= " l 4 "

android : dialogTitle="Enter text s i ze ( from 1 0 t o 3 2 ) " />

<ListPre ference

android : key= " @ string/pr_style"

android : title="Text Style"

android : sUI!U11ary= " Set text style "

android : de faultValue=" l "

android : entries=" @array/ text_styl e "

android : entryValues= " @array/text_styl e "

android : dialogTitle= " Choose text s tyle " />

< / Pre ferenceCategory>

< PreferenceCategory android : t itle="Other Prefe rences " >

<RingtonePreference

android : key= " @ string/pr_tone "

android : title= " Tone "

android : showDefault=" t rue "

android : showSilent=" t rue "

android : sUI!U11ary=" Set tone ( on or off) " />

< / PreferenceCategory>

</ Pre ferenceScreen>

31 7

Результатом применения предпочтения <Preferencecategory> является список элементов предпочтений, сгруппированных по категориям . Визуально это добавляет разделитель с заголовком категории между группами предпочте­ний, как на рис. 1 4 .9 .

1 4.2 . 7. PreferenceScreen

Корневой элемент <PreferenceScreen> позволяет вложение дочерних элемен­тов <Pre ferencescreen>. Любые дочерние записи вложенного элемента <PreferenceScreen> будут отображаться на отдельном экране. Родительский экран <PreferenceScreen> в этом случае будет отображать в своем списке предпочтений вход для запуска дочернего экрана nредпочтений.

Page 321: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

3 1 8 Глава 1 4

Рис. 1 4.9 . Груп п и ровка пред почте н и й с помощью Prefe renceCategory

Дополненный файл preferences .xml с дочерним окном предпочтений выбора цвета текста представлен в листи нге 1 4 . 1 5 .

< P refe rence Screen

xmlns : android= "http : / / s chema s . android . com/apk/ res / android" >

< Prefe renceCategory android : t i t l e= " Open f i l e mode pre fe rences " >

<CheckBoxPrefe rence

android : key= " @ s t r ing/pr_openmode "

android : t i tle="Open f i l e "

android : slШIП\ary="To open а f i l e at start appl ication " / >

< / Pre fe renceCategory>

< Prefe renceCategory android : t i t l e= " Text pre ferences " >

<Preference Sc reen

android : key= " @ s t ring /pr_co lor"

android : t i tle="Text Col o r "

android : s=a ry= " Set t e x t color"

<CheckBox P refe rence

android : key= " @ s t ring/pr_color_Ьlack"

andro id : t i t le="Black"

android : defaul tValue= " t rue "

android : slШIП\ary= " Se t Ы асk color " / >

Page 322: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

Работа с файлами и сохранение пользовательских настроек

<CheckBoxPreference

android : key= " @ st ring/pr_color red"

android : title="Red" android : sшrunary= " Set red color " />

<CheckBoxPreference android : key= " @ string/pr_color_green " android : tit le= "Green" android : sшrunary= " Set green color " / >

<CheckBoxPreference android : key= " @ st ring/pr_color_Ьlue " android : tit le="Blue " android : sшrunary= " Set Ьlue color " / >

< / PreferenceScreen> <EditTextPreference

android : key= " @ s tring/pr_s i z e " android : title= "Text S i ze " android : sшrunary= " Set text s i z e " android : de faultValue=" 1 4 " android : dialogTitle= " Enter text s i ze ( from 1 0 t o 32 ) " / >

<ListPre ference android : key= " @ string/pr_style" android : ti tle= " Text Style" android : sшrunary= " Set text styl e " android : de faultValue= " l " android : entries= " @ array/ text styl e " android : ent ryValues= " @array/text_styl e " android : dialogTitle= " Choose text style " / >

< / PreferenceCategory>

<Pre ferenceCategory android : title=" Othe r Preferences " > <RingtonePreference

android : key= " @ s tring/pr_tone " android : title= "Tone " android : showDefault=" true " android : showSi l ent= " t rue "

android : sшrunary=" Set tone ( on or off ) '' /> </PreferenceCategory>

< / PreferenceScreen>

3 1 9

Для экрана предпочтений выбора цвета текста необходимо добавить код об­работки выбора цвета в метод onResume ( ) класса Edi torActi vi ty. Выбор не­скольких цветов из группы суммирует значения каждого выбранного цвета, позволяя получить дополнительные цвета текста.

Измененный метод onResume ( ) класса Edi torActi vity представлен в листин­ге 1 4 . 1 6 .

Page 323: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

320 Глава 14

@Override

puЬlic void onResume ( )

supe r . onResume ( ) ;

SharedPreferences prefs

PreferenceManager . getDefaultSharedPreferences ( this ) ;

1 1 читаем открытия файла из CheckВoxPre ference

if ( pre fs . getBoolean ( getString ( R . string . pr_openmode ) , false ) )

openFi le ( FILENAМE ) ;

1 1 читаем размер текста из EditTextPreference

float fSi z e Float . parseFloat (

pre fs . getString ( getString ( R . string . pr_s i z e ) , " 2 0 " ) ) ;

1 1 читаем цвет текста из CheckВoxPreference

11 и суммируем значения для получения дополнительных цветов текста

int color Color . BLACK;

i f ( prefs . getBoolean ( getString ( R . string . pr_color_red) , false ) )

color += Color . RE D ;

i f (pre fs . getBoolean ( getSt ring ( R . string . pr_color green ) , false ) )

color += Color . GREEN ;

i f ( p refs . getBoolean ( getString ( R . string . pr_color Ьlue ) , false ) )

color += Color . BLUE ;

float fSize Float . parseFloat (

pre fs . getString ( getString ( R . string . pr_s i z e ) , " 2 0 " ) ) ;

1 1 читаем стили текста из ListPreference

String regular = prefs . getString ( getString ( R . string . pr_style ) ,

int typeface Typeface . NORМAL;

i f ( regular . contains ( "Bold" ) )

type face += Typeface . BOLD ;

i f ( regular . contains ( " Ital i c " ) )

typeface += Typeface . ITALI C ;

Page 324: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

Работа с файлами и сохранение пользовательских настроек

1 1 меняем настройки в EditText

mEdi t . s e tText S i ze ( fS i ze ) ;

mEdi t . s e tTextColor ( color ) ;

mEdi t . setType face ( nul l , type face ) ;

321

Окончательный вид приложения со всеми созданными в этой главе предпоч­тениями и отдельным входом T�xt Color для дочернего окна предпочтений по казан на рис . 1 4 . 1 О .

Рис. 1 4. 1 0 . Добавление дочернего контейнера Prefe rence Screen для выбора цвета текста

Page 325: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

ГЛ А В А 1 5

База дан н ых SQLite и контент-п ровайдеры

В этой главе рассматривается работа со встроенной базой данных SQLite и организация доступа к данным с помощью контент-провайдеров .

Контент-провайдер - один из четырех фундаментал ьных компонентов Аndrоid-приложений, которы й обеспечивает информационное наполнение для приложений. Контент-провайдер нужен, если есть необходимость совме­стного использования данных между приложениями . Если вы не собираетесь давать данные другим приложениям, можете работать с данными непосред­ственно через классы, предоставляющие интерфейс для взаимодействия с ба­зой данных SQLite.

1 5. 1 . База дан н ых SQLite Платформа Android предоставляет функции управления базой данных, кото­рые позволяют сохранять сложные коллекции данных. Aпdroid также постав­ляется с инструментом управления базой данных sq l iteЗ , которы й дает воз­можность просматривать содержание таблиц, выпол нять команды SQL и исполнять другие полезные функции на базах данных SQLite .

Все базы данных, SQLite и другие, сохраняются на устройстве в каталоге /dataldatalpackage_name/ базы данных. SQLite хранит всю базу данных (вклю­чая определения, таблицы, индексы и данные) в единственном стандартном файле . Библиотеки Android обеспечивают набор классов для создания и управления базами данных SQLite.

1 5 . 1 . 1 . Создание базы дан н ых: класс SQLiteOpenHelper

В библиотеке Android есть класс SQLiteOpenHe lper для создания базы данных. Класс SQLiteOpenНe lper содержит два абстрактных метода:

Page 326: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

324

D onCreate ( ) - вызывается при первом создании базы данных;

D onUpgrade ( ) - вызывается при модификации базы данных.

Глава 1 5

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

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

В этом же классе принято объявлять открытые строкавые константы для названия таблиц и полей создаваемой базы данных, которые клиенты могут использовать для определения столбцов при выпол нении запросов к базе данных. Тщательно документируйте тип данных каждого столбца, т. к. кли­енту требуется эта информация для обращения к данным. Например, так можно объявить константы для таблицы Contact:

puЬlic static final String ТАВLЕ_NАМЕ = " contact " ; puЬlic static final String NАМЕ " first_name " ; puЬlic static final St ring PHONE "phone " ;

Ваш класс, расширяющий SQLiteOpenНelper, также неявно наследует интер­фейс вasecolшnns, в котором определена строковал константа _I D, представ­ляющая имя поля для идентификаторов записей . В создаваемых таблицах ба­зы даННЫХ ПОЛе ID ДОЛЖНО иметь ТИП INTEGER PRIМARY КЕУ AUTOINCREMENT.

Описатель AUTOINCREМENT является необязательным.

В методе обратного вызова onCreate ( ) необходимо реализовать логику соз­дания таблиц и при необходимости заполнить их начальными данными, на­пример:

@Override

puЬlic void onCreate ( SQLiteDatabase dЬ ) { dЬ . execSQL ( "CREATE ТАВLЕ + ТАВLЕ _ NАМЕ

+ (_id INTEGER PRIМARY КЕУ AUTOINCREМENT ,

+ COL NАМЕ + ТЕХТ , + COL PHONE + ТЕХТ ) ; " ) ;

Метод onUpdate ( ) вызывается при установке обновлений программы с изме­ненной структурой таблиц. В методе обратного вызова onUpgrade ( ) можно, например, реализовать запрос в базу данных на уничтожение таблицы (DROP

ТАВLЕ), после чего вновь вызвать метод onCreate ( ) для создания версии таб­лицы с обновленной структурой, например, так:

@ Override puЬlic void onUpgrade ( SQLiteDatabase dЬ , int oldVersion, int newversion) {

dЬ . execSQL ( " DROP ТАВLЕ IF EXI STS onCreate ( dЬ ) ;

+ ТАВLЕ NАМЕ ) ;

Page 327: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

База данных SQLite и контент-провайдерьt . 325

В реальном приложении изменение структуры базы данных и ее таблиц, ко­нечно, должно происходить без потери пользовательских данных.

1 5. 1 .2 . Управление базой данных: класс SQLiteDatabase

В библиотеке Android для управления базой данных SQLite существует класс SQLiteDatabase. В классе SQLiteDatabase определены методы для чтения, до­бавления, удаления, изменения данных.

Для чтения данных используют вызов метода query ( ) :

Cursor query ( String taЬle , String [ ] columns ,

St ring selection, String [ ] se lect ionArgs ,

St ring groupBy, String having , String sortOrde r )

В метод que ry ( ) передают семь параметро в :

D taЬle - имя таблицы, к которой передается запрос;

D columns - список имен возвращаемых полей. При передаче nul l возвра­щаются все столбцы ;

D select ion - параметр, формирующий выражение WHERE (исключая сам оператор WHERE) . Значение nul l возвращает все строки;

D se lectionArgs - значения аргументов фильтра;

D groupBy ---, параметр, формирующий выражение GROUP ВУ (исключая сам оператор GROUP ВУ) . Если GROUP ВУ не нужен, передается nu1 1;

D having - параметр, формирующий выражение НAVING (исключая сам опе­ратор НAVING) . Если не нужен, передается nu1 1;

D sortOrde r - параметр, форматирующий выражение ORDER ВУ (исключая сам оператор ORDER ВУ) . При сортировке по умолчанию передается nul l .

Объект Cursor, возвращаемый методом query ( ) , обеспечивает доступ к набо­ру записей результирующей выборки . Для обработки возвращаемых данных объект Cursor имеет набор методов для чтения каждого типа данных ­getSt ring ( ) , get int ( ) И getFloat ( ) .

Для вставки новой записи в базу данных SQLite используется метод insert ( ) :

long insert ( St ring taЬle , St ring nullColumnHack, ContentValues values )

В метод insert ( ) необходимо передать три параметра:

D taЬle - имя таблицы, в которую будет вставлена запись;

D nul lColumnHack - в базе данных SQLite не разрешается вставлять пол­ностью пустую строку, и если строка, полученная от клиента контент-

Page 328: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

326 Глава 1 5

провайдера, будет пустой, то только этому столбцу явно будет назначено значение null;

О values - карта отображений (класс Мар и его наследники), передаваемая клиентом контент-провайдера, которая содержит пары ключ-значение. Ключи в карте должны быть названиями столбцов таблицы, значения ­вставляемыми данными .

Метод insert ( ) возвращает идентификатор _I D вставленной строки ил и - 1 в случае ошибки.

Для обновления и удаления записей в базе данных используют соответствен­но методы update ( ) и delete ( ) :

int update ( String taЬle , ContentValues values ,

String whereClaus e , String [ ] whereArgs )

int delete ( St ring taЬle , String whereClause , String [ ] whereArgs )

В этих методах два последних параметра формируют SQL-выражение WHERE

аналогично рассмотренному методу query ( ) для чтения данных. Эти методы возвращают число модифицированных или удаленных строк.

Кроме вышеперечисленных методов, в этом классе также определены раз­личные методы для выполнения других общих задач управления базой дан­ных.

1 5 .2 . Контент-п ровайдеры Контент-провайдеры поддерживают стандартный синтаксис запросов для чтения, изменения, вставки и удаления данных. Контент-провайдеры - это единственный способ совместного использования данных между приложе­ниями в Android .

Если необходимо предоставить доступ к своим данных для других приложе­ний, существует два варианта:

О создать собственный контент-провайдер, ContentProvider;

как подкласс класса

О добавить данные к существующему пронайдеру - если уже есть провай­дер, который управляет теми же данными и вы имеете разрешение для ра­боты с этими данными .

Все контент-провайдеры предоставляют общий интерфейс для запросов дан­ных клиентскими приложениями - на чтение, добавление, изменение и уда­ление данных.

Объект ContentProvider не используется напрямую. Клиентские приложе­ния используют контент-провайдеры косвенно, обычно через объект

Page 329: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

База данных SQLite и контент-провайдеры 327

ContentRe s o lver. Получить ContentResolve r можно через вызов метода getContentResol ver ( ) в· классе деятельности или другого компонента Аndrоid­приложения:

ContentResolve r resolver getContentResolve r ( ) ;

Вы можете использовать методы ContentRes olver для взаимодействия с лю­быми контент-провайдерами, которые доступны и требуются для работы приложения с данными .

После инициализации запроса система Android идентифицирует контент­провайдер, который является адресатом запроса и его реализацией. Система сама инициализирует все объекты Content Provider, и вам нет необходимости делать это самостоятельно.

Фактически, приложение никогда не имеет дело непосредственно с объекта­ми content Provide r. Как правило, есть только единственный экземпляр каж­дого типа ContentProvider, но он может связываться с многочисленными объектам и ContentRes olver в различных Приложениях и процессах. Взаимо­действие между процессами обрабатывается классами Content Provide r и ContentResol ver.

1 5.2 . 1 . Модел ь дан ных

Контент-провайдеры представляют данные в виде плоской таблицы, где каж­дая строка - запись, а каждый столбец - данные специфического типа и значения . Каждая запись обязательно включает числовое поле _ I D, которое уникально идентифицирует запись в пределах таблицы. Идентификаторы мо­гут использоваться для соответствия строк в связанных таблицах - напри­мер, находить номер телефона человека в одной таблице и фотографию того же человека в другой .

Запрос возвращает объект Cursor, который может перемещаться по записям, чтобы делать запись, и от столбца к столбцу, чтобы читать содержание каждо­го поля . Это специализировало методы для того, чтобы читать кажды й тип данных. Так, чтобы читать поле, вы должны знать, какие данные поле содержит.

1 5.2 .2 . U RI

Каждый контент-провайдер предоставляет открытый URI (обернутый как объект uю), что уникально идентифицирует его набор данных. Контент­провайдер, который управляет м ножественными наборами данных (множест­венные таблицы), должен предоставлять отдельные URI для каждого набора данных. Все U RI для провайдеров начинаются со строки " content :

Page 330: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

328 Глава 1 5

При оnределении контент-nровайдера, как nравило, оnределяют константу для URI . Andro id оnределяет константы URI для всех nровайдеров, которые идут с nлатформой. Вот, например, URI для таблицы телефонных звонков:

android . provide r . CallLog . Calls . CONTENT_URI

Константа URI используется во всех взаимодействиях с контент-nровайдером. Каждый метод класса ContentResol ver берет URI как первый nараметр. URI -это то, что идентифицирует провайдера, к которому объект ContentResolver

будет обращаться .

Константа URI состоит из четырех частей, которые nоказаны на рис. 1 5 . 1 .

content://com .sam ples.contactprovider/contacts/1 33

'----v--1 '-----у----____.., '--v-i у А в с D

Рис. 1 5. 1 . Части конста нты URI

Эти части URI предоставляют следующие сведения :

D А - стандартны й nрефикс, указывающий, что данные nредоставляются контент-nровайдером . Этот nрефикс никогда не изменяется;

D В - часть URI , который идентифицирует контент-провайдер. Для сторон­них nриложений он должен быть и менем пакета и класса (в нижнем реги­стре), чтобы гарантировать свою уникальность среди других uю;

D С - путь, который контент-провайдер использует, чтобы оnределить тре­буемые наборы данных. Если контент-nровайдер предоставляет только один тип данных, эта часть URI может отсутствовать. Если провайдер nре­доставляет данные нескольких типов, включая и подтипы, то эта часть URI

будет, например, выглядеть так: contacts /photos или contacts/bi rthday;

D D - идентификатор конкретной записи. Это и есть _ ш заnиси. Если за­прос не ограничивается одной записью, эта часть URI проnускается :

content : / /com. samples . contactprovider/contacts

1 5 .3 . Создан ие контент-п ровайдера Чтобы создать контент-провайдер, необходимо предnринять следующие шаги :

1 . У становить базу данных.

2 . Создать расширенный класс Contentprovider для обеспечения достуnа к данным.

3 . Объявить контент-nровайдер в файле манифеста nриложения.

Page 331: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

База данных SQLite и контент-провайдеры 329

1 5.3 . 1 . Расширение класса ContentProvider

В клиентском приложении запрос производится через объект ContentResolver,

при этом система анализирует U RI и передает запрос этому контент­провайдеру. В классе также необходимо определить константу URI . Если про­вайдер имеет связанные таблицы, необходимо определ ить константы CONTENT _ URI для каждой из таблиц. Все эти URI должны иметь одинаковые полномочия (т. к. они идентифицируют контент-провайдер) и отличаться друг от друга только их путями . Например:

content : / /com . samples . contactprovider/contacts content : / /com. samples . contactprovider/contacts /photos

В классе, наследуемом от contentProvider, необходимо реализовать следую­щие методы :

О query ( ) - для возвращения данных вызывающей программ е;

О insert ( ) - для вставки новых данных в контент-провайдер;

О update ( ) - для обновления существующих данных в контент-провайдере;

О delete ( ) - для удаления данных в контент-провайдере;

О getType ( ) - для возвращения типа MIME данных в контент-провайдере.

В методе обратного вызова onCreate ( ) , который вызывается системой при создании экземпляра контент-провайдера, инициализируется объект SQLiteDatabase:

private SQLiteDatabase dЬ;

@ Override puЬlic boolean onCreate ( )

dЬ ( new ContactDbHelper ( getContext ( ) ) ) . getWritaЬleDatabase { ) ; return ( dЬ nul l ) false true ;

Методы query ( ) , insert ( ) , update ( ) , delete ( ) , которые требуется реализовать в классе, производнам от content Provider, предоставляют клиенту контент­провайдера тонкую оболочку над одноименными методами класса SQLiteDatabase, которые мы рассматривали в разд. 15. 1 .2 . Фактически, кон­тент-провайдер инкапсулирует от приложения-клиента саму базу данных.

Реализация метода que ry ( ) в классе, производнам от ContentProvider, может выглядеть так:

@Override puЬlic Cursor query (Uri uri , String [ ] proj ect ion,

String selection, String [ ] selectionArgs , String sort ) {

SQLiteQueryBuilder qb = new SQLi teQueryBuilder ( ) ;

Page 332: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

330

qb . setTaЬles ( ContactDbHelper . TAВLE_NAМE ) ;

qb . setProj ectionМap (mContactMap ) ;

1 1 непосредственный запрос к БД Cursor с qb . query ( dЬ , proj ection, selection, selectionArgs ,

nul l , nul l , sort ) ;

c . setNotificationUri ( getContext ( ) . getContentResolver ( ) , uri ) ;

return с ;

Глава 1 5

Реализация метода insert ( ) для вставки данных может выглядеть следую­щим образом :

@Override

puЬlic Uri insert ( Uri url , ContentValues inValues )

ContentValues values new ContentValues ( inValues ) ;

1 1 непосредственная вставка данных в БД long rowid dЬ . insert (

CoпtactDbHelper . TAВLE_NAМE , ContactDbHelper . NAМE , values ) ;

1 1 получаем URI новой записи по rowid

Uri uri ContentUris . withAppendedid ( CONTENT_URI , rowid ) ;

getContext ( ) . getContentResolver ( ) . noti fyChange ( uri , nul l ) ;

return uri ;

Метод insert ( ) возвращает клиенту контент-провайдера URI вставляемой строки (с присвоеиным ей идентификатором в конце).

Пример реализации метода update ( ) для модификации данных и метода delete ( ) для удаления данных может выглядеть следующим образом :

@Override

puЬl ic int update ( Uri uri , ContentValues values ,

String where, String [ ] whereArgs ) {

1 1 модифицируем данные int retVal dЬ . update (

ContactDbHelper . TAВLE_NAМE , values , where , whe reArgs ) ;

getContext ( ) . getContentResolver ( ) . noti fyChange ( uri , nul l ) ;

return retVal ;

Page 333: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

База данных SQLite и контент-провайдеры 33 1

@Override puЬlic int delete ( Uri url , String where , String [ ] whereArgs )

int retVal dЬ . delete ( ContactDbHelper . TAВLE_NAМE , where , whereArgs ) ;

getContext ( ) . getContentResolver ( ) . noti fyChange ( url , null ) ;

return retVal ;

Эти методы возвращают в клиентское nриложение количество модифициро­ванных или удаленных строк.

Поскольку все вышеnеречисленные методы ContentProvider можно вызывать из разных объектов ContentResolver в разных nроцессах и nотоках, они должны быть реализованы nотокобезоnасным сnособом .

1 5.3 .2 . Деклари рование контент-провайдера в файле ман ифеста

Чтобы система Android могла узнать о контент-nровайдере, который вы раз­работали, необходимо задекларировать его в элементе <provider> в файле AndroidManifest.xml . Контент-nровайдеры, которые не объявлены в деклара­ции, не видимы в системе Android, и обращение к ним сгенерирует исключе­ние во время выnолнения nрограммы .

Наnример, для нашего nриложения для работы с контактами элемент <provider> мог бы выглядеть следующим образом :

<provide r

android : name=" . ContactProvider "

android : authorities= " com . samples . dЬcontacts . contactprovider " >

</provider>

Атрибут android : name - это nолное имя nодкласса ContentProvider. Атрибут android : authorities - часть authority константы URI, которая идентифици­рует данный контент-nровайдер .

Другие атрибуты элемента <provider> могут устанавливать разрешения для чтения и заnиси данн ых, устанавливать значок и текст, который отображен nользователю, включать и отключать nровайдер и т. д.

1 5.4. Зап росы к контент-п ровайдеру Чтобы сделать заnрос к контент-nровайдеру из клиентского nриложения, не­обходимо три обязательных nараметра: URI , который идентифицирует nро­вайдера, имена заnрашиваемых nолей данных и тиnы данных для этих nолей.

Page 334: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

332 Глава 1 5

Если вы запрашиваете отдельную запись, также необходим идентификатор этой записи. Рассмотрим теперь процесс создания запросов к контент­провайдеру.

1 5.4 .1 . Чтение возвращаемых значен и й

Чтобы сделать запрос к контент-провайдеру, в клиентском приложении ис­пользуют МеТОДЫ ContentResolver . query ( ) ИЛ И Activity . managedQuery ( ) :

Cursor query ( Uri uri , String [ ] proj ection, String selection, String [ ] selectionArgs , String sortOrde r )

Cursor managedQuery ( Uri uri , String [ ] proj ection, String select ion , String [ ] selectionArgs , String sortOrde r )

Оба метода принимают один и тот же набор параметров и возвращают объект Cursor. Однако метод managedQuery ( ) заставляет деятельность управлять цик­лом жизни объекта cursor аналогично жизненному циклу самой деятель­ности .

Эти методы имеют одинаковый набор параметров. Первые два параметра яв­ляются обязательными :

О URI провайдера - это константа CONTENT _ uю, которая идентифицирует конкретный объект Content Provider и набор данных. Существуют некото­рые вспомогательные методы для формирования URI, в частности ContentUris . wi thAppendedid ( ) и Uri . wi thAppendedPa th ( ) , которые добавля­ют в конец URI идентификатор записи. Это статические методы класса ContentUris, которые возвращают объект Uri с добавленным в конце идентификатором записи;

О имена полей данных, которые вы хотите получить из БД.

Следующие два параметра в методе - это детализация фильтра для запроса, отформатированная как SQL-предложение WНERE (исключая сам оператор WHERE непосредственно). Значение nul l в этих параметрах возвращает все строки, если только U RI сам не ограничивает запрос единственной записью. Чтобы ограничить запрос только одной конкретной записью, вы можете до­бавить значение ш записи.

Запрос возвращает набор записей из базы данных. Имена столбцов, их типы и заданный по умолчанию порядок сортировки данных являются специфиче­ским и для каждого контент-провайдера. Но каждый контент-провайдер имеет столбец _ I D, который содержит уникальный числовой идентификатор для каждой записи. Каждый провайдер может также сообщить о количестве воз­вращаемых записей через поле _ COUNT.

Последний параметр определяет порядок сортировки записей, как в SQL­oпepaтope ORDER ВУ. Если в параметр передать значение null, выборка будет

Page 335: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

База данных SQLite и контент-провайдеры 333

отсортирована по умолчанию. Порядок сортировки по умолчанию определя­ют заранее, в реализации класса SQLiteOpenHelper. Пример фрагмента кода для получения выборки данных:

11 массив имен полей, которые мьr хотим получить private static final String [ ] rnContent new String [ ]

ContactDbHelper . I D ,

ContactDbHelpe r . NAМE ,

ContactDbHelpe r . PHONE } ;

Cursor cursor

Cursor cursor rnanagedQuery ( ContactProvider . CONTENT_URI , rnContent , nul l , nul l , nul l ) ;

1 5.4.2. Пози цион ирование курсора

Объект cursor может использоваться для перемещений назад или вперед по выборке данных. У экземпляров типа cursor есть встроенное понятие пози­ции, похожей на Jаvа-интерфейс Iterator. Чтобы получить требуемые записи из выборки, можно использовать нескол ько методов для позиционирования курсора :

D rnoveToFi rst ( ) - перемещает курсор в первую запись в выборке;

D rnoveToLast ( ) - перемешает курсор в последнюю запись в выборке;

D rnoveToNext ( ) - перемешает курсор в следующую запись и одновременно определяет, существует ли эта запись. Метод rnoveToNext ( ) возвращает t rue, если курсор указывает на другую строку после перемещения, и false,

если текущая запись была последней в выборке;

D rnoveToPrevious ( ) - перемешает курсор в предыдущую запись;

D rnoveToPos i tion ( ) - перемешает курсор в указанную позицию;

D get Pos ition ( ) - возвращает текущий индекс позиции курсора.

Кроме вышеперечисленных методов у курсора есть еще и набор условных методов для определения позиции курсора в выборке :

D i s First ( ) ;

О i sLast ( ) ;

О isBeforeFi rst ( ) ;

D i sAfterLast ( ) .

Эти методы могут использоваться в программнам коде для проверки место­нахождения позиции курсора.

Page 336: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

334 Глава 1 5

1 5.4.3 . Добавление записей

Чтобы добавить новую запись в контент-провайдер, сначала надо создать объект Мар - карту с парами ключ-значение в объекте ContentValues, где каждый ключ соответствует имени столбца в контент-провайдере, а значе­ние - конкретны м данным для новой записи в этом столбце. После этого вызывается метод ContentResolve r . insert ( ) , которому надо передать URI провайдера и созданный объект contentValues . Этот метод возвращает пол­ный URI новой записи - т. е. URI контент-провайдера с добавленным в конце строки идентификатором для новой записи.

Вы можете использовать возвращаемый U RI , чтобы сделать новый запрос и получить уже обновленную выборку данных. Например, код для добавле­ния новой записи может выглядеть так:

ContentValues values new ContentValues ( 2 ) ;

формируем данные для вставки values . put ( ContactDbHelper . NAМE , textName . getText ( ) . toString ( ) ) ; values . put ( ContactDbHelper . PHONE , textPhone . getText ( ) . toString ( ) ) ;

вставляем данные getContentResolver ( ) . insert ( Contact Provider . CONTENT_URI , values ) ;

обновляем выборку cursor . reque ry ( ) ;

1 5.4.4. Изменение записи

Содержащуюся в записи информацию можно изменить, используя вызов ме­тода update ( ) . Например, так :

ContentValues values new ContentValues ( 2 ) ;

values . put ( ContactDbHelpe r . NAМE , textName . getText ( ) . toString ( ) ) ; values . put ( ContactDbHelper . PHONE , textPhone . getText ( ) . toString ( ) ) ;

getContentResolver ( ) . update ( ContactProvider . CONTENT_URI , values ,

1 5.4.5. Удаление записей

I D= " i d , nul l ) ;

Чтобы удалить единственную запись, вызовите метод ContentResol ver .

delete ( ) с U RI удаляемой строки . Например, так:

getContentResolver ( ) . delete (ContactProvider . CONTENT_URI ,

cursor . requery ( ) ;

ID=" + id, null ) ;

Page 337: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

База данных SQLite и контент-провайдеры 335

Чтобы удалить множество записей, необходимо вызвать метод ContentResol ver . delete ( ) с SQL-определением WHERE, в котором следует ука­зать условие для удаления выбранных строк.

1 5.5 . П ракти ческое п риложение для работы с базой дан н ых Реализуем приведенную ранее методику работы с данными в практическом приложении для редактирования контактов . Это приложение по функцио­нальности похоже на приложение для работы с контактами из главы 1 1 . Теперь мы разработаем приложение с такой же функциональностью, рабо­тающее с базой данных.

Создайте в Ecl ipse новый проект и в окне Create New Project введите сле­дующие значения:

С] Project name - contactEdi tor;

С] Application name - Contacts Sample;

С] Package name - сот . samples . contacteditor;

С] Create Activity - ListContactActivity.

В файле манифеста приложения необходимо зарегистрировать в элементе <provider> наш контент-провайдер. Содержимое файла манифеста представ­лено в листинге 1 5 . 1 .

< ?xml version= " . 0 " encoding= " ut f- 8 " ?>

<mani fest xmlns : android="http : / / s chemas . android . com/apk/ res /android"

package= "com . s amples . dЬcontacts " >

<appl ication android : label=" @ st ring/app_name " >

<provider

android : name=" . ContactProvider"

android : authorities= " com . samples . dЬcontacts . ContactProvide r " / >

<activity

android : name= " . ContactActivity"

android : label=" @ st ring/app_name " >

<intent-filter>

<action android : name="android . intent . action . МAIN " / >

<category android : name="android . intent . category . LAUNCHER" />

</ intent-filter>

Page 338: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

336

< /activity>

</application>

< /manifest>

Файл разметки деятельности main .xml представлен в листинге 1 5 .2 .

<?xml vers ion= " l . O " encoding="utf- 8 " ?>

<RelativeLayout xmlns : android="http : / /schernas . android . com/apk/ res /android"

android : orientation="horizontal "

android : layout_width=" fi l l_parent "

android : layout_height= " fi l l_parent " >

<TextVie1-1

android : id=" @ +id/narne "

android : layout_width= "wrap_content "

android : layout_height= "wrap_content "

android : layout_alignParentLeft= " t rue "

android : textS i ze= " l 8 sp " / >

<TextView

android : id=" @ +id/phone "

android : layout_width="wrap_content "

android : layout_height= "wrap_content " android : layout_alignParentRight= " t rue "

android : textS i ze= " 1 8sp"

android : paddingRight=" l Opx" />

< /RelativeLayout>

Глава 1 5

Диалоговые окна для добавления нового контакта и модификации сущест­вующего контакта представляют собой нестандартные диалоги, для которых требуется создание собственной разметки. В диалогах кроме кнопок ОК и Cancel добавлены текстовые поля для имени и телефона. Код файла разметки для диалоговых окон nредставлен в листинге 1 5 .3 .

< ? xrnl vers ion= " l . O " encoding= " ut f- 8 " ?>

<LinearLayout xmlns : android="http : / /schemas . android . com/apk/res/android"

android : orientation="vertical "

android : layout_width= " fi ll_parent "

android : layout_height="wrap_content " >

Page 339: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

База данных SQLite и контент-провайдерьt

<LinearLayout

android : orientation="hori zontal "

android : layout_width= " fill_parent "

android : layout_height="wrap_content " >

<TextView android : text= " @ string / field_name "

android : layout_width="wrap_content "

android : layout_height="wrap_content "

android : layout_alignParentLeft= " t rue " / >

<EditText

android : id=" @ + id/name "

android : layout_width= " fi l l_parent " android : layout_height="wrap_content "

android : layout_alignParentRight=" t rue " />

</LinearLayout>

<LinearLayout

android : orientation= " horizontal "

android : layout_width=" fill_parent "

android : layout_height="wrap_content " >

<TextView

android : text= " @ string/ field_phone " android : layout_width="wrap_content "

android : layout_height="wrap_content " android : layout_alignParentLeft=" t rue " />

<EditText

android : id=" @ +id/phone " android : layout_width= " fi l l_parent "

android : layout_height="wrap_content "

android : layout_alignParentRight=" t rue " />

< / LinearLayout>

< /LinearLayout>

337

В файл strings.xml вынесены все надnиси для текстовых nолей и кноnок, имеющихся в nриложении (это nриложение мы исnользуем в следующей гла­ве nри создании локализованного nриложения с русским языком интерфей­са) . Код файла strings.xml nоказан в листинге 1 5 .4 .

< ?xml vers ion= " l . O " encoding="ut f- 8 " ?>

<resources>

<string name=" app_name " >Contacts from database sample</string>

<string name="btn_ok" >OK</string>

<string name="btn_cancel " >Cancel</string>

Page 340: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

338

<string name=" field_name " >Name : < /string>

<string name=" field_phone " > Phone : < /string>

<string name=" t itle_add">Add new Contact< /string>

<string name=" title_edit " >Edit Contact</string>

<string name=" title de lete " > Delete this Contact ?</st ring>

<string name="menu_add" >Add< /string>

<string name="menu_edi t " >Edit</string>

<string name="menu_delete " >Delete< / s tring>

<string name=" toas t_notify">Please select Contact ! </ string>

</ resources >

Глава 15

Класс ContactDbHelper, расширяющий класс SQLiteOpenHelper, представляет таблицу Contact базы данных. В нем объявлена структура таблицы и в методе oncreate ( ) производится создание таблицы и заполнение ее текстовыми дан­ными при первом запуске приложения на устройстве. Полный код класса ContactDbHelper приведен в листинге 1 5 . 5 .

package com . samples . dЬcontacts ;

import android . content . ContentValues ;

import android . content . Context ; import android . database . Cl!rso r ;

import android . database . sqlite . SQLiteDatabase ;

import android . database . sqlite . SQLiteOpenНelpe r ;

import android . provide r . BaseColumns ;

puЬlic class ContactDbHelper extends SQLiteOpenНelper

implements BaseColumns

puЬlic static final String ТАВLЕ NАМЕ " contact " ;

puЬlic static final String NАМЕ " first name " ; puЬlic s tati c final String PHONE "phone " ;

puЬl ic ContactDbHelper ( Context context ) {

supe r ( context , Contact Provider . DB_CONTACTS , null ,

@Override

puЬl ic void onCreate ( SQLiteDatabase dЬ ) {

dЬ . execSQL ( " CREATE ТАВLЕ + ТАВLЕ NАМЕ

+ (_ id INTEGER PRIМARY КЕУ AUTOINCREМENT , "

+ NАМЕ + " ТЕХТ , " + PHONE + " ТЕХТ ) ; " ) ;

Page 341: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

База данных SQLite и контент-провайдеры

ContentVa1ues va1ues new ContentVa1ues ( ) ;

va1ues . put ( NAМE , " Jacob Anderson " ) ;

va1ues . put ( PHONE , " 4 1 2 4 1 2 4 1 1 " ) ;

dЬ . insert ( TAВLE_NAМE , NАМЕ , va1ues ) ;

va1ues . put ( NAМE , "Emi 1y Duncan" ) ;

va1ues . put ( PHONE , " 1 6 1 8 63 1 8 7 " ) ;

dЬ . insert ( TAВLE_NAМE , NАМЕ , va1ues ) ;

va1ues . put (NAМE , "Michae1 Fu11er" ) ;

va1ues . put ( PHONE , "·8 9 6 4 4 3 65 8 " ) ;

dЬ . insert ( TAВLE_NAМE , NАМЕ , va1ues ) ;

va1ues . put ( NAМE , "Ermna Greenman " ) ;

va1ues . put ( PHONE , " 9 64 9 9 0 5 4 3 " ) ;

dЬ . insert ( TAВLE_NAМE , NАМЕ , va1ues ) ;

va1ues . put ( NAМE , " Joshua Harrison" ) ;

va1ues . put ( PHONE , " 7 5 92 8 5 08 6 " ) ;

dЬ . insert ( TAВLE_NAМE , NАМЕ , va1ues ) ;

va1ues . put ( NAМE , "Madi son Johnson" ) ;

va'Lues . put ( PHONE , " 95 0 2 8 5 7 7 7 " ) ;

dЬ . insert ( TAВLE_NAМE , NАМЕ , va1ues ) ;

va1ues . put ( NAМE , "Matthew Cotrnan" ) ;

va1ues . put ( PHONE , " 68 7 6 9 9 9 9 9 " ) ;

dЬ . insert ( TAВLE_NAМE , NАМЕ , va1ues ) ;

va1ues . put ( NAМE , "01ivia Lawson" ) ;

va1ues . put ( PHONE , " 1 6 1 8 63 1 8 7 " ) ;

dЬ . insert ( TAВLE_NAМE , NАМЕ , va1ues ) ;

va1ues . put ( NAМE , "Andrew Chaprnan" ) ;

va1ues . put ( PHONE , " 5 4 65 9 9 64 5 " ) ;

dЬ . insert ( TAВLE_NAМE , NАМЕ , va1ues ) ;

va1ues . put (NAМE , " Danie1 Honeyrnan" ) ;

va1ues . put ( PHONE , " 8 7 654 5 6 4 4 " ) ;

dЬ . insert ( TAВLE_NAМE , NАМЕ , va1ues ) ;

va1ues . put ( NAМE , " I sabe11a Jackson " ) ;

va1ues . put ( PHONE , " 90 7 8 6 8 7 5 6 " ) ;

dЬ . insert ( TAВLE_NAМE , NАМЕ , va1ues ) ;

339

Page 342: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

340

values . put (NAМE , "Will iam Patterson " ) ; values . put ( PHONE , " 68 7 6 9 9 6 9 3 " ) ; dЬ . insert ( TAВLE_NAМE , NАМЕ , values ) ;

values . put ( NAМE , " Joseph Godwin" ) ; values . put ( PHONE , " 9 6 5 4 67 5 7 5 " ) ;

dЬ . insert ( TAВLE_NAМE , NАМЕ , values ) ;

values . put ( NAМE , "Samantha Bush " ) ;

values . put ( PHONE , " 90 7 8 6 5 64 5 " ) ; dЬ . insert ( TAВLE_NAМE , NАМЕ , values ) ;

values . put (NAМE , " Christopher Gateman" ) ; values . put ( PHONE , " 8 9 68 7 4 55 6 " ) ; dЬ . insert ( TAВLE_NAМE , NАМЕ , values ) ;

@ Override

puЫ ic void onUpgrade (

SQLiteDatabase dЬ, int oldVers ion, int newVers ion) dЬ . execSQL ( " DROP ТАВLЕ I F EXI STS + ТАВLЕ_NАМЕ ) ;

onCreate ( dЬ ) ;

Глава 1 5

Класс ContactProvider, расширяющий базовый класс Content Provider, пред­ставляет логику доступа к содержимому базы данных Contacts. Полный код класса ContactProvider приведен в листинге 1 5 .6 .

package corn . samples . dЬcontacts ;

irnport j ava . ut i l . HashМap;

irnport android . content . ContentProvide r ; irnport android . content . ContentUri s ;

irnport android . content . ContentValues ;

irnport android . content . UriMatche r ;

irnport android . database . Curso r ; irnport android . database . SQLException ; irnport android . database . sqlite . SQLiteDatabase ;

irnport android . database . sqlite . SQLiteQueryBuilde r ;

Page 343: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

База данных SQLite и контент-провайдеры

import android . net . Uri ;

import android . text . TextUtils ;

puЫic class ContactProvider extends ContentProvider

puЬlic static fina l String DB_CONTACTS " contacts . dЬ " ;

puЬlic static final Uri CONTENT URI Uri . parse (

" content : / /com . samples . dЬcontacts . contactprovider /contact " ) ;

puЬlic static final int URI CODE 1 ;

puЬlic static final int URI_CODE_ID 2 ;

private static final UriMatcher mUriMatcher ;

private static HashМap<St ring , String> mContactMap ;

private SQLiteDatabase dЬ ;

static

mUriMatche r new UriMatcher (UriMatcher . NO МАТСН ) ;

mUriMatche r . addURI ( "com. samples . dЬcontacts . contactprovider " ,

ContactDbHelper . TAВLE_NAМE , URI_CODE ) ;

mUriMatche r . addURI ( "com . samples . dЬcontacts . contactprovider" ,

ContactDbHelper . TAВLE_NAМE + " /# " , URI_CODE_I D ) ;

mContactMap new HashМap<S tring , String> ( ) ;

mContactMap . put ( ContactDbHelper . I D , ContactDbHe lper . I D ) ;

mContactMap . put ( ContactDbHelper . NAМE , ContactDbHelper . NAМE ) ;

mContactMap . put ( ContactDbHelper . PHONE , ContactDbHelper . PHONE ) ;

puЬlic S tring getDbName ( )

return ( DB_CONTACT S ) ;

@Ove rride

puЬlic boolean onCreate ( )

34 1

dЬ ( new ContactDbHelper ( getContext ( ) ) ) . getWritaЬleDatabase ( ) ;

return ( dЬ nul l ) fa lse true ;

@ Override

puЬlic Cursor que ry ( Uri url , String [ ] proj ection,

String se lection, String [ ] selectionArgs , String sort ) {

Page 344: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

342

String orderBy ;

i f ( TextUt i l s . isEmpty ( sort ) )

orderBy = ContactDbHe lpe r . NAМE ;

else

orderBy sort ;

Cursor с dЬ . que ry ( ContactDbHelper . TAВLE_NAМE ,

proj ection, selection, selectionArgs ,

nul l , nul l , orderBy ) ;

Глава 1 5

c . setNot i ficat ionUri ( getContext ( ) . getContentResolve r ( ) , url ) ;

return с ;

@Override

puЬlic Uri insert ( Uri url , ContentVa lues inValues )

ContentValues values new ContentValues ( inValues ) ;

long rowid dЬ . insert (

ContactDbHelper . TAВLE_NAМE , ContactDbHelper . NAМE , va lues ) ;

i f ( rowid > 0 )

else

Uri uri ContentUris . withAppendedid ( CONTENT_URI , rowid ) ;

getContext ( ) . getContentResolve r ( ) . noti fyChange (uri , nul l ) ;

return uri ;

throw new SQLException ( " Fai led to insert row into + url ) ;

@Ove rride

puЬlic int delete ( Uri url , St ring where , S tring [ ] whereArgs )

int retVal dЬ . delete ( ContactDbHelpe r . TAВLE_NAМE , where , whereArgs ) ;

getContext ( ) . getContentResolver ( ) . noti fyChange (url , null ) ;

return retVal ;

Page 345: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

База данных SQLite и контент-провайдеры

@ Override

puЬlic int update (Uri ur1 , ContentVa 1ues va1ue s ,

String where , String [ ] whereArgs ) {

int retVa1 dЬ . update ( ContactDbHe1pe r . TAВLE_NAМE , va1ues ,

343

where , whereArgs ) ;

getContext ( ) . getContentReso1ver ( ) . noti fyChange (ur1 , nu1 1 ) ;

return retVa1 ;

@Ove rride

puЬlic S tring getType (Uri uri )

return nu1 1 ;

Класс деятельности NewContactActivity предназначен для просмотра данных и имеет меню из трех пунктов - Add, Edit и Delete - для добавления, модификации и удаления данных соответственно. Код класса NewcontactActivity представлен в листинге 1 5 . 7 .

package com . samp1es . dЬcontact s ;

import android . app . A1ertDia1og ;

import android . app . ListAct ivity;

import android . content . ContentVa1ues ;

import android . content . Dia1oginte rface ;

import android . database . Cursor ;

import android . os . Bund1e ;

import android . view . Layout inf1ater ;

import android . view . Menu ;

import android . view . Menuitem;

import android . view . View ;

import android . widget . EditText ;

import android . widget . ListAdapte r ;

import android . widget . Simp1eCursorAdapte r ;

import android . widget . Toast ;

puЬlic c1ass ContactActivity extends ListActivity

private static fina1 int I DM ADD 1 0 1 ;

private static fina1 int I DM EDIT 1 0 2 ;

private static fina1 int I DM DELETE = 1 0 3 ;

Page 346: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

344

private Cursor mCurso r ;

private ListAdapter mAdapter ;

private static final St ring [ ] mContent new S tring [ ]

Contact DbHelper . _I D , ContactDbHelper . NAМE ,

ContactDbHelper . PHONE } ;

@ Override

puЬlic void onCreate ( Bundle savedinstanceState )

supe r . onCreate ( savedinstanceState ) ;

mCursor = managedQuery (

Глава 1 5

Contact Provider . CONTENT_URI , mContent , nul l , nul l , nul l ) ;

mAdapter new S impleCursorAdapter ( this ,

R . layout . row, mCursor,

new String [ ] { ContactDbHelper . NAМE , ContactDbHelper . PHONE } ,

new int [ ] { R . id . name , R . id . phone } ) ;

setListAdapter (mAdapter ) ;

@ Override

puЬlic boolean onCreateOpt ionsMenu ( Menu menu )

menu . add (Menu . NONE , I DM_ADD , Menu . NONE , . R . string . menu_add)

. setlcon ( R . drawaЬle . ic_menu_add )

. setAlphabeticShortcut ( ' a ' ) ;

menu . add (Menu . NONE , I DM_EDIT , Menu . NONE , R . string . menu_edit )

. setlcon ( R . drawaЬle . ic_menu_edi t )

. setAlphabeticShortcut ( ' e ' ) ;

menu . add (Menu . NONE , I DM_DELETE , Menu . NONE , R . string . menu_delete )

. seticon ( R . drawaЬle . ic_menu_delete )

. setAlphabeticShortcut ( ' d ' ) ;

return ( super . onCreateOptionsMenu (menu ) ) ;

@ Ove rride

puЬlic boolean onOptions itemSelected (Menultem item)

final long id this . getSelecteditemid ( ) ;

switch ( item . getltemld ( ) )

case I DM_ADD : {

CallAddContactDialog ( ) ;

brea k ;

Page 347: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

База данных SQLite и контент-провайдеры

case I DM EDIT : i f ( id > 0 )

CallEditContactDialog ( id) ;

else

345

Toast . rnakeText ( this , R . string . toas t_notify, Toast . LENGTH_SHORT )

. show ( ) ;

break;

case I DM DELETE :

i f ( id > 0 ) {

Ca llDeleteContactDialog ( id ) ;

else Toast . rnakeText ( this , R . string . toast_noti fy ,

Toast . LENGTH_SHORT )

. show ( ) ;

break ;

return ( supe r . onOptions iternSelected ( itern) ) ;

private void CallAddContactDialog ( ) {

Layoutinflater inflate r tayoutinflater . frorn ( this ) ;

View root inflate r . inflate ( R . layout . dialog, nul l ) ;

final EditText textNarne ( EditText ) root . findViewByid ( R . id . narne ) ;

final EditText textPhone ( EditText ) root . findViewByid ( R . id . phone ) ;

Ale rtDialog . Builder Ь new AlertDialog . Builder ( this ) ; b . setView ( root ) ;

b . setTitle ( R . s t ring . title_add) ;

b . setPositiveButton (

R . s tring . btn_ok, new Dialoginterface . OnClickLi stene r ( )

puЫic void onClick ( Dialoginterface dialog, int whichВutton)

ContentValues values new ContentValues ( 2 ) ;

values . put ( ContactDbHelper . NAМE , textName . getText ( } . toSt ring ( ) ) ;

values . put ( ContactDbHe lper . PHONE , textPhone . getText ( ) . toString ( ) ) ;

Page 348: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

346 Глава 15

getContentResolver ( ) . insert ( ContactProvider . CONTENT_URI , values ) ;

mCursor . requery ( ) ;

} ) ;

b . setNegativeButton (

R . string . btn_cancel , new Dialoginterface . OnClickListener ( )

puЬlic void onClick ( Dialoginterface dialog, int whichВutton) { }

} ) ;

Ь . show ( ) ;

private void CallEditContactDialog ( fina l long id ) {

Layoutinflater inflater Layout inflater . from ( this ) ;

View root inflater . inflate ( R . layout . dialog, nul l ) ;

final EditText textName ( EditText ) root . findViewByid ( R . id . name ) ;

final EditText textPhone ( EditText ) root . findViewByid ( R . id . phone ) ;

mCursor . moveToPos ition ( this . getSelecteditemPosition ( ) ) ;

textName . setText (mCursor . getString ( l ) ) ;

textPhone . setText (mCursor . getString ( 2 ) ) ;

new AlertDialog . Builde r ( this ) ; AlertDia log . Bui lder Ь

b . setView ( root ) ;

b . setTitle ( R . s tring . ti tle_edi t ) ;

b . setPos itiveButton (

R . st ring . btn_ok, new Dialoginterface . OnClickListene r ( )

puЬlic void onClick ( Dialoginterface dialog , int whichВutton)

ContentValues values new ContentValues ( 2 ) ;

values . put ( ContactDbHelper . NAМE , textName . getText ( ) . toString ( ) ) ;

values . put ( ContactDbHelper . PHONE , textPhone . getText ( ) . toString ( ) ) ;

getContentResolver ( ) . update (

ContactProvider . CONTENT_URI , values ,

mCursor . requery ( ) ;

I D= " + id, null ) ;

Page 349: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

База данных SQLite и контент-провайдеры 34 7

b . setNegativeButton (

R . string . btn_cancel , new Dialoginterface . OnClickListener ( )

puЬlic void onClick ( Dialoginterface dialog, int whichВutton ) { }

b . show ( ) ;

private void Cal lDeleteContactDialog ( final long id )

Ale rtDialog . Builde r Ь new Ale rtDialog . Builder ( this ) ;

b . setTitle ( R . s tring . title_delete ) ;

b . setPos itiveButton (

R . s tring . btn_ok, new Dialoginterface . OnCl ickLi s tene r ( )

puЬlic void onClick ( Dialoginterface dialog , int whichВutton )

getContentResolver ( ) . delete (

ContactProvide r . CONTENT_URI ,

mCursor . requery ( ) ;

b . setNegativeButton (

I D= " id, nul l ) ;

R . string . btn_cancel , new Dialoginterface . OnClickListener ( )

puЬlic void onClick ( Dialoginterface dialog, int whichВutton ) { }

b . show ( ) ;

Скомпилируйте проект и запустите его в эмуляторе мобильного устройства. При первом запуске приложения сработает метод обратного вызова onCreate ( ) в классе ContactDbHelper, который создаст базу данных Contacts с одной таблицей и заполнит ее текстовыми данными, как показано на рис. 1 5 .2 .

Приложение содержит меню, при выборе одного и з пунктов которого ото­бражаются диалоговые окна для добавления, модификации и удаления кон­такта, представленные на рис. 1 5 .3 .

Page 350: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

348 Глава 1 5

Рис. 1 5.2. Приложе н ие с текстовы м и д а н н ы м и

Рис. 1 5.3. Диалоговые о к н а д л я добавления, модификации и удаления контакта

Page 351: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

ГЛ А В А 1 6 1 1

Ресурсы, активы и локал изация п риложен и й

Ресурсы и активы - неотъемлемая часть Аndrоid-приложения. Это внешние элементы, которые вкл ючаются в приложение: изображения, аудио, видео, строки, разметки, тем ы и т. д. Каждое приложение содержит каталог для ресурсов res/ и каталог для активов assets/.

Ресурсы используются чаще, чем активы. Реальное различие между ресурса­ми и активами заключается в следующем :

Ll информация в каталоге ресурсов будет доступна в приложении через класс R, который автоматически генерируется средой разработки. То есть хране­ние файлов и данных в ресурсах (в каталоге res/) делает их легкодоступ­ными для использования в коде программы;

Ll для чтения информации, помещенной в каталог активов assets/ (необрабо­танный формат файла), необходимо использовать As setмanager для чтения файла как потока байтов.

В этой главе вы получите информацию о стандартных ресурсах, которые обычно используются в Аndrоid-приложении, и о том , как обращаться к ним в коде программы . В предыдущих главах книги вы уже познакомил ись с за­грузкой строковых и графических ресурсов в приложение, однако существует еще много других типов ресурсов, которые можно использовать в разработке.

1 6 . 1 . Доступ н ые ти п ы ресурсов Android предоставляет разнообразные типы ресурсов, которые вы можете использовать в разрабатываемых приложениях.

Ll Простые значения - ресурсы могут быть выражены как строки с исполь­зованием различных форматирований, чтобы однозначно указать тип соз­даваемого ресурса.

Page 352: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

350 Глава 1 6

О Цвет - кодировка цвета в шестнадцатеричном выражении оnределяет значение RGB и аlрhа-канал (цвет мы рассматривали в главе 6).

О Строки с дополнительньиw форматированием. Можно добавлять доnол­нительное форматирование для строки, исnользуя три стандартных НТМL-тега: <Ь>, <i> и <u> . Методы, которые будут обрабаты вать строко­вые ресурсы с НТМL-форматированием, должны уметь обрабатывать эти теги .

О Графические ресурсы . Есть множество видов графических ресурсов, кото­рые можно создавать и исnользовать в nриложении :

• файлы растровой графики в различных форматах: * .png (которы й наи­более nредnочтителен для исnользования), * .jpg и * .gif;

• PaintDrawaЬle - объекты, которые являются четырехугольником цвета с произвольно округленными углами . Этот элемент может быть оnре­делен в любом из файлов внутри каталога res/values/;

• графика NinePatch - изображение PNG, которое можно растягивать . В Android графика NinePatch исnользуется для nрорисовки виджетов ­кноnок, закладок и т. д .

О Анимация - Android может выполнить nростую анимацию на графике или на серии графических изображений . Анимация включает вращения, nостеnенное изменение, nеремещение и nротяжение.

О Меню - меню и nодменю также могут быть оnределены как ХМL­ресурсы и загружены в приложение.

О ХМL-файлы разметки. Этот вид ресурса вы уже хорошо изучил и в nреды­дущих главах кн иги.

О Стили - исnользуются для элементов. Это один ил и более атрибутов, относящихся к одному элементу. Стиль nрименен как атрибут к элементу в файле разметки.

О Темы - это один или более атрибутов, относящихся к целому экрану. На­nример, можно nрименить готовую тему, оnределенную в Andro id , ­Theme . dialog к деятельности, разрабатываемой для nлавающих диалого­вых окон .

1 6 .2 . Создан и е ресурсов Как уже было сказано в главе 3 , все ресурсы создаются и сохраняются в nред­оnределенных nодкаталогах в каталоге res/ nроекта. Aпdroid SDK имеет ути­литу aapt для комnиляции ресурсов.

Page 353: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

Ресурсы, активы и локализация приложений 351

Далее nриводится сnисок каталогов и вложенных файлов для каждого тиnа ресурса.

LJ res/an im/ - файлы анимации.

LJ res/drawaЬ\e/ - графика.

LJ resllayout/ - ХМL-файлы для схем разметки .

LJ res/values/ - ХМL-файлы, которые могут быть откомnилированы во м но­гие виды ресурса. В отличие от других каталогов, res/ может содержать любое число файлов. При создании файлов ресурсов следует соблюдать соглашение об именовании файлов ресурсов по тиnу элементов, оnреде­ленных в них:

• arrays .xml - массивы;

• colors .xml - значения цвета для графики и строк текста;

• d imens.xml - размерности;

• strings.xm l - строкавые значения;

• styles.xml - стили .

LJ res/xm l/ - nроизвольные ХМL-файлы , которые могут загружаться во вре­мя выnолнения.

LJ res/raw/ - nроизвольные файлы, nредназначенные для коnирования непо­средственно на устройство.

1 6 .3 . Ссыл ки на ресурсы Значение атрибута ХМL-элемента (или ресурса) может также быть ссылкой на ресурс. Это часто исnользуется в файлах разметки для строк и изображе­ний (которые находятся в другом файле), хотя ссылкой может быть любой тиn ресурса, наnример, цветовая кодировка или целочисленные значения.

Наnример, если мы имеем цветовые ресурсы , мы можем заnисать файл разметки, который устанавливает значение цвета для текста, находящегося в одном из этих ресурсов :

android : textColor= " @ color/opaque_red"

Обратите внимание здесь на исnользование nрефикса @ для того, чтобы вве­сти ссылку ресурса - текст nосле этого nрефикса - имя ресурса. В этом случае мы не должны был и указывать nакет, nотому что мы ссылаемся на ресурс в нашем собственном nакете. Для ссылки на системный ресурс мы должны заnисать :

android : textColor= " @ android : color/opaque_red"

Page 354: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

352

1 6 .4. Испол ьзование ресурсов в коде програм м ы

Глава 1 6

Во время компиляции генерируется класс R , который является оболочкой ре­сурсов и содержит идентификаторы всех ресурсов в программе. Класс R име­ет несколько вложенных классов, один для каждого типа ресурса, поддержи­ваемого системой Android, и для которого в проекте существует файл ресур­са. Класс R может содержать следующие вложенные классы :

О R . anim - идентификаторы для файлов из каталога res/an im/;

О R . array - идентификаторы для файлов из каталога res/values/;

О R . bool - идентификаторы для битовых массивов в файлах arrays.xml из каталога res/values/;

О R . color - идентификаторы для файлов colors.xml из каталога res/values/;

D R . dimen - идентификаторы для файлов d imens.xm l из каталога res/values/;

D R . drawaЬle - идентификаторы для файлов из каталога res/drawaЬ\e/;

О R . id - идентификаторы представлений и групп представлений для фай­лов ХМL-разметки из каталога res/layout/;

D R . integer - идентификаторы для целочисленных массивов в файлах arrays.xml из каталога res/values/;

О R . layout - идентификаторы для файлов разметки из каталога res/layout/;

О R . raw - идентификаторы для файлов из каталога res/raw/;

О R . string - идентификаторы для файлов strings.xm l из каталога res/val ues/;

D R . style - идентификаторы для файлов sty\es.xml из каталога res/values/;

D R . xml - идентификаторы для файлов из каталога res/xml/.

Каждый вложенный класс содержит один или несколько идентификаторов для откомпилированных ресурсов, которые используются в коде программы для загрузки ресурса. Далее приведен синтаксис для обращения к ресурсу:

R . resource_type . resource_name

В Приложениях также можно использовать системные ресурсы . Все систем­ные ресурсы определены под классом android . R. Например, стандартный зна­чок приложения на экране можно отобразить так:

android . R . drawaЬle . sym_de f_app_icon

Или загрузить стандартный стиль :

android . R . style . Theme_Black

Page 355: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

Ресурсы, активы и локализация приложений 353

1 6.4. 1 . Загрузка простых типов из ресурсов

Чтобы изучить на практике загрузку разнообразных простых типов ресурсов и их вызов из программнога кода, создадим в Ecl ipse новый проект:

D Project name - S impleValues;

О Application name - Resource S imple;

D Package name - com . samples . s implevalues;

D Create Activity - SimpleVa luesActi vi ty.

При создании проекта в каталоге res/values/ мастер генерирует единственный файл strings .xml . Добавьте в этот каталог следующие ХМL-файлы :

D arrays.xm l - для массивов строк и целочисленных значений;

D colors.xml - для значений цвета;

D d imen .xm l - для значений размеров текста;

D drawaЬ\es.xml - для графических примитивов.

Заполните эти файлы разнообразными данными, как показано в листин­гах 1 6 . 1 -1 6 .5 .

< ?xml vers ion= " l . O " encoding= " utf-8 " ?>

< resources>

<string-array name="names " >

<item>Andrew</ item>

<item>Helen</ item>

<item>Jack< /item>

</string-array>

<intege r-array name="digits " >

<item> l 9 9 9 < / item>

<item> 2 0 0 2 < / item>

<item>2 0 1 0 < / item>

< / intege r-array>

</ resources >

<?xml vers ion= " l . O " encoding= " ut f- 8 " ?>

<resources >

<color name=" textColor " > # O O O O FF</color>

Page 356: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

354

<color name= "backgroundColor"># FFO O O O < / color>

< / resources >

<?xml ve rs ion=" l . O " encoding= " utf-8 " ?>

<resources > <dirnen name="text Point S i z e " > l 8pt</dirnen>

< / resources >

< ?xml version=" l . O " encoding= " ut f- 8 " ?>

<resources >

<drawaЬle name= "grayDrawaЬle " > # DDD< /drawaЬle>

< / resources >

< ? xml ve rsion= " l . O " encoding= " utf-8 " ?>

<resources>

<string name= "app_name " >Resource Sample</string>

<string name=" s orne_text ">Sorne Text</st ring>

< / resources>

Глава 16

В файле разметки создадим структуру с текстовыми полям и для отображения на экране загружаемых ресурсов. Файл разметки деятельности приложения maiп.xml приведен в листинге 1 6 .6 .

<?юnl vers ion=" l . O " encoding= " utf-8 " ?>

<LinearLayout xrnlns : android=" http : / /schernas . android . com/apk/ re s / android"

android : orientation="vert ical "

android : layout_width=" fi l l_parent "

android : layout_height=" fi l l_parent " >

<LinearLayout

android : layout_width="wrap content "

android : layout_height="wrap_content " >

<TextView

android : layout_height="wrap_content "

android : text=" S tring array : "

Page 357: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

Ресурсы, активы и локализация приложений

android : layout_width="wrap_content "

android : paddingRight=" Spx "

android : textColor= " @ color/textColor" / >

<TextView

android : id= " @+id/text_st rings "

android : layout_width="wrap_content "

android : layout_height="wrap_content "

android : padding=" Spx "

android : textColor= " @ color/textColor" / >

< / LinearLayout>

<LinearLayout

android : layout_width= "wrap content "

android : layout_height= "wrap_content " >

<TextView

android : layout_he ight="wrap_content "

android : text= " Int array : "

android : layout_width= "wrap_content "

android : paddingRight= " 2 0px "

android : padding=" Spx "

android : textColor= " @ color/textColor" / >

<TextView

android : id=" @ +id/text_digits "

android : layout_width= "wrap_content "

android : layout_he ight="wrap_content "

android : textColor= " @ color/textColor " / >

< / LinearLayout>

<LinearLayout

android : layout_width= "wrap content "

android : layout_height= "wrap_content " >

<TextView

android : id=" @ +id/text_style "

android : layout_width= "wrap_content "

android : layout_he ight="wrap_content " / >

< / LinearLayout>

</LinearLayout>

355

В классе деятельности SimpleValuesActivity nоказаны варианты загрузки ре­сурсов в зависимости от их тиnа с nомощью сгенерированного nлагином класса R. Полный код класса nриведен в листинге 1 6 .7 .

Page 358: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

356

package com . samples . s implevalues ;

import android . app . Activity;

import android . graphics . drawaЬle . ColorDrawaЬle ;

import android . os . Bundle ;

import android . view . Window;

import android . widget . TextView;

puЬlic class S impleValuesActivity extends Activity

@ Override

puЬl ic void onCreate ( Bundle savedinstanceState )

super . ·onCreate ( savedinstanceState ) ;

setContentView ( R . layout . main ) ;

final TextView textSt rings

( TextView ) findViewByid ( R . id . text_strings ) ;

1 1 загрузка массива строк из res /values/arrays . xml

Глава 1 6

String [ ] names getResources ( ) . getStringArray ( R . array . names ) ;

for ( int i О ; i < names . length;

textStrings . append ( "Name [ " + i + " + names [ i ] + " \n " ) ;

final TextView textDigits

( TextView ) findViewByid ( R . id . text_digits ) ;

1 1 загрузка массива целых чисел из res /values/arrays . xml

int [ ] digits getResources ( ) . getintArray ( R . array . digits ) ;

for ( int i О ; i < digits . length; {

textDigi ts . append ( " Digi t [ " + i + " + digits [ i ] + " \n " ) ;

1 1 текстовое поле с атрибутами , загружаемыми из ресурсов

final TextView textStyle (TextView ) findVi ewByid (R . id . text_style ) ;

1 1 загрузка текста из res /values/strings . xml

textStyle . setText (

getResources ( ) . getText ( R . s tring . some_text ) ) ;

Page 359: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

Ресурсы, активы и локализация лриложений

/ 1 загрузка цвета текста из res /values /colors . xml

textStyle . setTextColor (

getResources ( ) . getColor ( R . color . textColor ) ) ;

/ 1 загрузка размера текста из res /values /dimen .�l

textStyle . setText S i ze (

getResources ( ) . getDimens ion ( R . dimen . textPointS i z e ) ) ;

/ 1 загрузка цвета для фона из res /values /colors . xml

textStyle . setBackgroundColor (

getResources ( ) . getColor ( R . color . backgroundColo r ) ) ;

/ 1 загрузка цвета фона окна деятельности / 1 из res/values/drawaЫes . xml Window w = this . getWindow ( ) ;

w . setBackgroundDrawaЬle (

( ColorDrawaЬle ) getResources ( ) . getDrawaЬle (

R . drawaЫe . grayDrawaЬle ) ) ;

357

После компиляции и запуска проекта внешний вид приложения должен быть таким, как на рис. 1 6 . 1 .

Рис. 1 6. 1 . Загрузка простых типов ресурсов

Page 360: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

358 Глава 1 6

1 6.4.2 . Загрузка файлов произвол ьнога ти па

Каталог res/raw/ предназначен для хранения файлов произвольнога типа, ко­торые сжимаются при компиляции проекта и копируются на устройство в "нормальном" виде. Например, в этот каталог можно поместить какой-либо текстовый файл, который будет загружаться в приложение.

При загрузке файла с произвольным типом данных используются методы ра­боты с потоками ввода-вывода, описанные в главе 14 . Однако, в отличие от примера (текстового редактора), приведеиного в главе 14, файлы, размещае­мые в каталоге res/raw/, генерируют идентификатор ресурса, и в коде про­грамм ы к ним можно обращаться не по имени файла, а по идентификатору ресурса.

Чтобы показать на практике вариант использования загрузки файлов из ката­лога res/raw/, создадим новый проект:

D Project name - ContactLauncher;

D Application name - Contact Launcher Sample;

D Package name - сот . samples . contact launcher;

D Create Activity - ContactLauncherAct ivity.

В файле разметки maiв .xml создайте единственный элемент тextView, как по­казано в листинге 1 6 . 8 .

< ?xml version=" l . O " encoding= " ut f- 8 " ?> <LinearLayout xmlns : android= " http : / /schemas . android . com/apk/ re s / android"

android : orientat ion="vertica l " android : layout_width= " fill_parent " android : layout_height= " fi l l_parent " android : gravity= " center">

<TextView android : id= " @ +id/text " android : layout_height="wrap_content " android : text= " @ string/hello" android : layout_width= "wrap_content " android : gravity= " l e ft l cente r " / >

< / LinearLayout>

Загрузка файла из ресурсов аналогична загрузке, приведеиной в приложении для работы с файлам и в главе 14. Код класса деятельности , в котором произ­водится загрузка ресурса, приведен в листинге 1 6 .9 .

Page 361: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

Ресурсы, активы и локализация приложений

package com . samples . raw;

import j ava . io . DatainputSt ream ;

import j ava . io . InputSt ream;

import android . app . Activity;

import android . os . Bundle ;

import android . widget . TextView ;

puЬlic class RawActivity extends Act ivity

@ Override

puЬl ic void onCreate ( Bundle savedinstanceState )

supe r . onCreate ( savedinstanceState ) ;

setContentView ( R . layout . main ) ;

final TextView text ( TextView ) findViewByid ( R . id . text ) ;

359

InputSt ream i File getResources ( } . openRawResource ( R . raw . file ) ;

t ry {

StringBuffer sBuffer new StringBuffe r ( ) ;

DatainputStream dataiO = new DatainputStream ( iFile ) ;

String strLine nul l ;

whi le ( ( strLine=dataiO . readLine ( ) ) nul l ) {

sBuffer . append ( strLine + " \n" ) ;

dataiO . close ( ) ;

iFile . close ( ) ;

text . setText ( sBuffer . toString ( } ) ;

catch ( Except ion е )

text . setText ( "Error loading file : + e . getMessage ( ) ) ;

Сделаем компиляцию и запустим проект на выполнение. Приложение должно загрузить текстовый файл из каталога ресурсов и вывести на экран его со­держимое, как показано на рис. 1 6 .2.

Page 362: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

360 Глава 1 6

Рис. 1 6.2. Загрузка ресурсов и з файла в каталоге res/raw/

1 6 .4.3 . Создан ие меню в XML

В предыдущих приложениях м ы создавали для окон деятельности схемы разметки в виде ХМ L-документов, сохраняемых в каталоге res/layouts/. Ана­логично можно определять меню в ХМL-документах и загружать их в при­ложение. Файлы меню сохраняются в отдельном каталоге res/menu/.

В ХМL-файле меню есть три элемента:

D <menu> - корневой элемент файла меню;

D <group> - контейнерны й элемент, определяющий группу меню;

D <item> - элемент, определяющий пункт меню.

Элементы < itern> и <group> могут быть дочерними элементами <group>. Ко­нечно, корневой узел любого файла должен быть элементом меню.

Как пример приложения с загрузкой меню из XML м ы определим то же са­мое меню со значками, созданное нами в разд. 1 0. 1 . 1 . Создадим в Ecl ipse но­вый проект и в диалоге Create New Project заполним поля :

D Project паше - IconМenuApp;

D Applicatioп паше - Load Menu from resource;

D Package паше - com . samples . resmenuxml ;

D Create Activity - ResMenuXmlAct ivity.

Page 363: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

Ресурсы, активы и локализация приложений 361

В ХМL-файле, который будет определять меню, создадим пять пунктов ме­ню - Open, Save, Edit, Help и Exit - с иконками, взятым и из приложения в разд. 1 0. 1 . 1 , и сохрани м этот файл под именем options .xm l в каталоге res/menu/ проекта. Полный код файла options.xm l представлен в листин­ге 1 6 . 1 0 .

<menu xmlns : android= "http : / /schernas . android . com/apk/res/android" >

< itern android : id=" @ +id/open" android : ti t le="Open "

android : icon=" @drawaЬle/ i c_rnenu open" android : orderinCategory= " l " />

< itern android : id=" @ +id/save "

android : title=" Save "

android : icon= " @drRwaЬle/ic rnenu save " android : orderinCategory= " 2 " />

<itern android : id=" @ + id/edit " android : ti tle= "Edit " android : icon= " @drawaЬle/ic rnenu edit " android : orderinCategory= " З " />

<itern

android : id=" @ +id/help"

android : ti t le="Help"

android : icon= " @drawaЬle / i c_rnenu he lp"

android : orderinCategory= " 4 " />

<itern

</rnenu>

android : id=" @ +id/exit" android : title= "Exi t " android : icon= " @drawaЬle / i c rnenu exi t " android : orderinCategory= " 5 " / >

Файл разметки для деятельности приложения с единственным виджетом TextView приведен в л истинге 1 6 . 1 1 .

<?Xml vers ion= " l . O " encoding= " utf-8 " ?>

<LinearLayout xmlns : android= " http : / / schernas . android . com/apk/ res /android" 1

android : orientation="vertica l "

Page 364: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

362

android : layout_width= " f i l l_parent " android : layout_he ight=" fi ll_parent " >

<TextView android : layout_width= " fill_parent " android : layout_height="wrap_content " android : text=" Press МENU button . . android : gravity= " center " android : textStyle="bold" />

</LinearLayout>

Глава 1 6

Загрузка меню и з ресурса несколько отличается от создания меню в коде приложения, которое мы рассматривали в главе 1 О. В коде метода обратного вызова onCreateOpt ionsMenu ( ) достаточно получить ссылку на ресурс ХМL­файла, определяющего меню:

@ Override

puЬlic boolean onCreateOptionsMenu (Menu menu) getMenuinflate r ( ) . inflate ( R . menu . opt ions , menu ) ;

return t rue ;

При загрузке меню из ХМL-файла идентификаторы меню определяют в фай­ле, и , следовательно, нет необходимости объявлять их в коде программы . В классе R будут сгенерированы константы, к которым можно обращаться в коде, как и к идентификаторам остальных ресурсов. Эти идентификаторы можно использовать в методе обратного вызова onOpt ions ltemSelected ( ) , на­пример, таким образом :

@ Override

puЬlic boolean onOptions i temSelected (Menui tem item)

switch ( item . geti temid ( ) )

case R . id . open :

brea k ; case R . id . save :

break ; default :

return fal s e ;

return t rue ;

Page 365: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

Ресурсы, активы и локализация приложений 363

Полный код класса главной деятельности ResMenuXmlActivity показан в листинге 1 6 . 1 2 .

package corn . samples . resrnenuxml ;

irnport android . app . Activity;

irnport android . os . Bundle ;

irnport android . view . Gravit y ;

irnport android . view . Menu ;

irnport android . view . Menui tern;

irnport android . widget . Toas t ;

puЬlic class ResMenuXmlActivity extends Activity

@Ove rride

puЫ i c void onCreate ( Bundle savedinstanceState )

supe r . onCreate ( savedinstanceState ) ;

setContentView ( R . layout . rnain ) ;

1 1 загрузка меню из ХМL-файла

@Override

puЬlic boolean onCreateOptionsMenu (Menu rnenu)

getMenuinflate r ( ) . inflate ( R . rnenu . options , rnenu ) ;

return t rue ;

@Override

puЫic boolean onOptionsiternSelected (Menuitern itern)

Cha rSequence rnessage ;

switch ( itern . getiternid ( ) )

case R . id . open :

rnessage

brea k ;

"Open itern selected" ;

case R . id . save :

rnes sage

brea k ;

" Save i tern se lected" ;

case R . id . help :

rnessage

brea k ;

"Help i tern se lected" ;

Page 366: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

364

case R . id . edit :

mes sage "Edit i tem se lected " ;

brea k ;

case R . id . exit :

message

break ;

de faul t :

"Exit i tem selected " ;

return false ;

Глава 1 6

Toast toast Toast . makeText ( thi s , me s sage , Toast . LENGTH_SHORT ) ;

toast . setGravi ty ( Gravi ty . CENTER , О , 0 ) ;

toast . show ( ) ;

return true ;

Скомпилируйте и запустите проект на выполнение. Внешний вид прило­жения с загрузкой меню из ХМ L-файла не отличается от меню, созданного в коде программ ы (рис. 1 6 .3 ) .

- � Open 5a'le

� о 0 Exlt

Рис. 1 6.3 . Мен ю, загруженное из ХМL-файла

1 6 .4.4. Загрузка ХМL-документов

Библиотеки Aпdro id имеют набор классов для чтения и записи ХМL-до­кументов с произвольной структурой и содержанием . Чтобы упаковать ста-

Page 367: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

Ресурсы, активы и локализация приложений 365

тический ХМL-документ с вашим приложением, поместите его в каталог res/xml/, и тогда вы получите возможность обращаться в коде программы к этому документу.

Рассмотрим загрузку ХМL-документа произвольной структуры из ресурсов в код программ ы . Создадим в Ec l i pse приложение, способное читать список контактов, определенных в ХМL-файле. В окне New Android Project запол­ните поля :

D Project name - Files _ Xrnl;

D Application name - XМLResource Sample;

D Package name - сот . samples . resxn11;

D Create Activity - ResXrnlAct ivity.

В каталоге res/ создайте подкаталог xml/, в котором будет располагаться ХМL-файл контактов . В этом файле мы напишем список контактов, уже не­однократно применяемый в приложениях в этой книге, и сохрани м его под именем contacts .xm l . Полный код файла contacts .xm l представлен в листин­ге 1 6 . 1 3 .

<contacts>

<contact first_name=" Jacob " last_name="Anderson" phone= " 4 1 2 4 12 4 1 1 " />

<contact fi rst_name=" Emily" last_name=" Duncan" phone= " l 6 1 8 63 1 8 7 " / >

<contact first_name="Michael " last_name=" Ful ler" phone= " 4 67 657 5 6 5 " / >

<contact first_name="Emma " last_name="Greenman" phone= " 0 2 5 6 6 57 4 6 " / >

<contact fi rst_name=" Joshua " last_name="Harrison" phone= " 4 7 52 8 9 5 68 " />

<contact first_name="Madison " last_name=" Johnson" phone= " 8 9 1 8 63 1 8 7 " />

<contact first_name="Matthew" last_name="Cotman" phone= " l 6 1 8 63 1 8 7 " />

<contact first name=" Ol ivia " last_name=" Lawson" phone= " 9 4 3 657 8 7 5 " / >

<contact first_name="Andrew" last_name="Chapman" phone= " 8 7 68 67 8 9 6 " />

<contact first_name=" Daniel " last_name="Honeyman" phone= " 9 8 7 65 4 3 8 8 " />

<contact first_name=" Isabella" last_name=" Jackson" phone= " 3 1 2 4 3 9 7 8 7 " />

<contact first_name="Wi l l iam" last_name=" Patterson" phone= " 6 8 7 6 9 9 6 93 " />

<contact first_name=" Joseph" last_name="Godwin" phone=" 9 6 5 4 6 7 57 5 " />

<contact first name=" Samantha " last name= "Bush" phone= " 9 0 7 8 6 5 6 4 5 " />

<contact first name=" Chris " last name= "Gateman" phone=" 8 9 6 8 7 4 55 6 " />

</contacts>

Файл разметки деятельности main .xml для главной деятельности приложения приведен в листинге 1 6 . 1 4 .

Page 368: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

Збб Глава 1 6

< ? xrnl ve rsion= " l . O " encoding= "ut f-8 " ?>

<LinearLayout xmlns : android= " http : / / schernas . android . com/apk/ re s /android"

android : orientation= " vert i ca l "

android : layout_width= " fi l l_parent "

android : layout_height= " fi l l_parent "

<ListView

android : id=" @ android : id / l i s t "

android : layout_width=" fi l l_parent"

android : layout_he ight=" fi ll_parent "

android : drawSe lectorOnTop= " false " / >

</LinearLayout>

Загрузить файл contacts .xml , созданный ранее, можно следующим образом :

Xml PullParser parser getResources ( ) . getXml ( R . xml . contacts ) ;

Метод getXml ( ) возвращает Xml PullParser, используя который можно прочи­тать загруженный ХМL-документ в цикле while :

whi le (parser . getEventType ( ) ! = XmlPullParse r . END_DOCUМENT )

i f ( parser . getEventType ( ) == XmlPullParser . START_TAG

& & parser . getName ( ) . equals ( " contact " ) ) {

l i s t . add (parser . getAttributeValue ( O )

+ parser . getAttributeValue ( l ) + " \n "

+ parser . getAtt ributeValue ( 2 ) ) ;

parser . next ( ) ;

Полный код класса главной деятельности приложения ResXmlAct ivity показан в листинге 1 6 . 1 5 .

package com . samples . resxml ;

import j ava . ut i l . ArrayLis t ;

import org . xmlpull . vl . XmlPullParser ;

import android . app . Li s tAct ivit y ;

import android . os . Bundle ;

Page 369: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

Ресурсы, активы и локализация приложений

import android . widget . ArrayAdapte r ;

import android . widget . Toas t ;

puЬlic class ResXmlAct ivity extends ListAct ivity

@ Ove rride

puЬl i c void onCreate ( Bundle savedinstanceState )

supe r . onCreate ( savedinstanceState ) ;

setContentView ( R . layout . main ) ;

ArrayList<String> l i s t new ArrayList<String> ( ) ;

try

367

Xml Pul l Parser parser getResources ( ) . getXml ( R . xml . contacts ) ;

while . ( pa rser . getEventType ( ) ! = XmlPul l Parser . END _DOCUМENT )

i f ( parser . getEventType ( ) XmlPu l l Parse r . START TAG

& & parser . getName ( ) . equals ( " contact " ) ) {

l i s t . add ( parser . getAttributeValue ( O )

+ parser . getAttributeVa lue ( l ) " \n "

+ pa rser . getAttributeValue ( 2 ) ) ;

parser . next ( ) ;

catch ( ThrowaЬle t ) {

Toas t . makeText ( this ,

"Error loading ХМL document :

. show ( ) ;

setListAdapter (new ArrayAdapter<String> (

+ t . toString ( ) , 4 0 0 0 )

thi s , android . R . layout . s imple_lis t_item 1 , l i s t ) ) ;

В нешний вид приложения , запущенного в эмуляторе мобильного устройства, показан на рис. 1 6 .4 .

Page 370: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

368 Глава 1 6

Рис. 1 6.4. Чтение ХМL-документа и з ресурсов

1 6 .5 . Стил и и темы Проектируя приложение, в ы можете использовать стили и темы для создания оригинального дизайна окон деятельностей приложения и отдельных элемен­тов пользовательского интерфейса.

Стили и тем ы - это такие же ресурсы, как и строки, изображения и т. д. Andro id обеспечивает некоторые заданные по умолчанию стили и темы , ко­торые вы можете использовать в приложениях. При необходимости вы може­те определить свой собственный стиль и тему для создаваемого приложения .

1 6 .5 . 1 . Стил и

Стиль - это один или несколько сгруппированных атрибутов форматирова­ния , которые вы можете применить как модуль к отдельным элементам поль­зовательского интерфейса в ХМL-схеме разметки для деятельности . Напри­мер, вы можете определить стиль, который устанавливает определенный раз­мер текста и цвет фона, а затем применить его к выбранным компонентам пользовательского интерфейса. Вот пример объявления стиля в ХМ L-файле:

<?xrnl vers ion= " . 0 " encoding= "utf-8 " ?>

<resources >

<style name= "CustomText " parent= " @ style /Text " >

< item name="android : text S i ze " > l B sp</ item>

Page 371: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

Ресурсы, активы и локализация приложений

< item name="android : textColor" > # 0 0 8 < / i tem>

</style>

< / resources >

369

Как было показано ранее, вы можете использовать элементы < item>, чтобы установить определенные значения форматирования для стиля . Атрибут nате

в элементе может быть стандартной строкой, шестнадцатеричным значением цвета или ссылкой на любой

· другой тип ресурса.

Обратите внимание на атрибут parent в элементе <style>. Этот атрибут по­зволяет определять ресурс, от которого текуuций стиль наследует значения свойств . Стиль может наследоваться от любого типа ресурса, которы й содер­жит требуемый стиль . Вообuце, ваши собственные стили должн ы всегда на­следоваться, прямо или косвенно, от стандартных стилей Android . В этом случае необходимо только определить значения, которые требуется изменить в наследуемом стиле .

Для ссылки на стиль используется атрибут style. Например, так можно при­соединить стиль для элемента TexView:

<TexView

style= " @ style/CustomText "

android : id=" @+id/ text l "

android : layout_width= " f i l l_parent"

android : layout_he ight= "wrap_content"

android : text=" Hello, World ! "

Теперь этот виджет Textview будет иметь стиль Customтext, который б ыл объ­явлен ранее в примере с ХМL-кодом.

1 6 .5 .2 . Тем ы

Тема - группа из одного или нескольких атрибутов форматирования, кото­рые вы можете применить как модуль ко всем действиям в приложении или только единственной деятельности . Например, вы могли определить тему, которая выбирает определенные цвета для рамки окна и группового передне­го плана и фона и устанавливает текстовые размеры и цвета для меню, затем применять это к действиям вашего приложения .

Темы похожи на определения стилей. Точно так же, как стили, темы объяв­ляются в ХМL-файле элементами <s tyle>, и ссылаются на них тем же самым способом . Различие состоит в том, что тема добавляется ко всему приложе­нию или к отдельной деятельности через элементы <appl ication> и <activity> в файле манифеста приложения, т. к. тем ы не могут быть приме­нены к отдельным представлениям .

Page 372: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

370

Вот объявление примера темы :

<?xml version= " l . O " encoding= " ut f- 8 " ?>

<resources>

<style narne= "CustomTheme " >

<item narne= "androi d : windowNoTitle " >true</item>

<i tem narne="windowFrarne ">@drawaЬle /screen frarne</item>

<i tem

Глава 1 6

narne= "windowBackground" > @drawaЬle/screen_background_white</ i tem>

<item narne= "panel ForegroundColor " > # FFO O O O O O < / item>

< item narne="panelBackgroundColor "># FFFFFFFF</item>

<item narne= "panelTextColor " > ?panelForegroundColor< /item>

< item narne="panelTextS i z e " > l 4 < / item>

<item narne= "menuitemTextColor " > ?panelTextColor</item> <item narne="menuitemTextS i z e " >?panelTextS i ze</item>

< /style>

< /resources>

Чтобы установить эту тему для всех деятельностей приложения, откройте файл AndroidMan ifest.xml и отредактируйте элемент <appl icat ion>, добавив атрибут android : theme с названием темы :

android : theme= " @ style /theme_custom"

Если вы хотите определить тему, которая будет загружаться только для одной деятельности приложения, добавьте атрибут с темой в элемент <activity> данной деятельности .

Наряду с другими встроенными ресурсами, в Android есть несколько стан­дартных тем, которые можно загрузить в приложение. Например, вы можете использовать тему Theme . Dialog, чтобы заставить деятельность отобразиться на экране как диалоговое окно. В файле манифеста объявить ссылку на стан-дартную тему Andro id можно следующим образом :

'

<activity android : theme=" @ android : style/Theme . Dialog " >

1 6 .5 .3 . Оп ределение собственных стилей и тем

Чтобы создать собственный стиль или тему в приложении, необходимо пред­принять следующие действия .

D Создать файл с названием styles.xml в каталоге приложения res/values/. В файл добавить корневой элемент <resources>.

D Для каждого стиля или тем ы добавить элемент <style> с уникальны м име­нем, например narne= "CustomTheme" , и при необходимости родительский ат-

Page 373: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

Ресурсы, активы и локализация приложений 371

рибут. Имя стиля используется для ссылки на этот стиль позже, и роди­

тельский атрибут указывает то, что данный стиль наследуется от другого

стиля .

О В элементе <style> создать набор из одного или нескольких элементов <itern>. Каждый элемент <itern> задает какие-либо свойства стиля .

Давайте для примера использования собственных стилей и тем разработаем приложение, в котором определим собственные стиль и тему. В Ecl ipse соз­дайте новый проект и в окне New Android Project заполните поля :

О Project name - StylesAndThemes;

О Application name - Styles and Thernes;

О Package name - сот . samples . stylesandthernes;

О Create Activity - StylesAndThemesAct ivity.

В каталоге res/values/ создадим ХМL-файл, в котором определим стили для текстового поля - SpecialText и для приложения - Stars, и сохраним его под именем styles.xml . Код файла приведен в листинге 1 6 . 1 6.

< ?xml version= " l . O " encoding= "ut f-8 " ?>

<resources>

<style name= " SpecialTex t " >

<item name= " android : text S i z e " > 2 8 sp< /item>

<item name=" android : textColor" > # FFO O O O < / item>

<item name= " android : background " > # O O O O O O < / item>

< /style>

<style name= " Stars " >

<item name=" android : windowBackground">@drawaЬle/ stars < / item>

<itern name= " android : windowNoTitle" >true</itern>

< /style>

< / resources>

В файле разметки main .xml определим единственный элемент TextView, и для этого элемента зададим созданн ы й в файле styles.xml стиль, используя для этого атрибут s tyle:

style= " @ style / SpecialText "

Полный код файла разметки main.xml представлен в листинге 1 6 . 1 7 .

Page 374: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

372 Глава 1 6

< ?xrnl ve rs ion= " l . O " encoding="utf- 8 " ?>

<LinearLayout xrnlns : android= "http : / / schemas . android . com/apk/ res /android"

android : orientation="vert ica l "

android : layout_width= " fi l l_parent "

android : layout_height=" fi l l_parent "

android : gravity= " center " >

<TextView

s tyle= " @ style / SpecialText "

android : layout_height= "wrap_content "

androi d : text= " @ string/he l lo "

android : gravity=" center"

android : layout_width= "wrap_content "

android : padding= " Spx " / >

</LinearLayout>

В файле манифеста приложения теперь необходимо объявить ссылки на тему для приложения, используя атрибут android : theme:

android : theme=" @ style/Stars "

Код файла манифеста приложения приведен в листинге 1 6 . 1 8 .

< ?xml version= " l . O " encoding= "ut f-8 " ?>

<mani fest xmlns : android="http : / / s chemas . android . com/apk/ res /android"

package= " com . samples . stylesandthemes "

android : vers ionCode= " l "

android : versionName= " l . O " >

<application

andro i d : icon= " @drawaЬle/icon"

andro i d : label= " @ string/app_name"

andro i d : theme= " @ style / Stars " >

<activity

android : name= " . StylesAndThemesActivity"

android : label= " @ string /app_name " >

<intent-fi lter>

<action android : name= "android . intent . action . МAIN " / >

<category android : name= " android . intent . category . LAUNCHER" />

< / intent - fi lter>

Page 375: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

Ресурсы, активы и локализация приложений

< /activity>

< / application>

<uses-sdk android : minSdkVersion= " З "

< /man i fest>

373

Внешний вид приложения с собственным стилем для текстового поля и те­мой для всего приложения показан на рис. 1 6 . 5 .

Рис. 16.5. Загрузка стилей и темы и з ресурсов

1 6 .6 . Акти вы Активы - это файлы произвольнога типа и содержания, располагаемые в каталоге assets/. Этот каталог находится на одном уровне с каталогом res/ в дереве проекта. Особенностью этого каталога является то, что файлы в assets/ не генерируют идентификаторы ресурса в классе R. В программ нам коде необходимо явно определять путь к файлу для доступа к нему. Путь к файлу - это относительный путь, начинающийся с assets/. Для обращения к этим файлам используется класс As setManager. Этот каталог, в отличие от подкаталога res/, позволяет произвольную глуби ну подкаталогов и произ­вольные имена файлов и подкаталогов.

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

Page 376: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

374 Глава 1 6

жением . Чтобы сделать это, необходимо создать каталог assets/ в корне ката­лога проекта и поместить в этот каталог свои файлы шрифтов.

В качестве примера приложения для работы со шрифтами, загружаемыми в качестве активов в приложение, создайте новы й проект и в окне Create New Project введите следующие значения :

О Project name - Res FontsApp;

О Application name - Load fonts from assets sample;

О Package name - сот . samples . fonts;

О Create Activity - FontsActivity.

Код в файле разметки maiп .xml состоит из контейнера LinearLayout и четырех дочерних виджетов тextView, которые будут отображать текст с использова­нием загружаемых шрифтов .

Код ХМL-файла разметки деятельности приложения main .xm l представлен в листинге 1 6 . 1 9 .

< ? xml vers ion= " . 0 " encoding= "ut f-8 " ?>

<LinearLayout

xmlns : android= "http : / /schemas . android. com/apk/res /android"

android : id= " @ +id/LinearLayoutO l "

android : layout_width= " fil l_parent "

android : layout_height= " fi l l_parent "

android : orientation= "vertica l "

android : gravity= " center " >

<TextView

android : text= " Libertine Italic"

androi d : id= " @ +id/text l "

android : layout_width= "wrap_content "

android : layout_height="wrap_content "

androi d : textS i z e= " З бsp"

android : padding= " l Osp " />

<TextView

android : text="AЬaddon font "

android : id=" @ +id/text2 "

android : layout_width= "wrap_content "

android : layout_height="wrap_content "

android : textS i z e= " З бsp"

android : padding= " l Osp " />

Page 377: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

Ресурсы, активы и локализация приложений

<TextView android : text= " a Рара font " android : id= " @ + id/text З " android : layout_width="wrap_content " android : layout_height="wrap_content " android : text S i ze= " З бsp" android : padding=" l O sp " />

<TextView android : text= "A Yummy Apology" android : id=" @ +id/text4 " android : layout_width= "wrap_content " android : layout_height= "wrap_content " android : textS i ze= " З бsp" android : padding= " l O sp " / >

< / LinearLayout>

375

Для примеров были использованы свободно распространяемые шрифты : Linuх-шрифт Libertine и несколько свободных шрифтов, доступных на сайте http://www.urbanfonts.com/free-fonts.htm .

В классе деятельности мы загружаем из ресурсов объект тextView, а затем создаем объект Typeface, используя вызов статического метода Typeface . createFromAs set ( ) . Метод createFromAs set ( ) принимает два пара­метра:

О объект As setManager, который можно получить вызовом метода getAs sets ( ) ;

О путь к файлу актива.

Например, загрузить шрифт для. текстового поля тextView можно следующим способом :

TextView text

Typeface face ( TextView ) findViewByid ( R . id . text_i ) ;

Typeface . createFromAsset ( getAssets ( ) , " font s / l ibertine_it . ttf" ) ;

text . setTypeface ( face ) ;

Полный код класса деятельности FontsActi vi ty приводится в листинге 1 6 .20.

package com . samples . fonts ;

import android . app . Activity; import android . graphics . Typeface ; import android . os . Bundle ;

import android . widget . TextView ;

Page 378: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

376

puЬlic class FontsActivity extends Act ivity

@ Override

puЬlic void onCreate ( Bundle savedinstanceState )

super . onCreate ( savedinstanceState ) ;

setContentView ( R . layout . main ) ;

/ 1 загружаем шрифты для текстовых полей

final TextView text l ( TextView ) findViewByid ( R . i d . text l ) ;

text l . setTypeface (Typeface . createFromAsset (

getAssets ( ) , " font s / l ibertine_it . tt f " ) ) ;

final TextView text2 ( TextView ) findViewByid ( R . i d . text2 ) ;

text2 . setTypeface (Typeface . createFromAsset (

getAs sets ( ) , " font s /abaddon . ttf" ) ) ;

final TextView textЗ ( T extView ) findViewByid ( R . id . textЗ ) ;

textЗ . setTypeface (Typeface . createFromAsset (

getAssets ( ) , " font s /apapa . tt f " ) ) ;

f inal TextView text 4 ( TextView ) findViewByid ( R . i d . text 4 ) ;

text 4 . setTypeface (Typeface . createFromAsset (

getAssets ( ) , " fonts /ayummyapology . ttf" ) ) ;

Рис. 1 6.6. Загрузка шрифтов , сохраненных в каталоге assets/

Глава 1 6

Page 379: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

Ресурсы, активы и локализация приложений 377

Внешний вид приложения, запущенного в эмуляторе мобильного устройства, показан на рис. 1 6 .6 .

1 6 .7 . Локал иза ция приложений Приложения для платформы Android могут работать н а устройствах во мно­гих регионах. Чтобы привлечь больше пользователей, ваше приложение должно обрабатывать текстовые, аудиофайлы, числа, валюту и графику спо­собами , соответствующими настройкам или языкам тех регионов, где ваше приложение будет использоваться.

Хорошая практика программирования под Android заключается в использо­вании файлов ресурсов, чтобы отделить содержание приложения от логики работы приложения . Обычно локализуют строкавые свойства элементов пользовательского интерфейса, но в принципе можно локализовать и другие компоненты приложения, например разметку, создав отдельную разметку для каждого региона или языка.

1 6 .7 . 1 . Ресурсы, заданные по умол чанию

Всякий раз, когда приложение запускается с настрой ками региона (или языка), для которого вы не создали локализованные строкавые ресурсы, сис­тема Android загружает заданные по умолчанию строки из файла res/values/strings.xm l . Если заданный по умолчанию ресурс отсутствует или в нем отсутствует требуемая строка, то приложение не запустится и сгенери­рует исключение.

Чтобы предотвратить запуск приложения с ошибкой, удостоверьтесь, что файл res/values/strings.xml существует и определяет каждую необходимую строку. Данное требование применимо ко всем типам ресурсов, а не только к строкам : вы должны создать набор заданных по умолчанию файлов ресурса, содержащих все ресурсы, которые ваше приложение загружает, - разметки, изображения, анимацию и т. д.

При создании локализованного приложения исследуйте в программнам коде каждую ссылку на ресурсы. Удостоверьтесь, что заданн ы й по умолчанию ре­сурс определен для каждого. Также удостоверьтесь, что заданный по умолча­нию строкавый файл содержит все необходимые строки. Локализованный строкавый файл может содержать подмножество строк, но заданный по умолчанию строкавый файл должен содержать их все - если какая-либо строка отсутствует в локал изованном файле, загрузится версия строки, опре­деленная в ресурсах по умолчанию.

Page 380: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

378 Глава 1 6

1 6 .7 .2 . Создание локал изованных ресурсов

Чтобы создать дополнител ьный ресурс для конкретного региона или языка, необходимо использовать спецификатор, который определяет комбинацию региона и языка. Пример спецификаторов приведен в табл . 1 6 . 1 .

Таблица 1 6. 1 . Спецификаторы локализованных ресурсов

Локальный код Язык 1 Страна Размещение фа йла stri ngs.xml

Default Engl ish 1 U nited Kingdom res /va lues /

ru-rRU Russian 1 Russia res /va lues- ru/

de-rDE German 1 Ge rmany res /values-de /

ja-rJ P J apa nese 1 J apan res /values-j a/

fr-rFR French 1 France res /va lues-fr/

fr-rCA French 1 Canada res /value s - fr /

en-rCA Engl ish 1 Canada res /values /

en-rUS English 1 Un ited States res /values /

Как видно из таблицы, английский язык является заданным по умолчанию и для него нет смысла определять отдельный ресурс, создавая каталог res/val ues-en/.

Давайте создадим локализованное приложение, переведя на русский язык интерфейс приложения для работы с базой данных контактов из предыдущей главы . При создании проекта мастер создает под каталогом res/ папки по умолчанию.

В каталоге res/ создадим дополнительную папку values-ru/ - каталог для русской локализованной версии . В этот каталог мы поместим локализован­ную версию файла строковых ресурсов, как показано на рис. 1 6 .7 .

На основе английского файла создайте файл для русской версии приложения, переведя все строки, находящиеся в нем, на русский язык, как показано в листинге 1 6 .2 1 . Сохраните файл в каталоге res/values-ru/.

i3 ·� res ii! i1:7 dr аwаЫе iiJ GiJ, layout i3 i1:7 values

• · · l.i!J strings . xml i3 · tz,. values-ru

l.i!J strings . xml

Рис. 1 6.7. Каталоги с локализованными строковыми ресурсам и

Page 381: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

Ресурсы, активы и локализация приложенuй

<?xml version= " . 0 " encoding= "ut f- 8 " ?>

<resources>

<string nаmе=" арр_nаmе " >Загрузка контактов из базы дaнныx</string>

<string name="btn_ok" >Coxpaнить < / s t ring>

<string name="btn_cance l " >Oтмeнa< / s t ring>

<string name= " field_name " >Имя : < / string>

<string name=" field_phone " >Teл . : </st ring>

<string name=" t itle_add" >Дoб�вить новый кoнтaкт</string>

<string name=" t itle_edi t " >Измeнить кoнтaкт</string>

<st ring name=" t it l e_delete " >Yдaлить кoнтaкт ?</string>

<string name="menu_add " >Дoбaвить </st ring>

<string name="menu_edit " >Измeнить < / s tring>

<string name="menu_delete " >Yдaлить < / s t ring>

<string name= " toast_notify">выбepитe кoнтaкт ! < / st ring>

< / resources>

379

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

Теперь поменяйте язык. Для этого откройте панель Application Launcher и выберите последовательно Settings 1 Language & keyboard 1 Select locale 1 Русский, как показано на рис. \ 6 . 8 .

Рис. 1 6.8. Установка языковых настроек в эмуляторе

Page 382: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

380 Глава 1 6

Снова зайдите в Application Launcher. Теперь наше приложение в Application Launcher называется Заrрузка контактов нз базы данных. За­пустите его . Приложение и все его диалоговые окна будут на русском языке. Внешний вид локализованного приложения с русским языком интерфейса, запущенного в эмуляторе мобильного устройства, показан на рис. 1 6 .9 .

Р и с . 1 6.9. Локализованное nриложение д л я редактирован ия конта ктов

Page 383: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

Г Л А В А 1 7

Графика

В этой главе мы обсудим варианты применения графики в Аndrоid-прило­жениях. Также будут рассмотрены основы использования объектов DrawaЬle

для работы с графикой.

Графику в приложении можно создавать двумя способами:

D нарисовав графику в объекте View из разметки;

D нарисовав графику непосредственно на канве.

Рисование графики в объекте view является лучшим выбором, если требуется нарисовать простую графику, которая не будет динамически изменяться в процессе работы приложения, и не является реализацией сложной графиче­ской игры .

1 7 . 1 . Объект DrawaЬ/e Android предлагает двумерную графическую библиотеку рисования на фор­мах и изображениях - android . graphics . drawaЬle.

Класс DrawaЬle является базовым классом для всех классов работы с графи­кой . Это общая абстракция для рисуемого объекта. Класс DrawaЬle определя­ет разнообразные виды графики, включая BitmapDrawaЬle, ShapeDrawaЬle,

PictureDrawaЬle, LayerorawaЬle и др. Диаграмма графических классов Android представлена на рис. 1 7 . 1 .

Есть два способа определить и инициал изировать объект DrawaЬle:

D использовать изображения, сохраненные в каталоге res/drawaЬle/;

D использовать ХМL-файл, в котором будут определены свойства объекта DrawaЬle.

Page 384: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

382 Глава 1 7

1 Object 1 DrawaЫe 1

BitmapDrawaЫe 1 ClipDrawaЫe 1

ColorDrawaЫe 1 DrawaЫeContainer 1

AnimationDrawaЫe 1 LeveiListDrawaЫe 1 StateListDrawaЫe 1

GradientDrawaЫe 1 lnsetDrawaЫe 1 LayerDrawaЫe 1

TransitionDrawaЫe 1 N inePathDrawaЫe 1

PictureDrawaЫe 1 RotateDrawaЫe 1 ScaleDrawaЫe 1

ShapeDrawaЫe 1 PaintDrawaЫe 1

Рис. 1 7. 1 . Иерархия графических классов

Самый простой способ добавить графику в приложение - это ссылка на за­грузочный модуль проектных ресурсов. Поддерживаем ые типы файлов:

D PNG - предпочтительный тип ;

D JPEG - приемлемый тип;

D GIF - нежелательный тип .

Загрузка через ссылку на ресурсы предпочтительна для значков, картинок или другой графики в приложении . Этот способ загрузки графических ресур­сов мы и нтенсивно использовали в создаваемых приложениях на протяжении всей книги.

Ресурсы изображений, помещенные в res/drawaЬie/ во время компиляции проекта, могут быть автоматически оптимизированы со сжатием изображе­ния утилитой aapt. Это приводит к изображению равного качества, но при этом требуется меньший объем памяти на мобильном устройстве. Если тре-

Page 385: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

Графика 383

буется загружать растровые изображения (* .bmp, которые утилита aapt обяза­тельно оптимизирует) без сжатия, поместите их в каталог res/raw/, где они не будут оптим изироваться утилитой aapt . Однако потребуется загрузка с ис­пользованием методов потокового ввода-вывода и последующая конвертация графики в растровый рисунок.

1 7 . 2 . Созда ние объектов DrawaЬ/e в коде п рограм м ы В других случаях вы можете захотеть обработать ваш ресурс изображения как объект DrawaЬle. Чтобы это сделать, создайте DrawaЬle, загрузив изобра­жение из ресурсов примерно так:

Resources res mContext . getResources ( ) ;

DrawaЬle myimage res . getDrawaЬle ( R . drawaЬle . my_image ) ;

Каждый уникальный ресурс в вашем проекте может поддерживать только одно состояние независимо от того, сколько различных объектов вы можете инициализировать в программ нам коде для этого ресурса. Например, если вы инициализируете два объекта orawaЬle от одного ресурса изображения, а за­тем измените свойство, например alpha (прозрачность), для одного из объек­тов DrawaЬle, другой объект также изменит это свойство .

К настоящему времени вы должны быть знакомы с принципами разработки интерфейса пользователя. Следовательно, вы понимаете силу и гибкость, свойственную определению объектов в XML. Если есть объект DrawaЫe, ко­торый вы хотели бы создать и который первоначально не зависит от пере­менных, определенных вашим программным кодом или пользовательским взаимодействием, то определение DrawaЬle в XML - наилучшее решение. Даже если вы ожидаете, что ваш объект DrawaЫe изменит свои свойства в течен ие работы пользователя с приложением, вы должны задать начал ьные свойства объекта DrawaЬle в XML, поскольку вы можете всегда изменять свойства после создания этого объекта в коде программ ы .

Как только вы определили ваш DrawaЬle в ХМL-файле, сохраните этот файл в каталоге res/drawaЫe/ вашего проекта. Затем загрузите и инициал изируйте объект, вызвав метод Resources . getDrawaЫe ( ) и передав ему в качестве пара­метра идентификатор ресурса вашего ХМL-файла. Любой подкласс, произ­водный от класса DrawaЫe, который поддерживает метод inflate ( ) , может быть определен в XML и инициализироваться в коде приложения .

В следующих разделах мы подробно рассмотрим использование объектов DrawaЫe в коде программы .

Page 386: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

384 Глава 1 7

1 7 .2. 1 . Класс TransitionDrawaЬ/e

Одна из возможностей использования объектов DrawaЬle - загрузка карти­нок с плавными переходами. Создание переходов между изображениями с

помощью класса Transi tionDrawaЬle лучше рассмотреть на примере. Создай­те в Ecl ipse новый проект и заполните поля в окне New Android Project :

а Project name - Transi tion;

а Application name - Transi tiori Sample;

а Package name - сот . samples . transi tion;

а Create Activity - TransitionActivity.

В файле разметки для деятельности создайте один элемент ImageView, как по­казана в листинге 1 7 . 1 .

<?xml version= " l . O " encoding="utf-8 " ?> <LinearLayout xmlns : android="http : / /schemas . android . com/apk/ res/android"

android : orientation="vertical " android : layout_width=" fil l_parent" android : layout_height=" fil l_parent " android : gravity="center">

<ImageView android : id="@+id/image " android : layout_width="wrap_content " android : layout_height="wrap_content " android : src="@drawaЬle/photol " />

</LinearLayout>

В каталоге res/drawaЬie/ проекта создадим два графических файла, photo J .j pg и photo2 .jpg. Их можно взять на компакт-диске, прилагаемом к книге из пап­ки Resources/, или в вашем каталоге Aпdroid SDK - графика, используемая в примерах, взята из каталога aпdroid-sdk-wiпdows/platforms/aпdroid-2/samples/ ApiDemos/res/drawaЫe/.

В каталоге res/drawaЬie/ проекта также создадим файл traпsitioп .xml , в ко­тором определим переход. Код файла transit ion.xml представлен в листин­ге 1 7 .2 .

Page 387: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

Графика 385

<?xml version= " l . O " encoding= " ut f-8 " ?> <trans ition xmlns : android= "http : / /schemas . android . com/apk/res/android " >

< item androi d : drawaЬle= " @drawaЬle /photol " ></item> <item android : drawaЬle=" @drawaЬle/photo2 " > </ item>

</trans ition>

В классе деятельности LoadimageActivity создадим объект Trans itionDrawaЬle

и установим его как содержание ImageView:

Resources res thi s . getResources ( ) ;

mTrans ition ( T ransitionDrawaЬl e ) res . getDrawaЬle ( R . drawaЬle . trans ition ) ;

Также в классе LoadimageActi vi ty создадим обработчик onClick ( ) , при вызове которого будет происходить смена картинок с плавным переходом в течение 1 секунды :

t rans ition . startTrans ition ( l O O O ) ;

Полный код класса LoadimageActivity представлен в листинге 1 7 .3 .

package com . samples . loadimage ;

import android . app . Activity; import android . content . res . Resources ;

import android . graphics . drawaЬle . Trans itionDrawaЬle ;

import android . os . Bundle ; import android . view . View;

import android . view . View . OnCl ickListene r ;

import android . widget . ImageView;

puЬlic class T ransitionAct ivity extends Act ivity

implements OnClickListener

private ImageView image ; private Trans itionDrawaЬle mTrans ition ;

@Ove rride

puЬlic void onCreate ( Bundle savedinstanceState )

supe r . onCreate ( savedinstanceState ) ;

setContentView ( R . layout . main ) ;

image ( ImageView ) findViewByid ( R . id . image ) ;

image . setOnClickListener ( this ) ;

Page 388: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

386

Resources res this . getResources ( ) ;

mTrans ition (Trans itionDrawaЬl e ) res . getDrawaЬle (

R . drawaЫe . trans ition ) ;

1 1 nереключаем картинки с эффектом плавного 11 перехода в течение 1 секунды

@ Override puЬlic void onClick (View v ) {

image . setimageDrawaЬle (mTransition ) ;

mTrans ition . startTrans ition ( l O O O ) ;

Глава 1 7

Запустите проект н а выпол нение . При касании экрана (нажатии правой кноп­ки мыши в области экрана эмулятора) будет происходить плавное переклю­чение фотографий (рис. 1 7 .2) .

Рис. 1 7.2. Переходы между изображения м и

1 7 . 2 . 2 . Класс ShapeDrawaЬ/e

Если вы хотите динамически рисовать разл ичные двумерные фигуры, класс ShapeDrawaЬle вполне удовлетворит ваши потребности. С объектами ShapeDrawaЫe вы можете программно создава�ь любые примитинные формы и их стили .

Page 389: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

Графика 387

Для создания графических Примитивов в библиотеке Android есть набор классов, производных от базового класса Shape :

о PathShape;

о RectShape;

о ArcShape;

о OvalShape;

о RoundRectShape.

Иерархия классов графических примитивов представлена на рис. 1 7 .3 .

Object 1 г-----, L___--1 Shape 1 �_,,_� ,--------,

PathShape 1 RectShape 1

г--------, ArcShape 1

1

OvaiShape 1 RoundRectShape 1

Рис. 1 7.3 . Иерархия классов графических примитивов

Класс ShapeDrawaЬle - расширение класса DrawaЬle, так что вы можете ис­пользовать его так же, как и любой другой объект orawaЬle. В конструкторе ShapeDrawaЬle рисуемый графический примитив определяется как RectShape,

т. е . hрямоугольник. Также для объекта ShapeorawaЬle необходимо установить цвет и границы фигуры. Если вы не установите границы, то графический прим итив не будет рисоваться . Если вы не установите цвет, фигура будет черной - значение по умолчанию.

Класс RectShape также можно использовать для рисования горизонтальных или вертикальных линий . Для этого надо задать высоту (или ширину) прямо­угольника в 1 -2 пиксела, например:

ShapeDrawaЬle d new ShapeDrawaЬle ( new RectShape ( ) ) ; d . set intrins icHeight ( 2 ) ; d . set int rins icWidth ( l 5 0 ) ; d . getPaint ( ) . setColor ( Color . МAGENTA) ;

Аналогично прямоугольнику прорисовывается объект oval Shape (эллипс):

ShapeDrawaЬle d new ShapeDrawaЬle ( new OvalShape ( ) ) ; d . setint r insicHeight ( l OO ) ; d . set intrinsicWidth ( l 5 0 ) ;

d . get Paint ( ) . setColor ( Color . RED ) ;

Page 390: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

388 Глава 1 7

Прорисовка прямоугольника с закругленными сторонами (Round.Rect) не­сколько сложнее . Конструктор класса Round.Rect для рисования прямоуголь­ника с закругленными сторонами принимает несколько параметров:

Round.RectShape ( float [ ] outerRadi i , RectF inset , float [ ] innerRadii )

Параметры конструктора RoundRectShape :

D outerRadi i - массив из восьми значений радиуса закругленных сторон внешнего прямоугольника. Первые два значения для верхнего левого угла, остальные пары отсчитываются по часовой стрелке от первой пары. Если на внешнем прямоугольнике закруглений не будет, передается nul l;

D inset - объект класса RectF, который определяет расстояние от внутрен­него прямоугольника до каждой стороны внешнего прямоугольника. Кон­структор Rect F принимает четыре параметра: пары Х и У координат лево­го верхнего и правого нижнего углов внутреннего прямоугольника. Если внутреннего прямоугольника нет, передается nul l;

D innerRadi i - массив из восьми значений радиуса закруглений углов для внутреннего прямоугольника. Первые два значения - координаты верх­него левого угла, остальные пары отсчитываются по часовой стрелке от первой пары. Если на внутреннем прямоугольнике закруглений не будет, передается nul l .

Например, создание прямоугольника с закругленными сторонами может вы­глядеть следующим образом :

float [ ] outR

RectF rectF

float [ ] inR

new float [ ] б , б , б , б , б , б , б , б

new RectF ( 8 , 8 , 8 , 8 ) ;

new float [ ] { б , б , б , б , б , б , б , б

ShapeDrawaЬle d new ShapeDrawaЬle (

new Round.RectShape ( outR, rectF, inR ) ) ;

d . setintrins icHeight ( l O O ) ;

d . set intrins icWidth ( l 5 0 ) ;

d . getPaint ( ) . setColor ( Color . WHITE ) ;

Класс Path формирует множественный контур геометрических путей, со­стоящих из прямых линейных сегментов, квадратичных и кубических кри­вых. Для установки точек и перемещения линий (или кривых) используются открытые методы moveTo ( ) и l ineTo ( ) . Например, так с помощью класса Path

можно нарисовать пятиконечную звезду:

Path р new Path ( ) ;

p . moveTo ( 50 , 0 ) ;

p . l ineTo ( 2 5 , 1 0 0 ) ;

Page 391: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

Графика

p . l ineTo ( l 0 0 , 5 0 ) ;

p . l ineTo ( 0 , 5 0 ) ;

p . l ineTo ( 7 5 , 1 0 0 ) ;

p . l ineTo ( 50 , 0 ) ;

ShapeDrawaЬle d = new ShapeDrawaЬle ( new PathShape ( p , 1 0 0 , 1 0 0 ) ) ;

d . set intrinsicHeight ( 1 0 0 ) ;

d . setint rinsicWidth ( 1 0 0 ) ; d . getPaint ( ) . setColor ( Color . YELLOW) ;

d . getPaint ( ) . setStyle ( Paint . Style . STROКE ) ;

389

Класс ArcShape создает графический примитив в форме дуги . Конструктор класса принимает два параметра:

ArcShape ( float startAngl e , float sweepAngle )

Первый параметр в конструкторе - угол начала прорисовки дуги в градусах, второй - угловой размер дуги в градусах.

Класс ShapeDrawaЬle, подобно многим другим типам DrawaЬle, входящим в пакет android . graphics . drawaЬle, позволяет определять различные свойства рисунка с помощью набора открытых методов, например setAlpha ( ) - для установки прозрачности, setColorFil ter ( ) и т. д.

Продемонстрируем работу с классом ShapeDrawaЬle и подклассами Shape на примере приложения, которое будет прорисовывать в объекте IrnageView раз­личные графические примитивы. Создайте в Ecl ipse новый проект и заполни­те поля в окне New Android Project:

D Project name - ShapeDrawaЬle;

D Application name - ShapeDrawaЬle Sample;

D Package name - сот . sarnples . shapedrawaЬle;

D Create Activity - ShapeDrawaЬleActivity.

Создайте файл разметки с единственным виджетом IrnageView, как показано в листинге 1 7 .4.

< ?xrnl vers ion= " 1 . 0 " encoding= "utf-8 " ?>

<LinearLayout xrnlns : android= " http : / / schernas . android . com/apk/res/android"

android : id= " @+id/ root "

android : layout_width=" fi l l_parent "

android : layout_height=" fi l l_parent "

android : orientation= " horizontal "

android : layout_gravity= "center_vertical l center_horizontal " >

Page 392: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

390

<IrnageView

android : id= " @ + id/ image "

android : layout_width= "wrap_content "

android : layout_height="wrap_content "

android : minHeight= " 90px "

android : minWidth= " 9 0px "

android : layout_rnargin= " l l 5px " / >

< /LinearLayout>

Глава 1 7

В классе деятельности DrawCanvasActivity приложения создадим меню из шести опций :

1 . Line - прорисовка линии .

2 . Oval - прорисовка элл ипса.

3. Rectangle - прорисовка прямоугольника.

4 . RoundRect. Fill - прорисовка прямоугольника с закругленными углами .

5 . Path - прорисовка пятиконечной звезды с помощью линий .

6 . Arc - прорисовка дуги.

При выборе пункта меню в элементе Imageview будет прорисовываться соот­ветствующий графический примитив . В методе обратного вызова onCreateOptionsMenu ( ) реализованы приведеиные ранее фрагменты кода про­рисовки фигур. Полный код класса DrawCanvasActivity представлен в листинге 1 7 . 5 .

package com . samples . shapedrawaЬle ;

import android . app . Activity;

import android . graphics . Color ;

import android . graphics . Paint ;

irnport android . graphics . Path;

import android . graphics . RectF;

import android . graphics . drawaЬle . ShapeDrawaЬle ;

import android . graphics . drawaЬle . shapes . ArcShape ;

import android . graphics . drawaЬle . shapes . OvalShape ;

import android . graphics . drawaЬle . shapes . PathShape ;

import android . graphics . drawaЫe . shapes . RectShape ;

import android . graphics . drawaЬle . shapes . RoundRectShape ;

import android . os . Bundle ;

Page 393: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

Графика

import android . view . Menu ;

import android . view . Menuitem;

import android . widget . ImageView;

puЬlic c1ass ShapeDrawaЬleActivity extends Act ivity

11 идентификаторы опций меню private static fina1 int I DM LINE 1 0 1 ;

private static fina1 int I DM OVAL 1 0 2 ;

private static fina1 int I DM RECT 1 0 3 ;

private static fina1 int I DM ROUNDRECT 1 0 4 ; private static fina1 int I DM STAR 1 0 5 ;

private static fina1 int I DM ARC 1 0 6 ;

private ImageView mimage ;

@ Override

protected void onCreate ( Bund1e s avedinstanceState )

super . onCreate ( savedinstanceState ) ;

setContentView ( R . 1ayout . main ) ;

mimage ( ImageView ) findViewByid ( R . id . image ) ;

@ Override

puЫi c boo1ean onCreateOptionsMenu ( Menu menu )

391

menu . add (Menu . NONE , I DM_LINE , Menu . NONE , " Line " ) ;

menu . add (Menu . NONE , I DM_OVAL , Menu . NONE , " Ova1 " ) ;

menu . add (Menu . NONE , I DM_RECT , Menu . NONE , "Rectang1e " ) ;

menu . add (Menu . NONE , I DM_ROUNDRECT , Menu . NONE , "Round Rect . Fi1 1 " ) ;

menu . add (Menu . NONE , I DM_STAR, Menu . NONE , " Path" ) ;

menu . add (Menu . NONE , I DM_ARC , Menu . NONE , "Arc " ) ;

return ( super . onCreateOptionsMenu (menu ) ) ;

@ Override

puЬl i c boo1ean onOptions itemSe1ected (Menuitem i tem)

ShapeDrawaЫe d nu1 1 ;

switch ( item . getitemid ( ) )

case I DM LINE :

d new ShapeDrawaЬle ( new RectShape ( ) ) ;

d . set intrinsicHeight ( 2 ) ;

Page 394: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

392

d . set intrinsi cWidth ( 1 50 ) ;

d . get Paint ( ) . setCo1or ( Co1or . МAGENTA) ;

break;

case I DM OVAL :

d new ShapeDrawaЬle ( new Ova1 Shape ( ) ) ;

d . set intrinsicHeight ( 1 0 0 ) ;

d . set intrins icWidth ( 1 50 ) ;

d . getPaint ( ) . setCo1or ( Co1or . RE D ) ;

break ;

case I DM RECT :

d = new ShapeDrawaЬle ( new RectShape ( ) ) ;

d . set intrinsicHeight ( 1 0 0 ) ;

d . set intrinsicWidth ( 1 5 0 ) ;

d . get Paint ( ) . setCo1or ( Co1or . BLUE ) ;

break;

case I DM ROUNDRECT :

Глава 1 7

f1oat [ ] outR = new f1oat [ ] б , б , б , б , б , б , б , б RectF rectF = new Rect F ( 8 , 8 , 8 , 8 ) ;

float [ ] inR = new float [ ] ( б , б , б , б , б , б , б , б

d = new ShapeDrawaЬ1e (new RoundRectShape ( outR, rectF, inR) ) ;

d . set intrinsicHeight ( 1 0 0 ) ; d . set intrinsicWidth ( 1 50 ) ;

d . get Paint ( ) . setCo1or ( Co1or . . WНITE ) ;

break ;

case I DM STAR :

Path р new Path ( ) ;

p . moveTo ( 5 0 , 0 ) ;

p . 1 ineTo ( 2 5 , 1 0 0 ) ;

p . 1 ineTo ( 1 0 0 , 5 0 ) ;

p . 1 ineTo ( 0 , 50 ) ;

p . 1 ineTo ( 7 5 , 1 0 0 ) ;

p . 1 ineTo ( 5 0 , 0 ) ;

d = new ShapeDrawaЬle ( new PathShape ( p , 1 0 0 , 1 0 0 ) ) ;

d . set intrinsicHeight ( 1 0 0 ) ;

d . setint rinsicWidth ( 1 0 0 ) ; d . get Paint ( ) . setCo1or ( Co1or . YELLOW ) ;

d . get Paint ( ) . setSty1e ( Paint . Sty1e . STROКE ) ;

break;

case I DM ARC :

d = new ShapeDrawaЬle ( new ArcShape ( O , 2 5 5 ) ) ;

d . set intrinsicHeight ( 1 0 0 ) ;

Page 395: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

Графика

d . set intrins i cWidth ( l O O ) ;

d . getPaint ( ) . setColor ( Color . YELLOW ) ;

break;

mimage . setBackgroundDrawaЬle ( d ) ;

return true ;

393

Скомпилируйте и запустите проект на выполнение. При выборе пункта меню на поверхности виджета ImageView будет прорисовываться соответствующий графический примитив (рис. 1 7 .4).

Рис. 1 7.4. Соэдание графических примитивое

1 7 . 3 . Рисован ие на кан ве Рисование на канве лучше всего использовать, когда окно приложения долж­но регулярно себя перерисовывать во время работы приложения . Например, при разработке игр необходимо создавать постоянно меняющуюся графику. Динамическое рисование на канве - процесс довольно медленный . Всего существует два способа реализации рисования на канве:

D в основном потоке программы, в котором запускается деятельность, вы создаете собственный компонент View, затем вызываете метод

Page 396: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

394 Глава 1 7

invalidate ( ) и обрабатываете создание графики в методе обратного вызо­ва onDraw ( ) ;

О в отдел ьном потоке - через объект Surfaceview.

Класс canvas имеет собственн ы й набор методов для рисования, которые вы можете использовать, например drawBi tmap ( ) , drawRect ( ) , drawтext ( ) и мно­гие другие. Другие классы, которые вы могли бы использовать, также имеют методы draw ( ) . Например, можно создать объекты DrawaЫe и передать их для прорисовки на канву. Класс DrawaЫe имеет собственный метод draw ( ) , кото­рый принимает объект canvas как параметр.

Канва фактически является поверхностью, на которой ваша графика будет рисоваться. Когда вы выполняете прорисовку в пределах метода обратного вызова View . onDraw ( ) , система передает в качестве параметра объект Canvas.

Вы можете также получить объект Canvas вызовом метода SurfaceHolder .

lockCanvas ( ) , если имеете дело с объектом SurfaceView.

Система Android вызывает метод onDraw ( ) по мере необходимости. Каждый раз, когда ваше изображение на канве представления требует перерисовки, необходимо вызывать метод inval idate ( ) . Он требует от системы обновления представления, и система Android тогда вызовет ваш метод onDraw ( ) .

Поскольку ShapeDrawaЫe имеет свой собственный метод draw ( ) , вы можете создать подкласс View, который рисует ShapeDrawaЫe в коде метода обратного вызова View . onDraw ( ) , например:

class CustomView extends View

private ShapeDrawaЫe mDrawaЬle ;

@Ove rride protected void onDraw ( Canvas canvas )

1 1 создаем прямоугольник mDrawaЫe new ShapeDrawaЬle ( new RectShape ( ) ) ;

mDrawaЫe . set intrins icHeight ( 2 ) ;

mDrawaЬle . set intrins icWidth ( l 50 ) ;

mDrawaЬle . get Paint ( ) . setColor ( Color . МAGENTA) ;

/ 1 выводим прямоугольник на канву

mDrawaЫe . draw ( canvas ) ;

Взяв за основу предыдущий пример, где мы загружали графические прими­тины в фон виджета Imageview, создадим приложение, которое будет прори-

Page 397: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

Графика 395

совывать те же прим итивы на канве представления. Создайте в Ec l ipse новый проект и заполните поля в окне New Android Project:

О Project name - Canvas ;

О Application name - Draw o n Canvas Sarnple;

О Package name - сот . sarnples . canvas ;

О Create Activity - DrawCanvasActivity.

В приложении кроме класса деятельности DrawCanvasActivity потребуется дополнительный класс DrawCanvasView, производны й от класса View, который и будет исполнять роль поверхности для рисования наших фигур. Объект DrawCanvasView будет основным представленнем для окна деятельности при­ложения .

После создания графического примитива объект ShapeDrawaЬle передается в объект DrawCanvasView для прорисовки на канве. Код класса деятельности DrawCanvasActivity представлен в листинге 1 7 .6 .

package com . sarnples . canvas ;

import android . app . Activity;

import android . graphics . Color ;

import android . graphics . Paint ;

import android . graphics . Path;

import android . graphics . RectF;

import android . graphics . drawaЫe . ShapeDrawaЫe ;

import android . graphics . drawaЫe . shapes . ArcShape ;

import android . graphics . drawaЬle . shapes . OvalShape ;

import android . graphics . drawaЬle . shapes . PathShape ;

import android . graphics . drawaЬle . shapes . RectShape ;

import android . graphics . drawaЬle . shapes . RoundRectShape ;

import android . os . Bundle ;

import android . view . Menu ;

import android . view . Menuitem;

puЬlic class ShapeDrawaЬleActivity extends Activity

1 1 идентификаторы опций меню puЬlic stat i c final int I DM LINE 1 0 1 ;

puЫ ic static f inal int I DM OVAL 1 0 2 ;

puЬlic static f inal int I DM RECT 1 0 3 ;

puЬlic stat ic final int I DM ROUNDRECT 1 0 4 ;

Page 398: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

396 Глава 1 7

puЫ ic static fina1 int I DM STAR 1 0 5 ;

puЬlic static fina1 int I DM ARC 1 0 6 ;

private DrawCanvasView rnView ;

@Override

protected void onCreate ( Bund1e savedinstanceState )

super . onCreate ( savedinstanceState ) ;

11 создаем nредставление - объект , в который

1 1 будем выводить фигуры

rnView new DrawCanvasView ( this ) ;

setContentView (rnView ) ;

@Override

puЬ1ic boo1ean onCreateOptionsMenu ( Menu rnenu )

Fi l l " ) ;

rnenu . add (Menu . NONE , r oм_LINE , Menu . NONE , " Line " ) ;

rnenu . add (Menu . NONE , I DM_OVAL , Menu . NONE , "Ova1 " ) ;

rnenu . add (Menu . NONE , I DM_RECT , Menu . NONE , "Rectang1e " ) ;

rnenu . add ( Menu . NONE , I DM_ROUNDRECT , Menu . NONE , "Round Rect .

rnenu . add (Menu . NONE , I DM_STAR, Menu . NONE , " Path" ) ;

rnenu . add ( Menu . NONE , I DM_ARC , Menu . NONE , "Arc" ) ;

return ( supe r . onCreateOptionsMenu (rnenu ) ) ;

@Override

puЬ1ic boo1ean onOptions iternSe1ected (Menuitern i tern)

ShapeDrawaЫe d new ShapeDrawaЬle ( ) ;

switch ( itern. getiternid ( ) ) { case I DM LINE :

d new ShapeDrawaЬle ( new RectShape ( ) ) ;

d . setintrinsicHeight ( 2 ) ;

d . setintrins icWidth ( l 50 ) ;

d . getPaint ( ) . setCo1or ( Co1or . МAGENTA) ;

break ;

case I DM OVAL :

d new ShapeDrawaЬle (new Ova1Shape ( ) ) ;

d . setintrinsicHeight ( l O O ) ;

d . setintrins i cWidth ( l 5 0 ) ;

d . getPaint ( ) . setCo1or ( Co1or . RE D ) ;

break;

Page 399: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

Графика

case I DM RECT :

d new ShapeDrawaЬle ( new RectShape ( ) ) ;

d . setintrinsicHeight ( 1 0 0 ) ;

d . setintrinsi cWidth ( 1 5 0 ) ;

d . getPa int ( ) . setColor ( Color . BLUE ) ;

break;

case I DM ROUNDRECT :

float [ ] outR new float [ ] 6 , 6 , 6 , 6 , 6 , 6 , 6 , 6 RectF rectF

float [ ) inR

new Rect F ( 8 , 8 , 8 , 8 ) ;

new float [ ] { 6 , 6 , 6 , 6 , 6 , 6 , 6 , 6

d new ShapeDrawaЬle (new RoundRectShape ( outR, rect F

d . set intrins i cHeight ( 1 0 0 ) ;

d . set int r insicWidth ( 1 5 0 ) ;

d . getPaint ( ) . setColor ( Color . WHITE ) ;

break;

case I DM STAR :

Path р new Path ( ) ;

p . moveTo ( 5 0 , 0 ) ;

p . l ineTo ( 2 5 , 1 0 0 ) ;

p . l ineTo ( 1 0 0 , 5 0 ) ;

p . l ineTo ( 0 , 50 ) ;

p . l ineTo ( 7 5 , 1 0 0 ) ;

p . l ineTo ( 5 0 , 0 ) ;

d new ShapeDrawaЬle ( new PathShape ( p , 1 0 0 , 1 0 0 ) ) ;

d . setintrinsicHeight ( 1 0 0 ) ;

d . setint rinsi cWidth ( 1 0 0 ) ;

d . getPaint ( ) . setColor ( Color . YELLOW ) ;

d . getPaint ( ) . setStyle ( Pa int . Style . STROКE ) ;

break;

case I DM ARC :

}

d new ShapeDrawaЬle ( new ArcShape ( O , 2 5 5 ) ) ;

d . setintrins icHeight ( 1 0 0 ) ;

d . setintrins icWidth ( 1 0 0 ) ;

d . getPa int ( ) . setColor ( Color . YELLOW ) ;

break;

1 1 передаем созданный объект ShapeDrawaЬle в представление

mView . setDrawaЬle ( d ) ;

return t rue ;

397

inR ) ) ;

Page 400: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

398 Глава 1 7

В классе DrawCanvasView через открытый метод setDrawaЬle ( ShapeDrawaЬle )

передается объект ShapeDrawaЬle, который будет прорисовываться на канве представления . В этом же методе вызывается invalidate ( ) , требующий от системы перерисовки представления . После выполнения система Aпdroid вы­зовет вашу реализацию метода onDraw ( ) , который производит перерисовку канвы представления .

В реализации метода обратного вызова onDraw ( ) компонента view использует­ся объект canvas, предоставляемый системой для всего вашего рисунка. Как только метод onDraw ( ) будет выполнен, система Android будет использовать ваш объект canvas, чтобы обновить графику на поверхности представления .

Полный код класса DrawCanvasView представлен в лисТИJ-!Ге 1 7 .7 .

package com . samples . canvas ;

import android . content . Context ;

import android . graphics . Canvas ;

import android . graphics . drawaЬle . ShapeDrawaЬle ;

import android . view . View;

class DrawCanvasView extends View

11 константы, определяющие начальную координату объекта private static final int START Х 1 0 ;

private static final int START У 1 0 ;

private ShapeDrawaЬle mDrawaЬle ;

puЬlic DrawCanvasView ( Context contex t )

super ( context ) ;

setFocusaЬle ( true ) ;

mDrawaЬle new ShapeDrawaЬle ( ) ;

1 1 метод, загружающий объект ShapeDrawaЬle для рисования puЬlic void setDrawaЬle ( ShapeDrawaЬle shape )

mDrawaЬle shape ;

1 1 привязываем объект ShapeDrawaЬle

mDrawaЬle . setBounds ( START_X, START_Y ,

START Х + mDrawaЬle . getintrins icWidth ( ) ,

START У + mDrawaЬle . getintrins icHeight ( ) ) ;

Page 401: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

Графика

требуем перерисовки графики inval idate ( ) ;

1 1 перерисовка графического объекта

@ Override

protected void onDraw ( Canvas canvas )

mDrawaЬle . draw ( canvas ) ;

399

Скомпилируйте и запустите проект на выполнение. Внешний вид приложе­ния похож на предыдущий пример. При выборе пун кта меню на канве пред­ставления будет прорисовываться соответствующий графический примитив (рис. 1 7 . 5 ) .

Rau11d R�ct. P•th Arr

Рис. 1 7.5. Рисование графических объекто в на канве

Page 402: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

Г Л А В А 1 8

Создан ие анимаци и

В этой главе мы обсудим создание анимации в Аndrоid-приложениях для раз­работки визуально привлекательных приложений средствами Android SDK, который предоставляет двумерную графическую библиотеку анимации на

канве и Представлениях android . view . animationpackages .

Анимация в Android представлена двумя видами:

LJ Tween Animation - анимация преобразований;

LJ Frame Animation - традиционная кадровая анимация .

1 8 . 1 . Анимация п реобразований Анимация может выполняться в виде ряда простых преобразований - пози­ции, размера, вращения и прозрачности на поверхности объекта View. Так, например, для объекта тextView возможно перемещать, вращать, уменьшать или увеличивать текст. Если объект TextView имеет фоновое изображение, оно будет преобразовано наряду с текстом. Пакет android . view .

animationpackages включает все классы, используемые в анимации с проме­жуточными кадрами . Иерархия классов анимации представлена на рис. 1 8 . 1 .

Основные классы анимации :

LJ Animat ionset - класс, представляющий группу анимаций, которые долж­ны запускаться вместе. Если класс AnimationSet устанавливает какие-либо свойства, эти свойства наследуют и объекты, входящие в группу;

LJ AlphaAnimation - класс анимации, который управляет прозрачностью объекта;

LJ RotateAnimat ion - класс анимации, который управляет вращением объ­екта;

Page 403: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

402 Глава 1 8

LJ ScaleAnimation - класс анимации, который управляет масштабированием объекта;

LJ Trans lateAnimat ion - класс анимации, который управляет позициониро­ванием объекта.

Object 1 г------,

Animation

AnimationSet 1 AlphaAnimation 1 RotateAnimation 1 ScaleAnimation 1

TranslateAnimation 1 Рис. 1 8. 1 . Классы анимации в Android

Команды анимации определяют преобразования, которые необходимо произ­вести над объектом . Преобразования могут быть последовательными или од­новременными . Каждое преобразование принимает набор параметров, опре­деленных для этого преобразования (начальный размер, конечный размер при изменении размера, стартовый угол и конечный угол при вращении объекта и т. д.), а также набор общих параметров (например, начального времени и продолжительности) . Если требуется сделать несколько преобразований одновременно, им задают одинаковое начальное время. Если требуется сде­лать последовательные преобразования, задается их время старта плюс про­должитель ность предыдущего преобразования.

Последовательность команд анимации определяется в ХМL-файле или в программ нам коде. Более предпочтителен для создания анимации ХМL­файл (аналогично определению разметки в ХМL-файле), по причине его воз­можности м ногократного использования и большей гибкости, чем при Жест­ком программ нам кодировании анимации .

1 8 . 1 . 1 . Создание анимации в ХМL-файле

ХМL-файл анимации располагают в каталоге res/an im/ проекта. Файл должен иметь единственный корневой элемент: это будет любой из элементов <alpha>, <scale>, <t rans late>, <rotate> или элемент <set>, который является контейнером для этих четырех компонентов (и может включать в себя другой контейнер <set> ). Пример возможной иерархии элементов ХМ L-файла ани­мации показан на рис. 1 8 .2 .

Page 404: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

Создание анимации 403

1 <set> 1 <set> 1

<scale> 1 <translate> 1

<set> 1 <scale> 1

<translate> 1 <alpha> 1

<alpha> 1 <scale> 1

<translate> 1 <rotate> 1

Р ис. 1 8.2 . Пример структуры ХМL-файла анимации

По умолчанию все элементы применяются одновременно. Чтобы запускать элементы последовательно, необходимо определить атрибут startOffset и указать значение в миллисекундах, например:

android : startOffset= " З O O O "

Эти вышеперечисленные элементы управления анимацией содержат м ноже­ство атрибутов. Рассмотрим их подробнее.

Общие атрибуты У элементов <alpha>, <scale>, <trans late>, <rotate> и <set> поддерживаются общие атрибуты, унаследованные от базового класса Animation:

Ll durat ion - продолжительность эффекта в миллисекундах;

Ll startOffset - начальное время смещения для этого эффекта, в милли­секундах;

Ll f i llBe fore - когда установлен в true, то преобразование анимации при­меняется перед началом анимации;

Ll fillAfter - когда установлен в t rue, то преобразование применяется по­сле конца анимации;

Ll repeatCount - определяет число повторений анимации;

Ll repeatMode - определяет поведение анимации при ее окончании . Возмож­ные варианты : перезапустить без изменений или полностью изменить анимацию;

Page 405: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

404 Глава 1 8

LJ zAdj ustment - определяет режим упорядочения оси Z , чтобы использовать при выполнении анимации (нормаль, вершина или основание);

LJ interpolator - определяет постоянную скорости, которая описывает ди­намику визуальной деятельности в зависимости от времени или, говоря простым языком, определяет скорость изменения анимации . Можно ис­пользовать любой из элементов подкласса интерполятора, определенных в R . styleaЬle, например:

android : interpolator= " @ android : anim/decelerate_interpolator"

Элемент <set>

Элемент <set> - контейнер, который может содержать другие элементы . Представляет класс Animat ionset. Поддерживает атрибут shareinterpolator,

который указывает на возможность совместного использования этого интер­полятора для всех дочерних элементов.

Элемент <alpha>

Постепенно изменяющаяся анимация. Представляет AlphaAnimation. Поддер­живает следующие атрибуты :

LJ fromAlpha - начальное значение прозрачности объекта;

LJ toAlpha - конечное значение прозрачности объекта.

Атрибуты содержат значение прозрачности от О до 1 , где О означает полную прозрачность объекта.

Элемент <sca/e>

Элемент <scale> управляет анимацией изменения размеров объекта и пред­ставляет класс ScaleAnimation. Вы можете определить центральную точку изображения (закрепить центр анимации изображения), относительно кото­рой будет изменяться масштабирование объекта. Элемент <scale> поддержи­вает следующие атрибуты :

LJ fromXScale - начальный масштаб по Х;

LJ toXScale - конечный масштаб по Х;

LJ fromYScale - начальны й масштаб по У; LJ toYScale - конечный масштаб по У; LJ pivotx - Х-координата закрепленного центра;

LJ pivotY - У -координата закрепленного центра.

Page 406: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

Создание анимации 405

Элемент <translate> Элемент <t ranslate> - создает вертикальную или горизонтальную анима­цию движения . Представляет класс тrans lateAnimation и поддерживает сле­дующие атрибуты:

LJ fromXDelta - начальное положение по Х;

LJ toXDel ta - конечное положен ие по Х;

LJ fromYDelta - начальное положение по У; LJ toYDelta - конечное положение по У Атрибуты должны быть в любом из следующих трех форматов:

1 . Абсолютное значение.

2 . Значения в процентах от - 1 00% до 1 00%.

3 . Значения в процентах от - 1 ОО%р до 1 ОО%р, где р указывает процент отно­сительно его родителя .

Элемент <rotate> Элемент <rotate> предназначен для анимации вращения и представляет класс RotateAnimation. Поддерживает следующие атрибуты :

LJ fromDegrees - начальный угол вращения в градусах;

LJ toDegrees - конечный угол вращения в градусах;

LJ pi votx - координата Х центра вращения в пикселах;

LJ pi votY - координата У центра вращения в пикселах.

1 8 . 1 .2 . Ан имация графи ческих примити вов

В приложение можно подключать несколько файлов анимации, используя их для одного объекта. Рассмотрим работу с элементами анимации на примере графического прим итива - прямоугольника, для которого используем все виды анимации, описанные в предыдущем разделе. Создайте в Ecl ipse новый проект и заполн ите поля в окне New Android Project:

LJ Project name - TweenAnimat ionShapes;

LJ Application name - Tween Animation Sample;

LJ Package name - com . samples . tweenanimat ionshapes;

LJ Create Activity - TweenAnimat ionActivity.

В каталоге res/an im/ проекта создадим пять файлов с ХМL-анимацией : alpha.xml, rotate .xml , scale.xml, translate .xml , в каждом из которых продемон-

Page 407: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

406 Глава 1 8

стрируем работу с соответствующим элементом, и файл total .xml , в котором продемонстрируем комбинацию элементов <alpha>, <scale>, <t rans late>,

<rotate> для создания смешанной анимации .

Код файлов alpha.xml, rotate.xml, scale .xml, translate .xml· и total .xml представ­лен в листингах 1 8 . 1- 1 8 . 5 .

< ? xml vers ion= " l . O " encoding="ut f-8 "

<set xmlns : android= "http : / / schemas . android . com/apk/res /android"

android : shareinterpolator= " false " >

<alpha

android : frornAlpha=" O . O "

android : toAlpha= " l . O "

android : startOffset= " O "

androi d : duration= " 5 0 0 0 " / >

< / set>

< ?xrnl ve rsion= " . 0 " encoding= "utf- 8 "

<set

xrnlns : android= "http : / / schernas . android . com/apk/ res /android"

android : shareinterpolator= " fa l s e " >

<rotate

android : fromDegrees=" O "

android : toDegrees=" 3 6 0 "

android : pivotX= " 5 0 % "

android : pivotY= " 5 0 % "

android : durat ion= " 5 0 0 0 " < / set>

<?xml ve rs ion= " . 0 " encoding="utf-8 "

<set

xrnlns : android= " http : / / s chernas . android . com/apk/ res /android"

android : shareinterpolator= " fa l s e " >

<scale

android : pivotX= " S O % "

Page 408: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

Создание анимации

android : pivotY= " SO % "

android : fromXScale= " l . O "

android : fromYScale= " l . O "

android : toXScale= " 2 . 0 "

android : toYScale= " 2 . 0 "

android : duration= " 2 5 0 0 "

<scale

android : start0ffset= " 2 50 0 "

android : duration= " 2 5 0 0 "

android : pivotX= " S O % "

android : pivotY= " S O % "

android : fromXScale= " l . O "

android : fromYScale= " l . O "

android : toXScale= " O . S "

android : toYScale= " O . S "

</set>

< ?xml version= " l . O " encoding= " ut f-8 "

<set xmlns : android= "http : / /schemas . android . com/apk/res /android"

android : shareinte rpolator= " false">

<translate

android : toYDelta= " - 1 0 0 "

android : fillAfter=" t rue "

android : durat ion= " 2 5 0 0 " />

<translate

android : toYDelta= " l O O "

android : fi l lAfter= " t rue "

android : durat ion= " 2 5 0 0 "

android : sta rt0ffset= " 2 5 0 0 " / >

< / set>

< ? xml ve rsion= " l . O " encoding= "utf- 8 "

<set xrnlns : android="http : / / schemas . android . com/apk/res /android"

android : shareinterpolator=" false " >

<alpha

android : fromAlpha= " O . O "

407

Page 409: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

408

android : toAlpha= " l . O "

android : startOffset=" O "

android : durat ion= " S O O O " / >

<scale

android : duration= " 2 5 0 0 "

android : pivotX= " SO % "

android : pivotY= " S O % "

android : fromXScale= " l . O "

android : fromYScale= " l . O "

android : toXScale= " 2 . 0 "

android : toYScale= " 2 . 0 "

<rotate

android : fromDegrees=" O "

android : toDegrees= " 3 6 0 "

android : pivotX= " S O % "

androi d : pivotY= " 5 0 % "

android : durat ion= " S O O O "

<translate

android : toYDelta= " - 1 0 0 "

android : fi l lAfter= " fa l s e "

android : duration= " 2 5 0 0 "

<scale

android : durat ion= " 2 5 0 0 "

android : st a rt0ffset=" 2 5 0 0 "

android : pivotX= " S O % "

android : pivotY= " SO % "

android : fromXScale= " l . O "

android : fromYScale=" l . O "

android : toXScale= " O . S "

android : toYScale= " O . S "

<translate

android : toYDelta= " l O O "

android : fi l lAfter= " fa l s e "

android : duration= " 2 50 0 "

android : start0ffset=" 2 5 0 0 "

< /set>

Глава 18

Графический примитив, изображение которого будет анимировано, также определим в отдельном ХМL-файле, которы й назовем shape .xml и сохраним в

каталоге проекта res/drawaЫe/. Это будет объект подкласса ShapeDrawaЬle ­

прямоугольник красного цвета. Код файла shape .xml представлен в листин­ге 1 8 .6 .

Page 410: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

Создание анимации

< ?xml version=" l . O " encoding= " ut f-8 " ? >

<shape

xmlns : android= " http : / / s chemas . android . com/apk/res/android"

android : shape=" rectangle " >

<solid android : color= " # FO O " />

< / shape>

409

Файл разметки для деятельности приложения будет состоять из еди нственно­го элемента ImageView, как показано в листинге 1 8 .7 .

<?xml version= " l . O " encoding= " ut f-8 " ?> <LinearLayout

xmlns : android= " http : / / s chemas . android . com/apk/ res/android"

android : layout_width=" fi l l_parent "

android : layout_height=" fi l l_parent "

android : orientation= "horizontal "

android : layout_gravity= "center_vertical l center_horizonta l " >

< ImageView

android : id= " @ + id/ image "

android : layout_width= "wrap_content "

android : layout_height= "wrap_content "

android : minHeight=" l O Opx "

android : minWidth= " l O Opx"

android : layout_margin= " l O Opx " / >

< /LinearLayout>

Запустить анимацию в коде программы очень просто: надо создать объект Animat ion ВЫЗОВОМ метода AnimationUtils . loadAnimation ( ) , КОТОрому в качестве параметров следует передать контекст деятельности и ссылку на ХМ L-файл анимации . Затем запустить анимацию пред<;тавления вызовом ме­тода View . startAnimat ion ( ) , передав в него объект Animat ion:

ImageView. image ( ImageView) findViewByid ( R . i d . image ) ;

Animat ion animat ion

AnimationUt i l s . loadAnimation ( this , R . anim . alpha ) ;

image . startAnimation ( animation ) ;

Page 411: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

4 1 0 Глава 18

В классе Animat ion есть вложенный интерфейс AnimationLi stener, в котором объявлены три метода обратного вызова:

D onAnimat ionEnd ( ) ;

D onAnimationRepeat ( ) ;

D onAnimat ionStart ( ) .

В этих методах можно реализовать код обработки события запуска, оконча­ния и перезапуска анимации. Например, при окончании анимации можно

сделать объект анимации невидимым, а при запуске - снова отобразить на экране:

@Override

puЬlic void onAnimationStart (Animation animation)

mimage . setVisibi l i ty (View . VI S IBLE ) ;

@Override

puЬlic void onAnimationEnd (Animation animat ion )

mimage . setVis ibility ( View . INVISIBLE ) ;

@Override

puЬlic void onAnimationRepeat (Animat ion animat ion )

mimage . setVisibility ( View . VI S IBLE ) ;

В классе деятельности создадим меню из пяти пунктов, соответствующих каждому типу запускаемой анимации, - Alpha, Scale, Translate, Rotate и Total. В качестве идентификаторов пунктов меню используем идентификато­ры ресурсов ХМL-файлов анимации, упростив тем самым структуру метода onOpt ions itemSelected ( ) , вызы ваемого при выборе пункта меню.

Полный код класса деятельности TweenAnimationActivity представлен в листинге 1 8 . 8 .

package com . samples . tweenanima ionshapes ;

import android . app . Activity;

import android . os . Bundle ;

import android . view . M�nu ;

import android . view . Menuitem;

import android . view . View;

Page 412: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

Создание анимации

import android . view . animation . Animation ;

import android . view . animation . Animat ionUti l s ;

import android . view . animation . Animation . AnimationLi stene r ;

import android . widget . ImageView;

import android . widget . Toast ;

puЬlic class TweenAnimationActivity extends Activity

implements AnimationListene r {

private ImageView m!mage ;

private Animation animation ;

@ Override

protected void onCreate ( Bundle savedinstanceState )

supe r . onCreate ( savedinstanceState ) ;

setContentView ( R . layout . main ) ;

mimage ( ImageView) findViewByid ( R . id . image ) ;

mimage . set imageResource ( R . drawaЬle . shape ) ;

@ Override

puЬlic boolean onCreateOptionsMenu ( Menu menu ) {

menu . add (Menu . NONE , R . anim. alpha , Menu . NONE , "Alpha " )

. setAlphabet icShortcut ( ' a ' ) ;

menu . add (Menu . NONE , R . anim . scale , Menu . NONE , " Scale " )

. setAlphabeticShortcut ( ' s ' ) ;

menu . add (Menu . NONE , R . anim . t ranslate , Menu . NONE , "Trans late " )

. setAlphabeticShortcut ( ' t ' ) ;

menu . add (Menu . NONE , R . anim. rotate , Menu . NONE , "Rotate " )

. setAlphabeticShortcut ( ' r ' ) ;

menu . add (Menu . NONE , R . anim. tota l , Menu . NONE , " Total " )

. setAlphabeticShortcut ( ' o ' ) ;

return ( supe r . onCreateOptionsMenu (menu ) ) ;

@ Override

puЬlic boolean onOptions itemSelected (Menuitem item)

11 загружаем анимацию из выбранного ХМL-файла

animation AnimationUt i l s . loadAnimation (

thi s , item . get itemid ( ) ) ;

animation . setAnimationListener ( this ) ;

4 1 1

Page 413: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

412

m!mage . startAnimation ( anirnation ) ;

return true ;

11 реализация интерфейса AnirnationLi stener

@ Ove rride

puЬl i c void onAnirnationEnd (Animation animation )

mirnage . setVis ibil ity (View . INVIS IBLE ) ;

@ Override

puЬl i c void onAnirnationRepeat (Anirnation animation )

m!rnage . setVi s ibility ( View . VIS IBLE ) ;

@Override

puЬl i c void onAnimationStart (Anirnation anirnation )

m!mage . setVis ibi l i ty ( View . VI S IBLE ) ;

Глава 18

Запустите проект на выполнение. Поочередно выбирая опции меню, про­смотрите создаваемую анимацию для фигур. Внешний вид приложения пока­зан на рис. 1 8 .3 .

Рис. 1 8.3. Приложе н ие с ХМL-ан имацией

Page 414: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

Создание анимации 413

1 8 . 1 .3 . Ани мация графи ческих файлов

Анимация для графических файлов, отображаемых в nредставлениях, н ичем особы м не отличается от анимации для графических nримитивов. Рассмот­рим на nримере анимацию графического объекта, отображаемого в ImageView.

Создайте в Ecl ipse новый nроект и заnолните nоля в окне New Android Project:

О Project name - TweenAnimationView;

О Application name - Tween Animation Sample;

О Package name - com . samples . tweenanimat ionview;

О Create Activity - TweenAnimationAct ivity.

Для изображения возьмите из каталога Resources/Iшages/ на комnакт-диске файл aпdroid_Зd .png (это фигурка андроида, которую мы уже не раз исnоль­зовали в nредыдущих главах) .

В ХМL-файле анимации создадим более сложную структуру no сравнению с nредыдущим nримером: исnол ьзуем элемент <scale> для растягивания изо­бражения и вложенный контейнер <set>. В контейнере <set> оnределим два дочерних элемента, <scale> и <rotate>, для одновременного вращения и изменения объекта View, и сохраним этот файл в каталоге res/an itn/ nод именем апiш aпdro id .xm l .

Полный код файла aп im_aпdroid .xшl nредставлен в листинге 1 8 .9 .

< ?xml version= " . 0 " encoding= " ut f- 8 "

<set xmlns : android= " http : / /schemas . android . com/ap k / res /android" android : share!nterpolator= " false " >

<scale

android : interpolator=

<set

" @ android : anim/accelerate_decelerate_interpolator"

android : fromXScale= " l . O " android : toXScale= " 1 . 4 " android : fromYScale= " l . O "

android : toYScale= " O . б "

android : pivotX= " S O % "

android : pivotY= " S O % "

android : fi l lAfter= " false" android : durat ion= " З O O O "

android : interpolator= " @ android : anim/decele rate_interpolator" >

Page 415: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

414

<scale

android : fromXScale= " 1 . 4 "

android : toXScale= " O . O "

android : fromYScale= " O . б "

android : toYScale= " O . O "

android : pivotX= " 5 0 % "

android : pivotY= " 5 0 % "

android : start0ffset= " 3 0 0 0 "

android : duration= " 2 0 0 0 "

androi d : fillBe fore=" false"

< rotate

android : frornDegrees= " O "

android : toDegrees= " - 4 5 "

android : toYScale= " O . O "

android : pivotX= " S O % "

android : pivotY= " S O % "

android : startOffset= " З O O O "

android : duration= " 2 0 0 0 " / >

</ set>

< / set>

Глава 18

В файле разметки для деятельности создайте кнопку для заnуска анимации и один элемент ImageView, как nоказано в листинге 1 8 . 1 О .

< ? xml version= " l . O " encoding= "ut f- 8 " ?>

<LinearLayout xmlns : android= " http : / / schemas . android . com/apk/ res /android"

android : orientation= " ve rt i cal "

android : layout_width= " fi l l_parent "

android : layout_height=" fi l l_parent " >

<LinearLayout

android : layout_height="wrap content "

android : orientation=" hori zontal "

android : layout_width= " fi l l_parent " >

<Button androi d : id= " @ +id/btn s tart "

android : layout_height="wrap_content "

android : text= " Start "

androi d : layout_width=" fi l l_parent "

android : layout_we ight=" l " />

</LinearLayout>

Page 416: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

Создание анимации

<LinearLayout

android : id= " @ + id/layout_anim"

android : layout_height= " fi l l_parent "

android : gravity= " center "

android : layout_width= " fi l l_parent " >

< ImageView

android : id=" @+id/image "

android : layout_width= "wrap_content "

android : layout_height="wrap_content "

android : minHeight=" l O Opx"

android : minWidth= " l O Opx "

android : layout_margin= " lOOpx"

android : s rc=" @drawaЫe/androidЗd" / >

< /LinearLayout>

< / LinearLayout>

4 1 5

Полный код класса деятельности тweenAnimationAct ivity представлен в лис­тинге 1 8 . 1 1 .

package com . samples . tweenanimationview ;

import android . app . Activity;

import android . os . Bundle ;

import android . view . View ;

import android . view . animation . Animation ;

import android . view . animation . AnimationUti l s ;

import android . widget . Button ;

import android . widget . ImageView;

puЫic class TweenAnimationActivity extends Activity

@ Override

protected void onCreate ( Bundle savedinstanceState )

s upe r . onCreate ( savedinstanceState ) ;

setContentView ( R . layout . main ) ;

final Button btnStart

final ImageView image

( Button ) findViewByid ( R . id . btn_start ) ;

( ImageView) findViewByid ( R . id . image ) ;

btnStart . setOnClickListener ( new View . OnCl ickLi stene r ( )

puЬlic void onClick (View v )

Page 417: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

4 1 6

запуск анимации представления Anirnat ion anim An imationUt ils . loadAnimat ion (

this , R . anim . interpolator ) ;

image . startAnimation ( anim) ;

Глава 1 8

Скомпилируйте проект и запустите его на вы полнение. При нажатии кнопки Start фигурка андроида сначала плавно растянется по горизонтал и, затем од­новременно повернется и уменьшится в размерах, после чего вернется в ис­ходное состояние. В нешний вид nриложения представлен на рис. 1 8 .4 .

Р и с . 1 8.4. Анимация отдельного объекта View

Можете в качестве упражнения nоэкспериментировать с атрибутам и элемен­тов в ХМ L-файле анимации и посмотреть получивш иеся резул ьтаты .

Независимо от того, как анимация изменяет размеры объекта ил и nеремещает его на плоскости, границы элемента View, в который загружено изображение, останутся неизменны ми : ваша анимация не будет автоматически корректиро­вать размеры представления для размещения объекта. Есл и ани мация выйдет за границы родительского представления, произойдет отсечение объекта анимации .

Page 418: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

Создание анимации 4 1 7

1 8. 1 .4. Ан имация груп п ы представлен и й

Анимацию можно сделать и для нескольких представлений, объединив и х в группу. Например, поместив представления в контейнер LinearLayout, при­чем можно использовать не только графические, но и текстовые представле­ния . Рассмотрим на примере анимацию двух представлений , IrnageView и тextView, объединенных в группу. Создайте в Ecl ipse новый проект и запол­ните поля в окне New Android Project:

о Project name - TweenAnimationView;

о Application name - Tween Anirnation Sample;

О Package name - com . samples . tweenanimationview;

О Create Activity - TweenAnimationAct ivity.

Усложним ХМL-файл анимации, добави в элементы для создания более инте­ресных эффектов - используем элемент <alpha> для изменения прозрачно­сти объектов и последовательность элемента <rotate> и нескольких элемен­тов <scale> и <rotate> для вращения и масштабирования. Сохраним этот файл в каталоге res/anim/ проекта под именем circle.xm\ . Полный код файла circle.xml представлен в листинге 1 8 . 1 2 .

<?xml vers ion= " l . O " encoding="ut f-8 "

<set xmlns : android="http : / /schemas . android . com/apk/res /android"

android : sha re !nte rpolator= " false " >

<alpha

android : fromAlpha= " O . O "

android : toAlpha= " l . O "

android : startOffset=" O "

android : duration= " 5 0 0 0 " / >

<scale

android : duration= " 2 50 0 "

android : pivotX= " 5 0 % "

android : pivotY= " S O % "

android : fromXScale= " l . O "

android : fromYScale= " l . O "

android : toXScale= " 2 . 0 "

android : toYScale= " 2 . 0 "

<rotate

android : frornDegrees=" O "

Page 419: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

4 1 8

android : toDegrees= " З б O "

android : pivotX= " S O % "

android : pivotY= " 5 0 % "

android : durat ion= " S O O O "

<scale

android : durat ion= " 2 5 0 0 "

android : start0ffset= " 2 5 0 0 "

android : pivotX= " S O % "

android : pivotY= " 5 0 % "

android : frornXScale= " l . O "

android : fromYScale= " l . O "

android : toXScale= " 0 . 5 "

androi d : toYScale= " O . S "

<scale

android : duration= " 2 50 0 "

android : start0ffset= " 5 0 0 0 "

android : pivotX= " S O % "

android : pivotY= " S O % "

android : frornXScale= i' l . О "

android : fromYScale= " l . O "

android : toXScale= " 1 . 2 5 "

android : toYScale= " 1 . 2 5 "

<scale

android : duration= " 2 5 0 0 "

android : sta rt0ffset= " 7 5 0 0 "

android : pivotX= " S O % "

android : pivotY= " S O % "

android : frornXScale= " l . O "

android : fromYScale= " l . O "

android : toXScale= " O . B O "

android : toYScale= " O . B O "

< / set>

Глава 18

В файле разметки для деятельности nриложения создайте кноnку и дочерний

контейнер LinearLayout, в котором разместите виджет ImageView с фигуркой андроида из nредыдущего nриложения и текстовое nоле тextView с надnисью "Hel lo, Aпdroid ! " Для дочернего контейнера обязательно nрисвойте иденти­фикатор :

android : id= " @+id/layout_anim,

по которому вы сможете загрузить его в код nрограммы и исnользовать для анимации . Код файла разметки nоказан в листинге 1 8 . 1 3 .

Page 420: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

Создание анимации

< ?xrnl version= " l . O " encoding= "ut f- 8 " ?> <LinearLayout

xrnlns : android= "http : / /schemas . android . com/apk/ res /android"

android : orientation= "ve rt i ca l " android : layout_width= " fill_parent " android : layout_height= " fi l l_parent " >

<LinearLayout android : layout_height="wrap content " android : orientation= " hori zontal " android : layout_width= " fi l l_parent " > <Button

android : id= " @ +id/btn start "

android : layout_height="wrap_content "

android : text=" Start "

android : layout_width= " fill_parent "

android : layout_we ight= " l " />

< /LinearLayout>

<LinearLayout android : id= " @ +id/layout_anim" android : layout_height= " f i l l_parent "

android : gravity= " center"

android : layout_width= " fi l l_parent " >

< ImageView

android : id= " @ + id/ image " android : layout_width="wrap_content " android : layout_height="wrap_content "

android : s rc=" @drawaЬle/androidЗd" /> <TextView

android : id= " @+id/text " android : text= " @ s tring/hello" android : layout_width="wrap_content "

android : layout_height= "wrap_content " /> < /LinearLayout>

</LinearLayout>

Внешний вид разметки должен nолучиться таким, как на рис. 1 8 . 5 .

4 1 9

Код класса деятельности nочти не отличается от nредыдущего nримера, за исключением того, что мы работаем с анимацией не отдельного nредстав­ления, а с анимацией груnnы представлений :

Page 421: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

420 Глава 1 8

layout ( LinearLayout ) findViewByid ( R . id . layout_anim) ; animation AnimationUt i l s . loadAnimation ( this , R . anim . c i rcle ) ;

Полный код класса деятельности тweenAnimationAct ivity nредставлен в л ис­тинге 1 8 . 1 4.

Рис. 18.5. Разметка для приложения

package com . samples . tweenanimationlayout ;

import android . app . Activi t y ; import android . os . Bundle ; import android . view . View ; import android . view . animation . Animation ; import android . view . animation . AnimationUti l s ; import android . widget . Button ; import android . widget . LinearLayout ;

puЬlic class TweenAnimationActivity extends Activity private LinearLayout layout ; private Animation animation ;

@Override

protected void onCreate (Bundle savedinstanceState )

supe r . onCreate ( savedinstanceState ) ;

setContentView ( R . layout . main ) ;

Page 422: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

Создание анимации 421

layout ( LinearLayout ) findViewByid ( R . id . layout_anim) ;

animation AnimationUt i l s . loadAnimat ion ( thi s , R . anim . c i rcle ) ;

layout . startAnimation ( animation ) ;

final Button btnStart ( Button ) findViewByid ( R . id . btn_start ) ;

btnStart . setOnClickListener ( new View . OnCl ickLi stener ( )

puЬl ic void onClick (View v ) {

layout . startAnimation ( animation ) ;

Скомпилируйте и запустите проект на выполнение. Внешний вид приложе­ния показан на рис. 1 8 .6 .

Рис. 1 8.6. Ани мация разметки с изображением и текстом

1 8 .2 . Кадровая анимация Кадровая (фреймовая) анимация - традиционная анимация, которая создает­ся последовательностью различных изображений подобно рулону пленки. Основой для кадровой анимации является класс AnimationDrawaЬle.

Page 423: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

422 Глава 1 8

Подобно анимации преобразований, о которой было рассказано ранее, ХМL­файлы для этого вида анимации располагают в каталоге res/an im/ проекта Android .

1 8 .2 . 1 . Создан ие кадровой анимации в XM L

Для кадровой анимации ХМL-файл состоит из корневого элемента <animation- list> и дочерних узлов <item>, каждый из которых определяет кадр, который имеет две составляющие:

О графический ресурс для кадра;

О продолжительность кадра.

Вот примерны й ХМL-файл для анимации фрейма:

<animation-list xmlns : android= "http : / /schemas . android . com/apk/res /android"

android : oneshot=" t rue " >

<item android : drawaЫe= " @drawaЫe/filel android : duration= " 2 0 0 "

<item android : drawaЫe= " @drawaЫe/ file2 " android : duration= " 2 0 0 "

<item android : drawaЫe= " @drawaЬle /file З " android : duration= " 2 0 0 "

< /animation- list>

Это анимация выполняется только для трех кадров. При установке атрибута android : oneshot списка в t rue анимация повторится только один раз и после остановки будет содержать последний кадр. Если же атрибут android : oneshot

установлен в false, то анимация будет циклической. Этот ХМL-файл, сохра­ненный в каталоге res/an im/ nроекта, можно добавить как фоновое изображе­ние для представления и затем запустить анимацию.

Давайте рассмотрим создание кадровой анимации на примере. Создайте в Ecl i pse новый проект и заполните поля в окне New Android Project:

О Project name - FrameAnimationView;

О Application name - Frame Animation Sample;

О Package name - сот . samples . frameanima·t ionxml;

О Create Activity - FrameAnimationActivity.

<?xml vers ion= " . 0 " encoding= "ut f-8 " ?>

<LinearLayout

xmlns : android= " http : / / schemas . android . com/apk/ re s / android"

android : orientation="vertica l "

Page 424: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

Создание анимации

android : layout_width= " fill_parent "

android : layout_height= " fi l l_parent " >

<LinearLayout

android : layout_height= "wrap content "

android : orientation= "horizontal "

android : layout_width= " fi l l_parent " >

<Button

android : id= " @ +id/btn start "

android : layout_height= "wrap_content "

android : text= " Start "

android : layout_width= " fi l l_parent "

androi d : layout_weight= " l " />

<Button

androi d : id= " @ +id/btn_stop"

android : layout_height= "wrap_content "

android : text= " S top"

android : layout_width= " fi l l_parent "

android : layout_weight=" l " / >

< /LinearLayout>

<IrnageView

androi d : id= " @ + id/irnage "

android : layout_width= "wrap_content "

android : layout_height= "wrap_content " / >

</LinearLayout>

423

Для анимации используем файлы android l .png, android2 .png, androidЗ .png, находящиеся в каталоге Resources/Images/ на диске, прилагаемом к книге . Таким образом , наша анимация будет состоять из трех кадров . Время показа каждого кадра установим в 300 м иллисекунд. Все это запишем в ХМL-файл , который сохраним под именем android_anim.xml в каталоге res/values/. Пол­ный код файла приведен в листинге 1 8 . 1 6 .

<anirnation-list xmlns : android= "http : / /schernas . android . com/apk/re s /android"

android : oneshot= " false " >

<item

android : drawaЬle= " @drawaЬle/androidl "

android : duration= " З OO " />

Page 425: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

424

<itern

android : drawaЬle= " @drawaЬle/android2 "

android : durat ion= " З OO " />

<item

android : drawaЬle= " @drawaЬle/androidЗ "

android : duration= " З OO " />

< /animation- list>

Глава 18

Получить объект AnimationDrawaЬle в коде программы можно следующим способом:

ImageView image ( ImageView) findViewByid ( R . i d . image ) ;

image . setBackgroundResource ( R . anim. android_anim) ;

AnimationDrawaЬle animation (AnimationDrawaЬle ) image . getBackground ( ) ;

Управлять объектом AnimationDrawaЬle можно, используя его открытые мето­

ды start ( ) И s top ( ) .

Полный код класса деятельности FrameAnimationActivity приведен в лис­тинге 1 8 . 1 7 .

package com . samples . frameanimationxml ;

import android . app . Activity;

import android . graphics . drawaЬle . AnimationDrawaЬle ;

import android . os . Bundl e ;

import android . view . View;

import android . widget . Button;

import android . widget . ImageView;

puЬlic class FrameAnimationAct ivity extends Activity

puЬl ic void onCreate ( Bundle savedinstanceState )

super . onCreate ( savedinstanceStat e ) ;

setContentView ( R . layout . ma in) ;

ImageView image ( ImageView) findViewByid ( R . id . image ) ;

image . setBackgroundResource ( R . anim. android_anim) ;

AnimationDrawaЬle animation

(AnimationDrawaЬle ) image . getBackground ( ) ;

final Button btnStart ( Button) findViewByid ( R . id . btn_start ) ;

btnStart . setOnClickListene r ( new View . OnClickListene r ( ) {

Page 426: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

Создание анимации

puЫ i c void onCl ick ( View v )

mAnim . s t a rt ( ) ;

final Button btnStop ( Button ) findViewByi d ( R . id . btn_stop ) ;

btnStop . s etOnCl ickL i s tener ( new View . OnCl ickLis tene r ( ) {

puЫ i c vo id onC l i c k ( View v )

mAnim . s t op ( )

425

Скомпилируйте проект и запустите его на выполнение. У нас получится ани­мированная фигурка андроида, выполняющая физзарядку (рис. 1 8 . 7) .

Рис . 1 8 .7. Приложение с фреймовой анимацией

1 8 .2 .2 . Создание ан имации в коде п рограммы

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

В качестве примера создадим в Ec l ipse новый проект, взяв за основу прило­жение для кадровой анимации из предыдущего раздела.

Page 427: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

426

Заполним поля в окне New Android Project:

D Project name - FrameAnimat ionimageView;

D Application name - Frame Animation Sample;

D Package name - сот . samples . frameanimat ionimageview;

D Create Activity - FrameAnimat ionActivity.

Глава 1 8

Файл разметки для деятельности используйте из листинга 1 8 . 1 5 предыдущего примера с анимацией . В классе деятельности FrameAnimationActivity опреде­лим два внутренних метода, start ( ) и stop ( ) , которые будем вызывать из обработчиков onClick ( ) кнопок Start и Stop.

В методе s tart ( ) реализуем создание анимации . Для этого сначала надо по­лучить кадры анимации в виде набора объектов DrawaЬle, загрузив изображе­ния из ресурсов . Для каждого кадра создается отдельный объект DrawaЬle:

BitmapDrawaЬle frame 1

( BitmapDrawaЬle ) getResources ( ) . getDrawaЬle ( R . drawaЬle . android1 ) ;

BitmapDrawaЫe frame2

( BitmapDrawaЬle ) getResources ( ) . getDrawaЬle ( R . drawaЬle . android2 ) ;

BitmapDrawaЬle frameЗ

( BitmapDrawaЬle ) getResources ( ) . getDrawaЬle ( R . drawaЬle . androidЗ ) ;

Созданные объекты Bi tmapDrawaЬle необходимо добавить в объект AnimationDrawaЫe методом addFrame ( ) . Метод addFrame ( ) принимает два па­раметра: кадр анимации (объект DrawaЬle) и продолжительность показа в м иллисекундах. Код для создания анимации должен выглядеть примерно так :

Animat ionDrawaЬle mAnimation new AnimationDrawaЬle ( ) ;

1 / устанавливаем . циклическое повторение анимации

mAnimation . setOneShot ( false ) ;

mAnimation . addFrame ( frame 1 , 1 0 0 ) ;

mAnimation . addFrame ( frame2 , 1 0 0 ) ;

mAnimation . addFrame ( frame З , 1 0 0 ) ;

/ 1 устанавливаем анимацию как фон для ImageView mimage . setBackgroundDrawaЬle (mAnimation) ;

1 1 делаем объект DrawaЫe видимым mAnimation . setVis iЬle ( t rue , t rue ) ;

mAnimation . start ( ) ;

Полный код класса деятельности FrameAnimationActivity приводится в листинге 1 8 . 1 8 .

Page 428: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

Создание анимации

package com . smples . frameaninimageview ;

import android . app . Activity;

import android . graphics . drawaЫe . AnimationDrawaЫ e ;

import android . graphics . drawaЬle . BitmapDrawaЬle ;

import android . os . Bundle ;

import android . view . View;

import android . widget . Button ;

import android . widget . ImageView ;

puЬlic class FrameAnimationActivity extends Activity

private final static int DURATION 3 0 0 ;

private AnimationDrawaЬle mAnimation nul l ;

private ImageView mimage ;

@Override

protected void onCreate ( Bundle savedinstanceState )

supe r . onCreate ( s avedinstanceState ) ;

setContentView ( R . layout . main ) ;

mimage ( ImageView ) findViewByid ( R . id . image ) ;

final Button btnStart ( Button ) findViewByid ( R . id . btn_start ) ;

btnStart . setOnClickListener ( new View . OnClickListener ( )

puЬlic void onClick (View v ) {

start ( ) ;

final Button btnStop ( Button ) findViewByid ( R . id . btn_stop ) ;

btnStop . setOnClickListener ( new View . OnClickListener ( ) {

puЬlic void onClick (View v ) {

stop ( ) ;

private void start ( )

{

BitmapDrawaЬle frame l

427

(BitmapDrawaЬle ) getResources ( ) . getDrawaЬle (R . drawaЬle . androidl ) ;

Page 429: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

428 Глава 18

BitrnapDrawaЬle frame2

(BitrnapDrawaЬl e ) getResources ( ) . getDrawaЬle ( R . drawaЬle . android2 ) ;

BitrnapDrawaЬle frameЗ ( BitrnapDrawaЬle ) getResources ( ) . getDrawaЬle ( R . drawaЬle . androidЗ ) ;

mAnimat ion new AnirnationDrawaЬle ( ) ;

mAnirnation . setOneShot ( false ) ;

mAnirnation . addFrame ( framel , DURATION ) ;

mAnirnation . addFrame ( frame2 , DURATION ) ;

mAnirnation . addFrame ( frame З , DURATION ) ;

mirnage . setBackgroundDrawaЬle (mAnimation ) ;

mAnirnation . setVis iЬle ( true , true ) ;

mAnirnation . start ( ) ;

private void stop ( )

{

mAnirnation . stop ( ) ;

mAnirnat ion . setVis iЬle ( false , fa lse ) ;

Внешний вид работающего приложения ничем не отличается от приложения с загрузкой анимации из ХМL-файла (см . рис. 1 8 .7 из предыдущего примера).

Page 430: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

П Р И Л О Ж Е Н И Е

О п и са н ие ком п а кт-диска и уста н ов ка п р и ме ров

Оп исан ие ком пакт-диска На ком пакт-диске находятся два каталога: Samples/ и Resources/. В каталоге Samples/ располагаются файлы проектов, оп исанных в книге . Каталог Resources состоит из трех подкаталогов:

О Animatioп/ - изображения для анимации (глава 18) ;

О lmages/ - изображения для работы с виджетом Ga l lery (глава 7) ;

О Meпu_lcoпs/ - значки для создан ия пользовательских уведомлений (гла­

ва 8) , диалоговых окон (глава 9) , меню (примеры из глав 10-18) .

Большинство изображений взято из ресурсов дистрибутива Android SDK. При желании вы можете использовать собственные изображения.

Установка п ри меров В каталоге Samples/ компакт-диска находятся все примеры приложений, рас­смотренных в книге . Дnя их установки на компьютер создайте в Ecl ipse новое рабочее пространство. Дnя этого выберите пункты меню File 1 Switch Workspace 1 Other и в открывшемся диалоговом окне Workspace Launcher укажите каталог, в котором вы хотите разместить новое рабочее пространст­во для примеров (рис. П 1 . 1 ) .

После создания рабочего пространства необходимо заново создать ссылку на каталог с распакован ным Aпdroid SDK. Дnя этого выберите пун кт меню Window 1 Preferences. В открывшемся окне Preferences выберите пун кт Android в левой панели . В поле SDK Location на правой паиели окна необ­ходимо указать каталог, в котором расположен Aпdro id SDK. Для этого на-

Page 431: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

430 Приложенив

жмите кнопку Browse и установите путь к каталогу Aпdroid SDK, как показа­но на рис. П 1 .2 . Теперь, когда рабочее пространство для примеров создано и настроено, мож­но импортировать проекты с ком пакт-диска. Для этого выберите пункт меню

Select а workspace Eclipse stores your projects in а folder called а workspace. Choose а workspace folder to use for this sessюn .

� !;_ору 5eШngs

Рис. П 1 . 1 . Создание рабочего пространства в Ecl ipse

General �

Build Android Preferences

:�::����;i.;�:��k�i�.�.��i .

DDMS Launch LogCat Usage Stats

of SDK Tari;Jets below i qniy relooded once you hi 'Дррlу' 'ОК'

Ant Data Management Google Help Instaii/Update Java Java ЕЕ Plug·in Development Remote Systems Run/Debug Server Tasks Team Terminal

lf Usage Data Collector Validation Web Web Services XDoclet

. . . . . . ' i . . . X.ГoiL . . .

. . · . . . . . . : . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . : . . . ... . . . .

. Target Name A�dr�id ·.i :;· · ·· ······ Andro1d 1 .5

1 Android 1 .б ' Android 2 .0 Android 2 . 0 . 1 Google AP!s

. Google AP!s 1 Google AP!s 1 Google AP!s

Vendor · · · · ·· ····· д�з;-;;;а·о'Р�·�·s��;�·�"р;�;��;·

Android Open Source Project Android Open Source Project дndroid Open Source Project Android Open Source Project Google Inc . Google Inc. Google Inc. Google Inc .

Andr id + Google AP!s

Рис. П 1 .2 . Подключение Android S D K

' Platforin дР . . , 1 . 1 1 . 5 1 .б 2 .0 2 . 0 . 1 1 . 5 1 . б 2 .0 2 . 0 . 1

2 3 4 5 б 3 4 5 б

Page 432: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

Описание компакт-диска и установка примеров 431

File 1 Import и в открывшемся диалоговом окне Import выберите опцию Generai/Existing Projects into Workspace, как показано на рис. П 1 .3 . Нажми­те кнопку Next.

Select Create new projects from an archive file or directory.

9- General @; Archive File tlli ExistJng Projects lnto Workspace 9 F1le System :.: .. ;. Preferences

(Е;- cvs !±i fe,· EJB

Java ЕЕ i''• Plug-in Development ;::;, Remote Systems i2i7 Run/Debug [:), Tasks

Team ±i (& Web it···i2;} Web serv1ces

Сд- ХМL

i Next >. ]

Рис. П1 .3 . Окно мастера импорта файлов

П\i D · . . · ·.· . . . . · : . . · · : = .: : · = ·

Cancel

В следующем окне выберите Select root directory и укажите путь к каталогу Samples, находящемуся на ком пакт-диске. Список Projects отобразит все проекты, находящиеся в каталоге Samples/. Для импорта всех проектов из ка­талога нажмите кнопку Select АН, а также установите флажок Сору projects into workspace для копирования файлов с ком пакт-диска в созданный вам и каталог для рабочего пространства, как показано на рис. П 1 .4 .

Обратите внимание на имена проектов: в отличие от книги, все проекты со­держат в названии префикс, указывающий на главу из книги, например Ch09 _ CustomDialog, в то время как в книге этот проект имеет название CustomDialog. Это сделано для более удобной группировки проектов в рабо­чем пространстве по соответствующим главам книги.

Page 433: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

432

Import Projects Select а directory to search for existing Eclipse projects.

0 Sel�ct root directory: • Oseiect �chive fde:

eroJects: �ChOЗ:н;II�Ad�id(F:�\S;��i;�\choз_нelloдd;�;dг�··--ч-� � ChOS_FrameLayout (F: \Samples\ChOS_FrameLayout) � ChOS_L1nearLayout (F: \Samples\ChOS_Linearlayout) � ChOS_RelativeLayout (F: \Samples\ChOS_RelatlveLayout) � ChOS_TaЬieLayout (F: \Samples\ChOS_TaЬieLayout) � ChOб_Button (F:\Samples\ChOб_Button) � ChOб_Checi<Вox (F: \Samples\ChOб_Checi<Вox) � ChOб_Chronometer (F : \Samples\ChOб_Chronometer)

[J Add project to worl<ing sets

�· < ! Se!ect All

"'·' j 1 Q.esele.ct All

! 1 Refresh

({;1 < Back '---"':;.;;·n;_.....;J 1 Cancel

Рис. П 1 .4. Окно выбора и м портируемого каталога и проектов

Приложение

Page 434: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

П редметны й указател ь

А

AbsListView 1 47 Activity Manager 1 3 AdapterVi ew 1 46, 1 47 Adnroid SDK 1 8 Anal ogClock 1 3 3 A ndroid Development Tool s 1 6- 1 9 A ndroid Power Management 9 Android SDK 1 7 A ndroid Virtual Device 2 1 , 23 AndroidManifest.xml 50 Application Launcher 380 ArrayAdapter 1 47 А VD Manager 1 8 , 23 , 24, 26

в BroadcastReceiver 286, 289 Bund1e 253 Button 98, 99

с CheckBox 98, 1 09 CheckBoxPreference 302 Chronometer 1 33 , 1 3 5 Content Providers 1 3 ContentProvider 1 3 , 3 2 8 Context M e n u 225 Cursor 1 47, 325

D Dalvik Debug Monitor Service 22 Dalvik Virtual Machine 1 2

DDMS (Dalvik Debug Mon itor Service) 20 D igitalCl ock 1 33 Draw 9-patch 23

Е Eclipse 1 5-20, 22, 24, 3 1 EditText 90 EditТextPreference 302 Explorer View 83

F Frame animation 40 1 FrameLayout 68 , 92 FreeType 1 2

G Gal lery 1 46, 1 6 1 GridView 1 46, 1 53 , 1 5 7

н Hierarchy V i ewer 23, 8 1 Home screen 26 H orizontai Scro i i V i ew 92

lmageButton 98, 1 1 5 I mage V i ew 95 lntent 25 5 l ntentFi lter 27 1 lterator 3 3 3

Page 435: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

434

J Java Runtime Environment 1 6

L

Layout Ed itor 63 Layout View 82 Iayoutopt 23 Iayouts 6 1 LinearLayout 68, 1 00 Li stActivity 1 4 7 ListPreference 302 ListView 1 46- 1 48 Loupe Y iew 83

м Media Framework 1 1 mksdcard 23

N Normal broadcasts 285 Normal Y iew 83

о on Draw() 394 OpenGL ES 1 1 Ordered broadcasts 285

р Package Manager 1 3 PaintDrawaЬ\e 3 5 0 P ixel Perfect View 8 1 , 8 3 Preferences 295 ProgressBar 1 20- 1 22 Properties Y iew 83

R

Radi oButton 98, 1 06 RatingBar 1 20 , 1 33 RelativeLayout 68 , 78 Request Layout 83

Предметный указатель

Resource Manager 1 3 RingtonePreference 3 02

s

Scro i ! V iew 92 SecurityException 279 SeekBar 1 20, 1 25 SGL 1 2 SharedPreferences 303 Simp1eAdapter 1 47, 1 70 SimpleCursorAdapter 1 70 S1 id ingDrawer 1 46 , 1 65 Spi nner 1 46 , 1 49 SQLite 1 1 sq1 ite3 23 SQLiteDatabase 325 SQLiteOpenHelper 323 SSL 1 2 Status Ваг Notification 1 75 Stri ng 90

т TabH ost 1 1 7 TaЬ\eLayout 68 , 74 TabWidget 1 1 7 TextView 8 5 , 86, 95 Toast Notification 1 75- 1 7 8 ToggleButton 98, 1 1 2 Traceview 23 Tween A n imation 40 1 , 405 , 4 1 3 , 4 1 7

u U R I 2 5 5 , 327

v

Y i ew 6 1 , 66 Y i ew System 1 4 Y i ewGroup 6 1 , 66

w WebKit 1 2 Window Manager 1 3

Page 436: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

Предметный указатель

А Адаптеры данных 1 3 9 А ктивная целая жизн)> службы 275 А кти в н ы й процесс 46 А ктивы 349, 373 А н имация 3 5 0 Атрибуты 404, 405

Б База дан н ы х SQLite 323 Библиотека Bioп ic 1 О Библиотеки ядра 1 3

в В иджет 85 Види м ы й процесс 47 Виртуальная маш и н а Dalvik 1 2 Всплывающее уведомление 1 75

г Горячие клавиши 226, 227 Графика NinePatch 3 5 0 , 3 5 1 Граф ические ресурсы 3 5 0 Графически й и нтерфейс

пользователя 6 1 Графический примитив 405, 408 Группа

О меню 244

О представлений 6 1

д Действие 255 Деятельность 43, 249 Диалог 1 9 1 Документ X M L 364 Дополнения 256 Драйвер IPC 9

3 Заголовок меню 226 Запрос 327, 332

и Идентификатор

О группы 226 О пункта меню 226

О ресурса представлен и я 1 3 9

О уведомлен ия 1 85 И нтерфейс

О 1terator 3 3 3 О OпC1 ickListeпer 98

О OпCreateCoпtextMenuListeпer 98

О On FocusChangeLi stener 98 О OnKeyListeпer 98

О On LongCi ickListener 98

О OnTouchListener 98

к Каталог ресурсов 36 Категория 2 5 5 Класс О A l ertDialog 1 93 О A 1 phaA п i mation 40 1 О A пalogCiock 1 3 3 , 1 34

435

О A п i matioпDrawaЬle 42 1 , 424, 426---428

О AnimatioпSet 40 1 , 404

О A rcShape 3 87, 389, 390, 392, 395, 397

О A rrayAdapter 1 40

О A rray List 1 70 О AssetMaпager 349, 373, 375 О A utoCompleteTextV i ew 1 40

О B roadcastReceiver 285-287, 289-29 1

О Buпdle 253 О B utton 99

О Calendar 2 1 6

О CheckBox 1 09

О CheckBoxPrefereпce 302

О Chronometer 1 33 , 1 3 5

О CoпteпtProvider 326-329, 33 1 , 332, 340, 34 1

О ConteпtResolver 327-3 29, 33 1 , 332, 334, 3 3 5

О CoпteпtValues 325, 3 2 6 , 330, 334, 3 3 8-340, 342, 343 , 345, 346

О Coпtext 1 39, 295 О Cursor 325

Page 437: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

436

Класс (прод.) о CursorAdapter 1 47 о DatePickerDialog 2 1 1 о DigitaiCiock 1 33 , 1 34 о DrawaЬie 3 8 1 , 3 8 3 , 3 84, 3 87, 3 89, 394 о EditText 8 5 о EditTextPreference 302 о F i l e l n putStream 295 о F i leOutputStream 296 о FrameLayout 92 о Gallery 1 5 7, 1 6 1 о GridV iew 1 53 о H ashMap 1 7 1 о Horizontai Scro i i V iew 92 о 1mageButton 1 1 5 о lmageY iew 95 о lntent 1 82, 285--287, 289--293 о I ntentF i lter 27 1 о Layoutlntlater 1 79 о ListAct ivity 1 47 , 1 48 о ListAdapter 1 4 7 о ListPreference 302 о ListYiew 1 47 о М ар 1 70, 326, 334 о Menultem 226 о M ult iA utoCompleteTextY iew 1 43 о Notification 1 83 о NotificationManager 1 83 о PaintDrawaЬie 3 5 0 о Path 3 8 8 о Pendingl nteпt 1 84 о ProgressBar 1 20 , 1 2 1 о ProgressD ialog 206 о Rad ioButton 1 Об о RatingBar 1 20, 1 29 о RectShape 3 87, 3 90--392, 394--397 о RingtonePreference 302 о RotateAni mation 40 1 о Round RectShape 3 87, 3 88, 390, 392,

395, 397 о ScaleA n imatioп 402 о Scro i i Y iew 92 о SeekBar 1 20, 1 25 о Service() 276, 277, 279, 280 о ShapeDrawaЬie 3 8 1 , 3 86--392, 3 94--398 о S i mpleAdapter 1 47

Предметный указатель

о SimpleCursorAdapter 1 47, 1 70

о S l i d i ngDrawer 1 5 7, 1 64

о Spinner 1 49

о SQLiteDatabase 325

о SQLiteOpen Helper 323

о String 90

о TabHost 1 1 7

о TabWidget 1 1 7 о TextView 85

о TimePickerDialog 2 1 6

о Toast 1 79

о ToggleB utton 1 1 2

о Trans it ion DrawaЬie 3 84

о TranslateAnimation 402

о Typeface 3 7 5 , 3 76

о Y iew 6 1 , 398

о Y i ewGroup 6 1 Класс

о R 39, 349, 352

О деятельности 1 6 1 Команды ан имации 402 Константа

о о о о о о о о о о о о о о о о о о о

ACTI ON_BOOT_COM P LETED 287

ACTI ON_C A L L 2 5 5

ACTI ON_CAM ERA_B UTTON 2 8 7

ACTI ON_DATE_CHANGED 287

ACTION_E D I Т 255

ACTION M A IN 255

ACTION SCREEN O F F 287 - -

ACTION SYNC 2 5 5

ACTI ON_T I M E_CH A N G E D 287

ACTION _ T I M EZON E _ CHANGED 287

CATEGORY _B RO W SA B L E 256

CATEGORY _НО М Е 256

CATEGORY_LA UNC H ER 256

LENGTH LONG 1 76

LENGTH_SHORT 1 76

NOTI F I CATION_S E R V ICE 1 84

RESU LT_CANCELED 2 5 8

RESU LT_F I RST_U S E R 2 5 8

R E S U L Т_ ОК 2 5 8 Контейнерные виджеты 1 46 Контекст

о деятел ьности 409

О приложения 1 76 , 1 84

Page 438: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

Предметный указатель 437

Контекстное меню 225, 237 о onCreate() 250, 25 1 , 275 , 276, 324 Контент-nровайдер 1 3 , 43, 45 , 323, 326 о onCreateDialog() 1 92, 207

о onCreateOptionsMenu() 226

л о onDestroy( ) 250, 253, 275 , 276

о onltemSelected() 1 5 5 Локализованные строкавые о onNoth ingSelected() 1 5 5

ресурсы 377 о onOptionsltemSelected() 227, 229, 232, Локализованный строкавый файл 377

234, 235, 242, 245 , 247

о onPause() 250, 252 м о onPrepareDialog() 1 93

М анифест 40, 369, 3 70 о onProgressChanged() 1 26

О nриложении 3 72 о onReЬind() 277

Менеджер о on Receive() 286, 287, 289-29 1

О деятельностей 1 3 о onRestart() 250, 25 1

о местоnоложения 1 4 о onRestorelnstanceState() 253

о окон 1 3 о on Resume() 250, 25 1

о nакетов 1 3 о on Save l nstanceState() 253

о nоверхностей 1 О, 1 1 о onStart() 250, 25 1 , 275

о ресурсов 1 3 о on StartTrackingTouch() 1 26

О уведомле н и й 1 4 о onStop() 253

Меню 225, 350 , 3 60-364, 369 о onStopTracki ngTouch() 1 26

Меню о onUnЬind() 277

О выбора оnций 226 о onUpgrade() 324

О со значками 225, 230, 23 1 о openFi le l nput() 297 Метод о openFi leOutput() 297 О addCategory() 256 о query() 325 , 326, 329, 332 О Ь i nd Service() 276 о removeCategory() 256 о delete() 326, 329, 330, 334, 3 3 5 о sendB roadcast() 288 о getCategories() 256 о setCheckaЫe() 244 о getlte m l d() 227 о setltems() 200 о getOnChronometerTickLi stener() 1 3 5 о setM ultiChoiceltems() 203 о getPosition() 3 3 3 о setOnChronometerTickListener() 1 3 5 о getТext( ) 90 о setOnCiickListener() 1 О 1 о getТype() 329 о set0n 1temSelectedListener() 1 5 5 о i nsert( ) 325 , 326, 329, 330, 334 о setS ingleChoice l tems() 200 о inval idate() 3 94 о showDialog() 1 92 о makeText() 1 76 о startService() 275 о moveToFirst() 3 3 3 о stopService() 279 о moveTo Last() 3 3 3 о update() 326, 329, 330, 334 о moveToNext() 3 3 3

о moveToPosition() 3 3 3 н о moveToPrevious() 3 3 3

о onActivityResult() 2 5 8 Намерен ие 4 9 , 2 5 4 о onBind() 277 Неявные намерения 2 5 7 о onContextltemSelected() 237 Нормальные сообщения о намерениях 285

Page 439: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

438

n Перерисовка 394, 398, 399 Плаrин A DT 20, 35 Подменю 240 Позиционирование курсора 333 Покадровая ан имация 42 1 Полная целая ЖИЗН/> службы 275 Полосы прокрутки 92 Порядковые сообщения о намерениях 285 П редпочтение 295, 30 1 Представлен ие 6 1 , 398 П реобразования 402 П риемн и к щ и роковещательн ых намерений

43 , 44, 285 Проrрам м н ы й стек 7, 9 Процесс 45 Пункт меню 244 Пустой процесс 47

р Разметка 62 Расщиренное меню 225 , 233, 236 Ресурс 349, 3 7 7 Рисование на канве 3 9 3

с Связывание данн ы х 1 3 9 Сервисн ы й процесс 47 Система О представлений 1 4 О управления энерrопотреблен ием 9 Системная библиотека С 1 О Системн ы й идентификатор ресурса 1 39 Служба 43, 44 Статическое связывание дан н ых 1 47 Стек деятельностей 254 Стили 350, 368

Предметный указатель

т Текстовое поле с автозаполнен ием 1 40 Телефон н ы й менеджер 1 4 Тем ы 349, 3 5 0, 368--370, 3 73

у Уведомлен ие 1 75

О в строке состояния 1 82 Уровень

О A P I 2 1

О библиотек и среды выполнения 7

О каркаса приложен и й 7

О приложений 7

О ядра 7

ф Файл

О R.j ava 3 8

О манифеста 5 0 Фильтр намерений 27 1 Флаги 256 Фоновое приложение 1 83 Фоновый процесс 47 Функциональные библ иотеки С/С++ 1 0

ш Широковещательные намерения 2 8 8

я Я в н ы е намерения 2 5 7 Ядро A ndroid 7

Page 440: Голощапов А. Л. - Google Android программирование для мобильных устройств - 2011

Go dr

nроrраNНАирование д.n11 мо6иnьных

устройств Все что нужно All• разработки nриnожений на nnатформе Google Android

r •••• ano• Alleкceii .... . . " ..... , ведущи й п рогра м м и ст и

архитектор п рогра м м нога обеспечения и баз дан н ых. Разработч и к

с м ноголетн и м оп ытом работы , специал изирующийся на созда н и и приложений для настольных и мобильных систем.

«МЬJ сейчас реализуем более 60 000 Апdгоid-устройств в день, и эта цифра

удвоилась за последний квартал . . . . Очев идно, что рост ускоряется . . .

Android станет мобильной операционной системой М! 2 еще до 2012 года»

Эрик Ш м идт (Eric Schmidt), директор Google (из выступления на Moblle World Coпgress 201 0 , Барселона )

Р ы н о к п ро г р а м м н о га о б е с п еч е н и я д л я м о б ил ь н ы х уст ро й ст в бур н о раз­

в и вается , и разработка п р ил оже н и й для н и х ста н о в и тся занятием не тол ько

п е р с п е кт и в н ы м , н о и п р и б ы л ь н ы м , и и м е н н о в это й отр а сл и п ро г р а м м и ст

м ожет р а с п рост р а н я т ь с в о и п р ил оже н и я ч е р ез о н л а й н - м а га з и н ы ко м п а ­

н и й-производителей мобил ьных устройств .

С п о м о щ ь ю д а н н о й кн и г и в ы н а уч и те с ь созд а в а т ь п р о г р а м м ы д л я м о ­

бильных устройств под управл е н и е м операционной систе м ы Goog le Aпd roid . Бол ь ш о е кол и ч ество п р и м е р о в кода н а п р ил а га е м о м к кн и ге CD-ROM поз­

вол и т б ы стро сове р ш е н ство ваться и разви ваться . Кн и га рассч ита н а , в пер­

вую очеред ь , н а п ро г ра м м и сто в , уже и м е ю щ и х опыт п рогра м м и ро в а н и я н а язы ках Java или С#. N ЕТ.

i$ji§iei0jkl +О Мобильные устройства ISBN 978-5-9775-0562-8

На компакт-dиске приведены примеры из книги

БХВ-11Е1ЕР&УРГ, 1 90005, Санкт-Петербург,

Измайловекий лр., 29

E-mail : mailli»bhv.ru lntemet: www.bhv.ru Тел . : (81 2) 251 -42-44

Факс: (81 2) 320-01 -79