Уровень API: 17
Android 4.2 ( JELLY_BEAN_MR1
) — это обновление версии Jelly Bean, которое предлагает новые функции для пользователей и разработчиков приложений. Этот документ представляет собой введение в наиболее известные и полезные новые API для разработчиков.
Как разработчик приложения, вам следует как можно скорее загрузить образ системы Android 4.2 и платформу SDK из диспетчера SDK . Если у вас нет устройства под управлением Android 4.2, на котором можно протестировать приложение, используйте образ системы Android 4.2, чтобы протестировать приложение на эмуляторе Android . Затем создайте свои приложения для платформы Android 4.2, чтобы начать использовать новейшие API.
Чтобы лучше оптимизировать свое приложение для устройств под управлением Android 4.2, вам следует установить для targetSdkVersion
значение "17"
, установить его в образ системы Android 4.2, протестировать его, а затем опубликовать обновление с этим изменением.
Вы можете использовать API в Android 4.2, одновременно поддерживая более старые версии, добавив в код условия, которые проверяют уровень системного API перед выполнением API, не поддерживаемых вашим minSdkVersion
. Чтобы узнать больше о обеспечении обратной совместимости, прочтите «Создание обратно совместимых пользовательских интерфейсов» .
Дополнительную информацию о том, как работают уровни API, можно найти в разделе «Что такое уровень API?».
Важные изменения в поведении
Если вы ранее публиковали приложение для Android, обратите внимание на следующие изменения, которые могут повлиять на поведение вашего приложения:
- Поставщики контента больше не экспортируются по умолчанию. То есть значением по умолчанию для атрибута
android:exported
теперь является“false"
. Если важно, чтобы другие приложения могли получить доступ к вашему поставщику контента, теперь вы должны явно установитьandroid:exported="true"
.Это изменение вступит в силу, только если вы установите
android:targetSdkVersion
илиandroid:minSdkVersion
значение 17 или выше. В противном случае значение по умолчанию по-прежнему будет“true"
даже при работе на Android 4.2 и выше. - По сравнению с предыдущими версиями Android результаты определения местоположения пользователя могут быть менее точными, если ваше приложение запрашивает разрешение
ACCESS_COARSE_LOCATION
, но не запрашивает разрешениеACCESS_FINE_LOCATION
.Чтобы удовлетворить ожидания пользователей в отношении конфиденциальности, когда ваше приложение запрашивает разрешение на грубое определение местоположения (а не на точное), система не будет предоставлять пользователю оценку местоположения, которая будет более точной, чем городской квартал.
- Некоторые настройки устройства, определенные
Settings.System
, теперь доступны только для чтения. Если ваше приложение попытается записать изменения в настройки, определенные вSettings.System
, которые были перемещены вSettings.Global
, операция записи завершится ошибкой при работе на Android 4.2 и более поздних версиях.Даже если ваше значение для
android:targetSdkVersion
иandroid:minSdkVersion
меньше 17, ваше приложение не сможет изменить настройки, которые были перемещены вSettings.Global
при работе на Android 4.2 и более поздних версиях. - Если ваше приложение использует
WebView
, Android 4.2 добавляет дополнительный уровень безопасности, чтобы вы могли более безопасно привязывать JavaScript к своему коду Android . Если вы установили дляtargetSdkVersion
значение 17 или выше, теперь вам необходимо добавить аннотацию@JavascriptInterface
к любому методу, который вы хотите сделать доступным для вашего JavaScript (метод также должен быть общедоступным). Если вы не предоставите аннотацию, метод будет недоступен для веб-страницы в вашемWebView
при работе на Android 4.2 или более поздней версии. Если дляtargetSdkVersion
установлено значение 16 или ниже, аннотация не требуется, но мы рекомендуем обновить целевую версию и добавить аннотацию для дополнительной безопасности.Узнайте больше о привязке кода JavaScript к коду Android .
Мечта
Daydream — это новый интерактивный режим заставки для устройств Android. Он активируется автоматически, когда устройство вставляется в док-станцию или когда устройство остается бездействующим при подключении к зарядному устройству (вместо выключения экрана). Daydream отображает по одному сну за раз, что может быть чисто визуальным, пассивным отображением, закрывающимся при прикосновении, или может быть интерактивным и реагировать на полный набор входных событий. Ваши мечты реализуются в процессе вашего приложения и имеют полный доступ к набору инструментов пользовательского интерфейса Android, включая представления, макеты и анимацию, поэтому они более гибкие и мощные, чем живые обои или виджеты приложений.
Вы можете создать мечту для Daydream, реализовав подкласс DreamService
. API-интерфейсы DreamService
аналогичны API-интерфейсам Activity
. Чтобы указать пользовательский интерфейс своей мечты, передайте идентификатор ресурса макета или View
в функцию setContentView()
в любой момент после создания окна, например, из обратного вызова onAttachedToWindow()
.
Класс DreamService
предоставляет другие важные методы обратного вызова жизненного цикла поверх базовых API-интерфейсов Service
, такие как onDreamingStarted()
, onDreamingStopped()
и onDetachedFromWindow()
. Вы не можете инициировать DreamService
из своего приложения — он запускается системой автоматически.
Если ваш сон интерактивный, вы можете начать действие из сна, чтобы отправить пользователя в полный пользовательский интерфейс вашего приложения для получения более подробной информации или контроля. Вы можете использовать finish()
чтобы завершить сон, чтобы пользователь мог увидеть новое действие.
Чтобы сделать вашу мечту доступной для системы, объявите DreamService
с помощью элемента <service>
в файле манифеста. Затем вы должны включить фильтр намерений с действием "android.service.dreams.DreamService"
. Например:
<service android:name=".MyDream" android:exported="true" android:icon="@drawable/dream_icon" android:label="@string/dream_label" > <intent-filter> <action android:name="android.service.dreams.DreamService" /> <category android:name="android.intent.category.DEFAULT" /> </intent-filter> </service>
В DreamService
есть еще несколько полезных методов, о которых следует знать:
-
setInteractive(boolean)
контролирует, получает ли сон события ввода или завершается сразу после ввода пользователя. Если сон интерактивный, пользователь может использовать кнопки «Назад» или «Домой» , чтобы выйти из сна, или вы можете вызвать функциюfinish()
чтобы остановить сон. - Если вам нужен полностью захватывающий дисплей, вы можете вызвать
setFullscreen()
, чтобы скрыть строку состояния. - Перед запуском Daydream дисплей тускнеет, сигнализируя пользователю о приближении тайм-аута простоя. Вызов
setScreenBright(true)
позволяет вместо этого установить обычную яркость дисплея.
Дополнительную информацию см. в документации DreamService
.
Вторичные дисплеи
Android теперь позволяет вашему приложению отображать уникальный контент на дополнительных экранах, подключенных к устройству пользователя через проводное соединение или Wi-Fi. Чтобы создать уникальный контент для вторичного дисплея, расширьте класс Presentation
и реализуйте обратный вызов onCreate()
. В onCreate()
укажите свой пользовательский интерфейс для дополнительного дисплея, вызвав setContentView()
. Являясь расширением класса Dialog
, класс Presentation
предоставляет область, в которой ваше приложение может отображать уникальный пользовательский интерфейс на дополнительном дисплее.
Чтобы обнаружить дополнительные дисплеи, на которых вы можете отобразить свою Presentation
, используйте API DisplayManager
или MediaRouter
. Хотя API DisplayManager
позволяют перечислять несколько дисплеев, которые могут быть подключены одновременно, вместо этого обычно следует использовать MediaRouter
для быстрого доступа к дисплею системы по умолчанию для презентаций.
Чтобы получить отображение по умолчанию для вашей презентации, вызовите MediaRouter.getSelectedRoute()
и передайте ему ROUTE_TYPE_LIVE_VIDEO
. Возвращает объект MediaRouter.RouteInfo
, который описывает текущий выбранный системой маршрут для видеопрезентаций. Если MediaRouter.RouteInfo
не имеет значения NULL, вызовите getPresentationDisplay()
чтобы получить Display
представляющий подключенный дисплей.
Затем вы можете отобразить свою презентацию, передав объект Display
конструктору класса Presentation
. Ваша презентация теперь появится на дополнительном дисплее.
Чтобы во время выполнения обнаружить подключение нового дисплея, создайте экземпляр MediaRouter.SimpleCallback
, в котором вы реализуете метод обратного вызова onRoutePresentationDisplayChanged()
, который система будет вызывать при подключении нового дисплея презентации. Затем зарегистрируйте MediaRouter.SimpleCallback
, передав его в MediaRouter.addCallback()
вместе с типом маршрута ROUTE_TYPE_LIVE_VIDEO
. Когда вы получите вызов onRoutePresentationDisplayChanged()
, просто вызовите MediaRouter.getSelectedRoute()
как указано выше.
Чтобы дополнительно оптимизировать пользовательский интерфейс Presentation
для дополнительных экранов, вы можете применить другую тему, указав атрибут android:presentationTheme
в <style>
, который вы применили к своему приложению или действию.
Имейте в виду, что экраны, подключенные к устройству пользователя, часто имеют больший размер и, вероятно, другую плотность экрана. Поскольку характеристики экрана могут отличаться, вам следует предоставить ресурсы, оптимизированные специально для таких больших дисплеев. Если вам нужно запросить дополнительные ресурсы из вашей Presentation
, вызовите getContext()
.getResources()
чтобы получить объект Resources
, соответствующий дисплею. Это предоставит из вашего приложения соответствующие ресурсы, которые лучше всего подходят для размера и плотности экрана дополнительного дисплея.
Дополнительные сведения и некоторые примеры кода см. в документации по классу Presentation
.
Виджеты экрана блокировки
Android теперь позволяет пользователям добавлять виджеты приложений на экран блокировки. Чтобы сделать виджет приложения доступным для использования на экране блокировки, добавьте атрибут android:widgetCategory
в XML-файл, в котором указан AppWidgetProviderInfo
. Этот атрибут поддерживает два значения: home_screen
и keyguard
. По умолчанию для атрибута установлено значение home_screen
, поэтому пользователи могут добавлять виджет вашего приложения на главный экран. Если вы хотите, чтобы виджет вашего приложения был также доступен на экране блокировки, добавьте значение keyguard
:
<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android" ... android:widgetCategory="keyguard|home_screen"> </appwidget-provider>
Вам также следует указать начальный макет виджета вашего приложения на экране блокировки с помощью атрибута android:initialKeyguardLayout
. Это работает так же, как android:initialLayout
, поскольку предоставляет макет, который может появиться сразу же, пока виджет вашего приложения не будет инициализирован и не сможет обновить макет.
Дополнительную информацию о создании виджетов приложений для экрана блокировки, в том числе о правильном размере виджета приложения на экране блокировки, см. в руководстве по виджетам приложений .
Несколько пользователей
Android теперь позволяет использовать несколько пользовательских пространств на общих устройствах, таких как планшеты. Каждый пользователь на устройстве имеет свой собственный набор учетных записей, приложений, системных настроек, файлов и любых других данных, связанных с пользователем.
Как разработчику приложения вам не нужно ничего делать, чтобы ваше приложение правильно работало с несколькими пользователями на одном устройстве. Независимо от того, сколько пользователей может существовать на устройстве, данные, которые ваше приложение сохраняет для данного пользователя, хранятся отдельно от данных, которые ваше приложение сохраняет для других пользователей. Система отслеживает, какие пользовательские данные принадлежат пользовательскому процессу, в котором работает ваше приложение, и предоставляет вашему приложению доступ только к данным этого пользователя и не разрешает доступ к данным других пользователей.
Сохранение данных в многопользовательской среде
Всякий раз, когда ваше приложение сохраняет настройки пользователя, создает базу данных или записывает файл во внутреннюю или внешнюю память пользователя, эти данные доступны только во время работы от имени этого пользователя.
Чтобы быть уверенным, что ваше приложение работает правильно в многопользовательской среде, не обращайтесь к внутреннему каталогу приложения или внешнему хранилищу с помощью жестко закодированных путей и вместо этого всегда используйте соответствующие API:
- Для доступа к внутреннему хранилищу используйте
getFilesDir()
,getCacheDir()
илиopenFileOutput()
. - Для доступа к внешнему хранилищу используйте
getExternalFilesDir()
илиgetExternalStoragePublicDirectory()
.
Независимо от того, какой из этих API вы используете для сохранения данных для данного пользователя, данные не будут доступны при работе от имени другого пользователя. С точки зрения вашего приложения, каждый пользователь работает на совершенно отдельном устройстве.
Идентификация пользователей в многопользовательской среде
Если ваше приложение хочет идентифицировать уникальных пользователей, например, для сбора аналитики или создания других связей учетных записей, вам следует следовать рекомендуемым методам идентификации уникальных установок . Создав новый UUID
при первом запуске вашего приложения, вы обязательно получите уникальный идентификатор для отслеживания каждого пользователя, независимо от того, сколько пользователей устанавливают ваше приложение на одном устройстве. Кроме того, вы можете сохранить локальный токен, полученный с вашего сервера, или использовать идентификатор регистрации, предоставленный Google Cloud Messaging .
Помните: если ваше приложение запрашивает один из идентификаторов аппаратного устройства (например, MAC-адрес WiFi или SERIAL
номер), оно предоставит одно и то же значение для каждого пользователя, поскольку эти идентификаторы привязаны к оборудованию, а не к пользователю. Не говоря уже о других проблемах, которые создают эти идентификаторы, о которых говорилось в блоге «Идентификация установок приложений» .
Новые глобальные настройки
Системные настройки были обновлены для поддержки нескольких пользователей с добавлением Settings.Global
. Эта коллекция параметров аналогична Settings.Secure
, поскольку они доступны только для чтения, но применяются глобально во всех пользовательских пространствах на устройстве.
Некоторые существующие настройки были перенесены сюда из Settings.System
или Settings.Secure
. Если ваше приложение в настоящее время вносит изменения в настройки, ранее определенные в Settings.System
(например, AIRPLANE_MODE_ON
), то следует ожидать, что это больше не будет работать на устройстве под управлением Android 4.2 или более поздней версии, если эти настройки были перенесены в Settings.Global
. Вы можете продолжать читать настройки, которые находятся в Settings.Global
, но поскольку эти настройки больше не считаются безопасными для изменения приложений, попытка сделать это завершится неудачно, и система запишет предупреждение в системный журнал при запуске вашего приложения на Андроид 4.2 или выше.
Поддержка макета RTL
Android теперь предлагает несколько API, которые позволяют создавать пользовательские интерфейсы, которые плавно меняют ориентацию макета для поддержки языков, использующих пользовательский интерфейс с письмом справа налево (RTL) и направление чтения, таких как арабский и иврит.
Чтобы начать поддерживать макеты RTL в вашем приложении, установите атрибут android:supportsRtl
для элемента <application>
в файле манифеста и установите для него “true"
. Как только вы включите это, система позволит различным API-интерфейсам RTL отображать ваше приложение с RTL. Например, на панели действий справа будут отображаться значок и заголовок, а слева — кнопки действий, а любые макеты, созданные вами с помощью классов View
, предоставляемых платформой, также будут перевернуты.
Если вам необходимо дополнительно оптимизировать внешний вид вашего приложения при отображении с макетом RTL, существует два основных уровня оптимизации:
- Преобразуйте свойства макета, ориентированные слева и справа, в свойства макета, ориентированные на начало и конец.
Например, используйте
android:layout_marginStart
вместоandroid:layout_marginLeft
иandroid:layout_marginEnd
вместоandroid:layout_marginRight
.Класс
RelativeLayout
также предоставляет соответствующие атрибуты макета для замены позиций слева и справа, напримерandroid:layout_alignParentStart
для заменыandroid:layout_alignParentLeft
иandroid:layout_toStartOf
вместоandroid:layout_toLeftOf
. - Или, чтобы обеспечить полную оптимизацию макетов с письмом справа налево, вы можете предоставить совершенно отдельные файлы макета, используя квалификатор ресурса
ldrtl
(ldrtl
означает направление макета справа налево}). Например, вы можете сохранить файлы макетов по умолчанию вres/layout/
, а макеты, оптимизированные для RTL, — вres/layout-ldrtl/
.Квалификатор
ldrtl
отлично подходит для рисуемых ресурсов, позволяя предоставлять графику, ориентированную в направлении, соответствующем направлению чтения.
В рамках платформы доступны различные другие API для поддержки макетов RTL, например, в классе View
, чтобы вы могли реализовать правильное поведение для пользовательских представлений, и в Configuration
для запроса текущего направления макета.
Примечание. Если вы используете SQlite и у вас есть таблицы или имена столбцов, состоящие только из чисел, будьте осторожны: использование String.format(String, Object...)
может привести к ошибкам, когда числа будут преобразованы в их арабские эквиваленты, если на вашем устройстве установлена арабская локаль. Вы должны использовать String.format(Locale,String,Object...)
чтобы гарантировать сохранение чисел в формате ASCII. Также используйте String.format("%d", int)
вместо использования. String.valueOf(int)
для форматирования чисел.
Вложенные фрагменты
Теперь вы можете вставлять фрагменты внутрь фрагментов. Это полезно в различных ситуациях, когда вы хотите поместить динамические и повторно используемые компоненты пользовательского интерфейса в компонент пользовательского интерфейса, который сам по себе является динамическим и повторно используемым. Например, если вы используете ViewPager
для создания фрагментов, которые прокручиваются влево и вправо и занимают большую часть пространства экрана, теперь вы можете вставлять фрагменты в каждую страницу фрагмента.
Чтобы вложить фрагмент, просто вызовите getChildFragmentManager()
для Fragment
, в который вы хотите добавить фрагмент. Это возвращает FragmentManager
, который вы можете использовать, как обычно, из активности верхнего уровня для создания транзакций фрагментов. Например, вот код, который добавляет фрагмент из существующего класса Fragment
:
Котлин
val videoFragment = VideoPlayerFragment() childFragmentManager.beginTransaction().apply { add(R.id.video_fragment, videoFragment) commit() }
Ява
Fragment videoFragment = new VideoPlayerFragment(); FragmentTransaction transaction = getChildFragmentManager().beginTransaction(); transaction.add(R.id.video_fragment, videoFragment).commit();
Из вложенного фрагмента вы можете получить ссылку на родительский фрагмент, вызвав getParentFragment()
.
Библиотека поддержки Android теперь также поддерживает вложенные фрагменты, поэтому вы можете реализовать дизайн вложенных фрагментов на Android 1.6 и более поздних версиях.
Примечание. Вы не можете раздуть макет во фрагмент, если этот макет содержит <fragment>
. Вложенные фрагменты поддерживаются только при динамическом добавлении к фрагменту.
Рендерскрипт
Функциональность вычислений Renderscript была расширена за счет следующих функций:
- Внутренние функции скрипта
Вы можете использовать встроенные функции скрипта Renderscript, которые реализуют общие операции, такие как:
-
Blends
-
Blur
-
Color matrix
-
3x3 convolve
-
5x5 convolve
-
Per-channel lookup table
-
Converting an Android YUV buffer to RGB
Чтобы использовать встроенную функцию сценария, вызовите статический метод
create()
каждой встроенной функции, чтобы создать экземпляр сценария. Затем вы вызываете доступные методыset()
каждого встроенного скрипта, чтобы установить все необходимые входные данные и параметры. Наконец, вызовите методforEach()
для выполнения сценария.-
- Группы сценариев
ScriptGroup
позволяет объединять связанные сценарии Renderscript и выполнять их одним вызовом.Используйте
ScriptGroup.Builder
, чтобы добавить все сценарии в группу, вызвавaddKernel()
. Добавив все сценарии, создайте соединения между сценариями, вызвавaddConnection()
. Когда вы закончите добавлять соединения, вызовитеcreate()
, чтобы создать группу сценариев. Перед выполнением группы сценариев укажите входноеAllocation
и начальный сценарий для запуска с помощью методаsetInput(Script.KernelID, Allocation)
и укажите выходноеAllocation
, куда будет записан результат, и окончательный сценарий для запуска с помощьюsetOutput()
. Наконец, вызовитеexecute()
для запуска группы сценариев.- Фильтрскрипт
Filterscript определяет ограничения для существующих API-интерфейсов Renderscript, которые позволяют полученному коду работать на более широком спектре процессоров (ЦП, графических процессоров и DSP). Чтобы создать файлы Filterscript, создайте файлы
.fs
вместо файлов.rs
и укажите#pragma rs_fp_relaxed
чтобы сообщить среде выполнения Renderscript, что ваши сценарии не требуют строгой точности с плавающей запятой IEEE 754-2008. Эта точность позволяет сбрасывать до нуля денормативные значения и округлять их до нуля. Кроме того, ваши сценарии Filterscript не должны использовать 32-битные встроенные типы и должны указывать пользовательскую корневую функцию с помощью атрибута__attribute__((kernel))
поскольку Filterscript не поддерживает указатели, которые являются сигнатурой функцииroot()
по умолчанию. определяет.
Примечание. Хотя поддержка Filterscript присутствует в платформе, поддержка разработчиков будет доступна в SDK Tools Release 21.0.1.
Подробный обзор всех изменений API в Android 4.2 см. в отчете о различиях API .