Уровень API: 17
Android 4.2 (JELLY_BEAN_MR1) – это обновление Jelly Bean, в котором появились новые функции для пользователей и разработчиков приложений. В этом документе представлены наиболее заметные и полезные новые API для разработчиков.
Разработчикам приложений рекомендуется как можно скорее скачать образ системы Android 4.2 и платформу SDK из SDK Manager. Если у вас нет устройства с 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…
Важные изменения в поведении
Если вы уже публиковали приложение для Android, обратите внимание на следующие изменения, которые могут повлиять на его работу:
- Поставщики контента больше не экспортируются по умолчанию. Это значит, что значением по умолчанию для атрибута
android:exportedтеперь является“false". Если вам важно, чтобы другие приложения могли получить доступ к вашему поставщику контента, вам необходимо явно задать значениеandroid:exported="true".Это изменение вступит в силу, только если для параметра
android:targetSdkVersionилиandroid:minSdkVersionзадано значение 17 или выше. В противном случае значением по умолчанию будет“true", даже если приложение запущено на устройстве с Android 4.2 или более поздней версией. - Если приложение запрашивает разрешение
ACCESS_COARSE_LOCATION, но не запрашиваетACCESS_FINE_LOCATION, то результаты определения местоположения пользователя могут быть менее точными, чем в предыдущих версиях Android.Чтобы обеспечить конфиденциальность пользователей, когда приложение запрашивает разрешение на доступ к приблизительному местоположению (а не точному), система не будет предоставлять данные о местоположении пользователя, которые точнее, чем городской квартал.
- Некоторые настройки устройств, заданные в
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().
Класс Presentation является расширением класса Dialog и определяет область, в которой приложение может отображать уникальный интерфейс на дополнительном экране.
Чтобы определить дополнительные экраны, на которых можно показывать 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-адрес Wi-Fi или номер SERIAL), они будут предоставлять одно и то же значение для каждого пользователя, поскольку эти идентификаторы привязаны к оборудованию, а не к пользователю. Не говоря уже о других проблемах, которые возникают при использовании этих идентификаторов и описаны в статье Идентификация установок приложений.
Новые глобальные настройки
Системные настройки были обновлены, чтобы поддерживать несколько пользователей с добавлением Settings.Global. Этот набор настроек похож на настройки Settings.Secure, поскольку они доступны только для чтения, но применяются глобально ко всем пользовательским пространствам на устройстве.
Некоторые настройки были перенесены сюда из Settings.System или Settings.Secure. Если ваше приложение в настоящее время изменяет настройки, ранее определенные в Settings.System (например, AIRPLANE_MODE_ON), то эти изменения больше не будут работать на устройстве с Android 4.2 или более поздней версии, если эти настройки были перенесены в Settings.Global. Вы по-прежнему можете считывать настройки из Settings.Global, но поскольку они больше не считаются безопасными для изменения приложениями, попытка сделать это не удастся, и система запишет предупреждение в системный журнал при запуске вашего приложения на Android 4.2 или более поздней версии.
Поддержка макетов с направлением письма справа налево
В Android теперь есть несколько API, которые позволяют создавать пользовательские интерфейсы, поддерживающие языки с направлением письма справа налево, например арабский и иврит.
Чтобы добавить в приложение поддержку макетов с направлением письма справа налево, задайте атрибут android:supportsRtl для элемента <application> в файле манифеста и установите для него значение “true". После этого система включит различные API, чтобы приложение отображалось с макетами, поддерживающими направление письма справа налево. Например, на панели действий значок и название будут показаны справа, а командные кнопки – слева. Кроме того, будут перевернуты все макеты, созданные с помощью классов View, предоставляемых фреймворком.
Если вам нужно оптимизировать внешний вид приложения при отображении с макетом с письмом справа налево, есть два основных уровня оптимизации:
- Преобразуйте свойства макета, ориентированные на левую и правую стороны, в свойства макета, ориентированные на начало и конец.
Например, используйте
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означает layout-direction-right-to-left). Например, файлы макетов по умолчанию можно сохранить в папкеres/layout/, а макеты, оптимизированные для языков с письмом справа налево, – в папкеres/layout-ldrtl/.Квалификатор
ldrtlотлично подходит для ресурсов, которые можно нарисовать, чтобы вы могли предоставлять графику, ориентированную в направлении, соответствующем направлению чтения.
В фреймворке есть и другие API, поддерживающие макеты с направлением справа налево. Например, класс View позволяет реализовать правильное поведение для пользовательских представлений, а Configuration – запросить текущее направление макета.
Примечание. Если вы используете SQlite и у вас есть таблицы или столбцы, названия которых состоят только из цифр, будьте осторожны: использование String.format(String, Object...) может привести к ошибкам, когда цифры будут преобразованы в их арабские эквиваленты, если на вашем устройстве установлена арабская локаль.
Чтобы числа сохранялись в формате ASCII, используйте String.format(Locale,String,Object...). Кроме того, вместо String.valueOf(int) для форматирования чисел используйте String.format("%d", int).
Вложенные фрагменты
Теперь вы можете встраивать фрагменты в другие фрагменты. Это полезно в различных ситуациях, когда вам нужно поместить динамические и многократно используемые компоненты интерфейса в другой динамический и многократно используемый компонент. Например, если вы используете ViewPager для создания фрагментов, которые пролистываются влево и вправо и занимают большую часть экрана, теперь вы можете вставлять фрагменты на каждую страницу фрагмента.
Чтобы вложить фрагмент, просто вызовите getChildFragmentManager() для Fragment, в который вы хотите добавить фрагмент. Этот метод возвращает объект FragmentManager, который можно использовать для создания транзакций фрагментов так же, как и в случае с действием верхнего уровня. Например, следующий код добавляет фрагмент из существующего класса Fragment:
Kotlin
val videoFragment = VideoPlayerFragment() childFragmentManager.beginTransaction().apply { add(R.id.video_fragment, videoFragment) commit() }
Java
Fragment videoFragment = new VideoPlayerFragment(); FragmentTransaction transaction = getChildFragmentManager().beginTransaction(); transaction.add(R.id.video_fragment, videoFragment).commit();
Из вложенного фрагмента можно получить ссылку на родительский фрагмент, вызвав метод getParentFragment().
Библиотека поддержки Android теперь также поддерживает вложенные фрагменты, поэтому вы можете реализовывать вложенные фрагменты в Android 1.6 и более поздних версиях.
Примечание. Вы не можете развернуть макет во фрагмент, если этот макет содержит <fragment>. Вложенные фрагменты поддерживаются, только если они добавлены во фрагмент динамически.
RenderScript
Функциональность вычислений Renderscript была расширена за счет следующих возможностей:
- Встроенные функции скрипта
Вы можете использовать встроенные скрипты Renderscript, которые реализуют распространенные операции, например:
BlendsBlurColor matrix3x3 convolve5x5 convolvePer-channel lookup tableConverting 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
-
Filterscript определяет ограничения для существующих API Renderscript, которые позволяют запускать результирующий код на более широком спектре процессоров (ЦП, графических процессорах и цифровых сигнальных процессорах). Чтобы создать файлы 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.