Глава 14. Сохранение фрагментов
Привязка индекса к сроку жизни сохраненного фрагмента позволяет ему пережить уничтожение объекта активности и решает проблему сброса индекса при повороте.
Но как видно из рис. 14.4, сохранение
QuizFragment не позволяет индексу пере- жить завершение процесса, которое может произойти, если пользователь оставит приложение на некоторое время, а активность и сохраненный фрагмент будут уничтожены для освобождения памяти.
Если список состоит всего из пяти вопросов, возвращение к началу может по- казаться приемлемым решением. А если бы в приложении GeoQuiz было 100 во- просов? Необходимость начинать все заново вызовет у пользователя (законное) раздражение. Состояние индекса должно переживать срок жизни записи актив- ности. Для этого индекс будет сохраняться в onSaveInstanceState(…)
. Затем, если пользователь оставит приложение на некоторое время, он сможет продолжить с прежнего места.
Итак, если в активности или фрагменте присутствуют данные, которые должны существовать в течение долгого времени, их следует привязать к сроку жизни записи активности, переопределяя метод onSaveInstanceState(Bundle)
для сохранения состояния и его последующего восстановления.
Для любознательных: повороты
до появления фрагментов
Фрагменты появились в версии Honeycomb и были доступны только для телефонов с Ice Cream Sandwich. С другой стороны, проблема поворота существует с самого начала.
Чтобы оценить всю прелесть сохранения фрагментов, нужно хотя бы примерно представлять, что происходило до их появления.
Хотите сохранить объект между изменениями конфигурации? Для этого ис- пользовался метод с именем onRetainNonConfigurationInstance()
. Разработчик переопределял метод onRetainNonConfigurationInstance()
, чтобы он возвращал сохраняемый объект. Чтобы получить объект обратно, вызывался метод getLa stNonConfigurationInstance()
Хотите сохранить в активности более одного объекта? Что ж, вам не повезло.
Каждая активность может хранить только один объект. Если вам этого мало, придется возиться с упаковкой нескольких объектов в один.
Используете объект (например,
MediaPlayer
), который должен освобождаться при уничтожении активности? Придется проверять, что метод onRetainNon-
ConfigurationInstance()
не вызывался, чтобы вы могли выполнить нужные действия в onDestroy()
Метод onRetainNonConfigurationInstance()
сейчас считается устаревшим, так что передача существующих объектов при поворотах теперь всегда осуществляется через сохранение фрагментов. Если вы уже немного освоились с использованием фрагментов, вы обнаружите, что этот способ намного приятнее старого.
Локализация
Локализацией
(localization) называется процесс выбора ресурсов приложения в за- висимости от конфигурации языка устройства. В этой главе мы локализуем при- ложение HelloMoon — в частности, будут определены испанские версии звукового и строкового файла. Если на устройстве выбран испанский язык, Android находит и использует испанские ресурсы.
Рис. 15.1. iHola, Luna!
15
258Глава 15. Локализация
Локализация ресурсовЯзыковые настройки являются частью конфигурации устройства. Android предо- ставляет конфигурационные квалификаторы для разных языков, существенно упрощающие локализацию: вы создаете подкаталоги ресурсов с разными языковыми квалификаторами и размещаете в них альтернативные ресурсы. Система ресурсов
Android делает все остальное.
Языковые квалификаторы позаимствованы из кодов ISO 639-1. Испанскому языку соответствует квалификатор
-es
. Создайте в проекте HelloMoon два новых под- каталога res
: res/raw-es/
и res/values-es/
Ресурсы для испанского языка включены в файл решений этой книги (
https://www.
bignerdranch.com/solutions/AndroidProgramming.zip
). Найдите в этом архиве файлы:
15_Localization/HelloMoon/res/raw-es/one_small_step.wav
15_Localization/HelloMoon/res/values-es/strings.xml
Скопируйте их в соответствующие каталоги из только что созданных.
Вот и все, что нужно сделать, чтобы предоставить локализованные ресурсы для вашего приложения. Чтобы убедиться в этом, переключите язык устройства на испанский (откройте панель
Settings и найдите языковые настройки; в зависимости от версии Android раздел будет называться
Language and input
,
Language and
Keyboard или что-нибудь в этом роде.
Добравшись до списка языковых настроек, выберите испанский язык (
Español
).
Регион (
España или
Estados
Unidos
) не играет роли, потому что каталоги ресурсов содержат квалификатор
-es
, подходящий для обоих вариантов.
(Каталог ресурсов можно уточнить квалификатором «язык+регион» для более точного определения ресурсов. Например, для испанского языка в Испании исполь- зуется квалификатор
-es-rES
, где r
обозначает квалификатор региона, а
ES
— код
Испании по стандарту ISO 3166-1-alpha-2. Обратите внимание: регистр символов в конфигурационных квалификаторах не учитывается, но рекомендуется соблюдать стандартную схему Android: код языка записывается символами нижнего регистра, а код региона — символами верхнего регистра с префиксом r
(в нижнем регистре).
Запустите приложение HelloMoon, нажмите кнопку
Tocar и послушайте, как зна- менитые слова Нила Армстронга звучат на испанском языке.
Ресурсы по умолчаниюДля английского языка используется конфигурационный квалификатор
-en
. Воз- можно, в порыве локализационного усердия вам захочется переименовать суще- ствующие каталоги raw и values в raw-en/
и values-en/
Это не лучшая мысль. Ресурсы в этих каталогах являются
ресурсами по умолчанию.
Каталоги ресурсов по умолчанию не имеют квалификаторов. Наличие ресурсов по умолчанию играет важную роль: если Android не удается найти ресурс, под-
ходящий для конфигурации устройства, при их отсутствии в приложении про- изойдет сбой.
Конфигурационные квалификаторы
259
Например, если файл strings.xml присутствует в каталогах values-en/
и values-es/
, но не в каталоге values/
, при попытке запустить приложение HelloMoon на устройстве с любым языком, кроме испанского и английского, оно аварийно завершится. На- личие ресурсов по умолчанию обеспечивает безопасность приложения независимо от конфигурации устройства.
Плотность пикселов и ресурсы по умолчанию
Единственным исключением из правила предоставления ресурсов по умолчанию является экранная плотность пикселов. Имена каталогов drawable в проекте обычно уточняются для разных плотностей экрана квалификаторами
-mdpi
,
-hdpi и
-xhdpi
Однако выбор ресурсов drawable в Android не сводится к простому подбору каталога для плотности пикселов устройства или использованию каталога по умолчанию при отсутствии совпадения.
Выбор определяется сочетанием размера экрана и плотности, и Android может выбрать ресурс из каталога с квалификатором меньшей или большей плотности с последующим масштабированием. Более подробная информация приведена в документации по адресу https://developer.android.com/guide/practices/screens_support.
html
, но важный момент заключается в том, что размещать графические ресурсы по умолчанию в res/drawable/
не обязательно.
Конфигурационные квалификаторы
Вы уже видели и использовали конфигурационные квалификаторы для выбора альтернативных ресурсов: языка (например, values-es/
), ориентации экрана (на- пример, layout-land/
), плотности экрана (например, drawable-mdpi/
) и уровня API
(например, values-v11/
).
В табл. 15.1 перечислены характеристики конфигурации устройств с конфигу- рационными квалификаторами, распознаваемыми системой Android для выбора ресурсов.
Таблица 15.1. Характеристики с конфигурационными квалификаторами
Мобильный код страны (MCC) с необязательным мобильным кодом сети (MNC)
Код языка с необязательным кодом региона
Направление макета
Наименьшая ширина
Доступная ширина
Доступная высота
Размер экрана
Соотношение сторон экрана
Ориентация экрана
продолжение
260Глава 15. Локализация
Режим пользовательского интерфейса
Ночной режим
Плотность экрана (dpi)
Тип сенсорного экрана
Доступность клавиатуры
Основной метод ввода текста
Доступность навигационных клавиш
Основной нетекстовый метод навигации
Уровень API
Описания этих характеристик и примеры конкретных конфигурационных квалифи- каторов можно найти по адресу
https://developer.android.com/guide/topics/resources/providing-resources.html#AlternativeResourcesПриоритеты альтернативных ресурсовПри таком количестве конфигурационных квалификаторов для выбора ресурсов возможны ситуации, в которых конфигурация устройства соответствует сразу нескольким альтернативным ресурсам. В таких ситуациях квалификаторы рас- сматриваются в порядке, представленном в табл. 15.1.
Чтобы понять, как работает система приоритетов, мы добавим в HelloMoon еще один альтернативный ресурс — версию строкового ресурса app_name для альбомной ориентации. Ресурс app_name используется как заголовок активности — этот текст выводится на панели действий. В альбомной ориентации
появляется больше места для вывода текста, и мы можем воспользоваться этим обстоятельством.
Создайте каталог values-land и скопируйте в него строковый файл по умолчанию.
Единственный строковый ресурс, который должен измениться в альбомной ориен- тации, — app_name
. Удалите другие строковые ресурсы и измените значение app_name так, как показано в листинге 15.1.
Листинг 15.1. Создание альтернативного строкового ресурса для альбомной ориентации
(values-land/strings.xml)
Hello, Moon! How are you? Is it cold up there?
HelloMoon
Hello world!
Settings
Play
Stop
Neil Armstrong stepping
Таблица 15.1 (продолжение)
Приоритеты альтернативных ресурсов
261
onto the moon
Альтернативы для строковых ресурсов (и других ресурсов values
) подбираются на уровне отдельных строк, так что в случае совпадения строки дублировать не обязательно. Дубликаты только усложнят сопровождение приложения с течением времени.
Теперь у нас имеются три версии app_name
: версия по умолчанию в файле values/
strings.xml
, испанская альтернатива в файле values-es/strings.xml и альтернатива для альбомной ориентации в файле values-land/strings.xml
Включите на своем устройстве испанский язык, запустите HelloMoon и поверните устройство. Альтернатива для испанского языка обладает более высоким приори- тетом, поэтому вы увидите строку из файла values-es/strings.xml
Рис. 15.2. Android отдает предпочтение языку перед ориентацией экрана
Если хотите, попробуйте вернуться к английскому языку, снова запустить при- ложение и убедиться в том, что на экране появляется альтернативная строка для альбомной ориентации (как и предполагалось). Чтобы вернуться к английскому языку, поищите в лаунчере раздел
Ajustes или
Configuración и найдите параметр со словом idioma
(язык).
Множественные квалификаторы
Каталогу ресурсов можно назначить более одного квалификатора. Например, чтобы задать в приложении HelloMoon строку на испанском языке для альбомной ориентации, создайте каталог с именем values-es-land
Если каталог имеет более одного квалификатора, они должны следовать в порядке приоритетов. Таким образом, values-es-land является допустимым именем каталога, а values-land-es
— нет.
(Учтите, что квалификатор «язык-регион» — например,
-es-rES
— выглядит как объединение двух разных квалификаторов, но это впечатление обманчиво. Обо- значение региона само по себе не является действительным квалификатором.)
262
Глава 15. Локализация
Скопируйте файл values-land/strings.xml в каталог values-es-land/
и внесите изменения, представленные в листинге 15.2 (или, если хотите, скопируйте файл res/values-es- land/strings.xml из проекта решений).
Листинг 15.2. Создание испанского строкового ресурса для альбомной ориентации
(values-es-land/strings.xml)
Hello, Moon! How are you? Is it cold up there?
¡Hola, Luna! ¿Como estás? ¿Hace frío ahí arriba?
Выберите испанский язык, запустите HelloMoon и убедитесь в том, что новый альтернативный ресурс появляется в положенном месте.
Рис. 15.3. Испанская строка для альбомного режима отображается на экране
Поиск наиболее подходящих ресурсов
Давайте разберемся подробнее, как же Android определяет, какую версию app_name следует отображать при запуске. Сначала Android рассматривает три варианта строкового ресурса с именем app_name
:
values-es/strings.xml
values-land/strings.xml
values-es-land/strings.xml
Затем рассматривается конфигурация устройства. В настоящее время она включает испанский язык и альбомную ориентацию экрана.
Исключение несовместимых каталогов
Поиск оптимального ресурса Android начинает с исключения всех каталогов ре- сурсов, несовместимых с текущей конфигурацией.
Дополнительные правила использования ресурсов
263Ни один из трех вариантов не является несовместимым с текущей конфигурацией.
Если повернуть устройство в книжную ориентацию, конфигурация изменится, а каталоги ресурсов values-land/
и values-es-land/
станут несовместимыми и будут исключены.
С некоторыми квалификаторами все не так однозначно в отношении совмести- мости конфигураций. Например, уровень API не требует жесткого совпадения.
Квалификатор
-v11
совместим со всеми устройствами с уровнем API 11 и выше.
Некоторые квалификаторы были добавлены на более поздних уровнях API. На- пример, квалификаторы направления макета появились в API уровня 17; два допустимых значения —
-ldltr
(слева направо) и
-ldrtl
(справа налево). Новые квалификаторы сопровождаются неявным квалификатором уровня API, так что
-ldltr можно рассматривать как
-ldltr-v17
. (Добавление скрытых квалификато- ров — еще одна веская причина для включения ресурсов по умолчанию.)
С плотностью экрана проблема решается иначе, без учета совместимости. Android выбирает ресурс, который считается наиболее подходящим для конфигурации; он может быть (а может и не быть) ресурсом, квалификаторы которого соответствуют конфигурации.
Перебор таблицы приоритетовПосле исключения несовместимых каталогов Android начинает перебирать таблицу приоритетов (см. табл. 15.1), начиная с самого высокоприоритетного квалификатора MCC. При наличии каталога ресурсов с квалификатором MCC все каталоги ресурсов,
не имеющие квалификатора MCC, исключаются. Если после этого остается более одного подходящего каталога, Android рассматривает следующий по приоритету квалификатор и продолжает до тех пор, пока не оста- нется всего один каталог.
В нашем примере каталогов с квалификатором MCC нет, поэтому ни один каталог не исключается, а Android переходит к следующему пункту — квалификатору языка.
Два каталога (
values-es/
и values-es-land/
) содержат квалификаторы языка. У одного каталога (
values-land/
)
такого квалификатора нет, и он исключается.
Android продолжает опускаться по списку квалификаторов. Достигнув ориентации экрана, Android находит один каталог с квалификатором ориентации и один каталог без него. Каталог values-es/
исключается, и остается только каталог values-es-land/
Таким образом, Android использует ресурс из values-es-land/
Дополнительные правила использования ресурсовТеперь, когда вы лучше разбираетесь в системе ресурсов Android, мы представим некоторые системные требования, которые также следует учитывать при постро- ении собственных приложений.
264Глава 15. Локализация
Имена ресурсовИмена ресурсов должны записываться символами нижнего регистра и не могут содержать пробелов: one_small_step.wav
, app_name
, armstrong_on_moon.jpg
Ссылки на ресурсы в XML или коде не включают расширение файла. Например, ссылка в файле макета имеет вид
@drawable/armstrong_on_moon
, а ссылка в коде —
R.drawable.armstrong_on_moon
. Следовательно, вы не сможете различать одноимен- ные файлы ресурсов, находящиеся в одном каталоге, по расширениям.
Структура каталогов ресурсовРесурсы должны храниться в одним из подкаталогов res/
. Сохранение ресурсов в корневом каталоге res/
запрещено, это приведет к ошибкам при построении при- ложения.
Имена подкаталогов res напрямую связаны с процессом построения Android и не могут изменяться. Мы уже видели каталоги drawable/
, layout/
, menu/
, raw/
и values/
Полный список поддерживаемых подкаталогов res
(без квалификаторов) на- ходится по адресу https://developer.android.com/guide/topics/resources/providing-resources.
html#ResourceTypes
Все остальные подкаталоги, создаваемые в res/
, игнорируются. Создание каталога res/my_stuff не приведет к ошибке, но Android не будет использовать ресурсы из этого каталога.
Кроме того, в res/
нельзя создавать дополнительные уровни подкаталогов. Это ограничение иногда осложняет жизнь разработчикам. Реальные проекты могут содержать сотни графических ресурсов; желание распределить их по подкаталогам вполне естественно. Однако делать это нельзя. Единственное, что поможет вам в этой ситуации, — тщательный выбор имен ресурсов, чтобы порядок их сортировки упрощал поиск конкретных файлов.
Примером такой стратегии сортировки служит схема выбора имен файлов маке- тов в Android. Файлы макетов начинаются с типа представления, определяемого макетом (например, activity_
, dialog_
или list_item_
). Например, в каталоге res/layout/
приложения CriminalIntent содержатся файлы activity_crime_pager
, activity_fragment
, dialog_date
, fragment_crime и list_item_crime
. Макеты активностей группируются в по- рядке сортировки, что теоретически упрощает их поиск.
Тестирование альтернативных ресурсовМакеты и другие ресурсы необходимо тестировать. По тестовым макетам вы узнаете, сколько альтернатив вам понадобится для разных размеров экранов, ориентаций и т. д.
Тестирование может осуществляться как на реальных, так и на виртуальных устрой- ствах, причем вы также можете использовать графический конструктор макетов.
Графический конструктор макетов содержит много инструментов для предвари- тельного просмотра макета в разных конфигурациях. Макет можно
просматривать для разных размеров экранов, типов устройств, уровней API, языков и т. д.
Тестирование альтернативных ресурсов
265
Чтобы просмотреть эти варианты, откройте файл fragment_hello_moon.xml в графиче- ском конструкторе макетов. Опробуйте инструменты, обозначенные на следующем рисунке.
Размеры экрана и локальные контексты
Устройства
Уровни API
Язык/регион
Ориентация экрана
Рис. 15.4. Предварительный просмотр макета в графическом конструкторе
Чтобы убедиться в том, что вы включили все необходимые ресурсы по умолчанию, назначьте приложению язык, для которого не были заданы локализованные ре- сурсы. Запустите приложение, посетите все представления и проверьте повороты.
Если в приложении произойдет сбой, поищите в LogCat сообщение «Resource not found...» и определите отсутствующий ресурс по умолчанию.
Прежде чем переходить к следующей главе, верните на своем устройстве основной язык вместо испанского. Для этого поищите в лаунчере раздел
Ajustes или
Configura- ción и найдите параметр со словом idioma
(язык).
Панель действийПанель действий (action bar) появилась в Honeycomb. Она заменяет классическую строку заголовка, но ее функции не сводятся к простому отображению значка при- ложения и заголовка. На панели действий также могут размещаться команды меню, а значок приложения может использоваться как навигационная кнопка.
В этой главе мы создадим меню для приложения CriminalIntent. В меню будет присутствовать
команда меню для добавления нового преступления. Кроме того, кнопка приложения будет выполнять функции кнопки Up.
КнопкаUp
Команда меню для до- бавления нового пре- ступления
Рис. 16.1. Расширенные возможности панели действий16
Командное меню
267
Командное меню
Меню на панели действий называется командным меню (options menu). Пункты этого меню относятся к экрану или приложению в целом. Хорошим примером служит добавление нового преступления. С другой стороны, операция удаления преступления из списка лучше подходит для контекстного меню, поскольку для нее необходим контекст — информация о том, какое преступление нужно удалить.
Контекстные меню более подробно рассматриваются в главе 18.
Нашему командному меню потребуются новые строковые ресурсы. Один ресурс также понадобится и для контекстного меню в главе 18. Добавьте строковые ресурсы для обеих глав в файл strings.xml
(листинг 16.1). Пока эти строки выглядят довольно загадочно, но лучше решить эту проблему сразу. Когда они понадобятся нам позд- нее, они уже будут на своем месте, и нам не придется отвлекаться от текущих дел.
Листинг 16.1. Добавление строк для меню (res/values/strings.xml)
Crimes
Date:
Date of crime:
New Crime
Show Subtitle
Hide Subtitle
If you see something, say something.
Delete
Рис. 16.2. Командные меню до Honeycomb