API 级别:17
Android 4.2(JELLY_BEAN_MR1
)
是对 Jelly Bean 版本的更新,为用户和应用提供了新功能
开发者。本文档介绍了 Google Cloud 中
实用的新 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 系统映像上安装您的应用并进行测试,然后发布此变更的更新。
您可以通过在代码中添加条件,在执行您的 minSdkVersion
不支持的 API 之前检查系统 API 级别,实现在使用 Android 4.2 中的 API 的同时仍为旧版本提供支持。如需详细了解如何保持向后兼容性,请参阅创建向后兼容界面。
如需详细了解 API 级别的工作原理,请参阅什么是 API 水平?
重要的行为变更
如果您之前发布过 Android 应用,请注意以下事项 可能影响应用行为的更改:
- 默认情况下,系统不再导出content provider。也就是说,
android:exported
属性的默认值现在为“false"
。如果其他应用能够访问您的 content provider 非常重要,您现在必须明确设置android:exported="true"
。只有当您将
android:targetSdkVersion
或android:minSdkVersion
设置为 17 或更高版本时,此变更才会生效。否则,即使在 Android 4.2 及更高版本上运行,默认值仍为“true"
。 - 与以前的 Android 版本相比,用户位置信息结果可能不太准确
如果您的应用请求
ACCESS_COARSE_LOCATION
权限,但 不请求ACCESS_FINE_LOCATION
权限。当您的应用请求获得以下权限时,满足用户在隐私权方面的期望: 粗略位置(而非精确位置)时,系统不会提供用户位置估算值 比城市街区更准确。
Settings.System
定义的某些设备设置现在为 只读属性。如果您的应用尝试将更改写入已移至Settings.Global
的Settings.System
中定义的设置,则在 Android 4.2 及更高版本上运行时,写入操作将静默失败。即使
android:targetSdkVersion
和android:minSdkVersion
的值低于 17,您的应用也无法修改 在 Android 4.2 及更高版本上运行时已移至Settings.Global
。- 如果您的应用使用
WebView
,Android 4.2 会添加额外的安全层,以便您更安全地将 JavaScript 绑定到 Android 代码。如果您将targetSdkVersion
设置为 17 或更高,则现在必须向您希望 JavaScript(此方法也必须为公开方法)可用的任何方法添加@JavascriptInterface
注解。如果您没有提供 注解,则WebView
中的网页无法访问此方法 在 Android 4.2 或更高版本上运行时。如果您将targetSdkVersion
版本 16 或更低版本,则不是必需的,但我们建议您更新目标版本 并添加注释以提高安全性。
Daydream
Daydream 是 Android 设备的一种全新互动式屏保模式。它会自动激活 当设备插入基座时,或当设备插入基座时处于空闲状态时 充电(而不是关闭屏幕)。Daydream 一次显示一个梦, 是纯视觉的被动显示,轻触时会关闭,或者可能是互动式的自适应型显示设备 一整套输入事件。梦想会在应用进程中运行,并且拥有以下全部权限: Android 界面工具包(包括视图、布局和动画),使其更加灵活 比动态壁纸或应用微件更强大。
您可以通过实现 DreamService
的子类为 Daydream 创建梦想。DreamService
API 的设计与 Activity
API 类似。要为
实现以下目的后,随时将布局资源 ID 或 View
传递给 setContentView()
:
一个窗口,例如在 onAttachedToWindow()
中
回调。
DreamService
类在基本 Service
API(例如 onDreamingStarted()
、onDreamingStopped()
和 onDetachedFromWindow()
)之上提供了其他重要的生命周期回调方法。您无法从应用启动 DreamService
,而是由系统自动启动。
如果您的智能作梦内容是交互式的,您可以从智能作梦内容中启动 activity,将用户引导至应用的完整界面,以便查看更多详细信息或进行更多控制。您可以使用 finish()
结束智能作梦,以便用户看到新的 activity。
如需向系统提供您的智能作业,请在清单文件中使用 <service>
元素声明 DreamService
。然后,您必须添加一个具有 "android.service.dreams.DreamService"
操作的 intent 过滤器。例如:
<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
的辅助显示屏,
使用 DisplayManager
或 MediaRouter
API。虽然 DisplayManager
API 可让您
则通常应使用 MediaRouter
来快速访问系统的默认显示屏,
演示文稿。
如需获取演示文稿的默认显示,请调用 MediaRouter.getSelectedRoute()
并传入 ROUTE_TYPE_LIVE_VIDEO
。这将返回一个 MediaRouter.RouteInfo
对象,用于描述系统当前选定的路线
。如果 MediaRouter.RouteInfo
不为 null,请调用
getPresentationDisplay()
,用于获取表示已连接屏幕的 Display
。
然后,您可以通过传递 Display
对象来显示演示文稿
转换为 Presentation
类的构造函数。现在,您的演示文稿将
显示在辅助显示屏上
如需在运行时检测何时连接了新屏幕,请创建一个 MediaRouter.SimpleCallback
实例,并在其中实现 onRoutePresentationDisplayChanged()
回调方法,系统会在有新的屏幕连接时调用该方法
已连接展示显示屏。然后,将 MediaRouter.SimpleCallback
与 ROUTE_TYPE_LIVE_VIDEO
路线类型一起传递给 MediaRouter.addCallback()
,以注册 MediaRouter.SimpleCallback
。收到对 onRoutePresentationDisplayChanged()
的调用时,只需调用 MediaRouter.getSelectedRoute()
,如上所述。
如需进一步优化 Presentation
中的界面以适应辅助屏幕,您可以通过在应用或 activity 中应用的 <style>
中指定 android:presentationTheme
属性来应用其他主题。
请注意,连接到用户设备的屏幕通常较大,
可能不同的屏幕密度由于屏幕特性可能会有所不同,因此您应该
提供专门针对如此大屏幕进行了优化的资源。如果您需要向 Presentation
请求更多资源,请调用 getContext()
.getResources()
以获取与显示屏对应的 Resources
对象。这提供了
从您的应用中选出最适合您的应用的
辅助显示屏的屏幕尺寸和密度
如需了解详情和查看一些代码示例,请参阅 Presentation
类文档。
锁屏微件
Android 现在允许用户将应用微件添加到锁定屏幕。如需让应用微件可在锁定屏幕上使用,请向指定 AppWidgetProviderInfo
的 XML 文件添加 android:widgetCategory
属性。此属性支持两个值: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
,您可以确保获得用于跟踪每位用户的唯一 ID,无论单个设备上安装了多少用户的应用。或者,您也可以保存从
也可以使用 Google 云消息传递提供的注册 ID。
请注意,如果您的应用请求某个硬件设备标识符(例如 Wi-Fi MAC 地址或 SERIAL
号码),则会为每位用户提供相同的值,因为这些标识符与硬件相关联,而不是与用户相关联。更别说
如识别
应用安装博文。
新的全局设置
系统设置已更新,增加了 Settings.Global
,以支持多用户。此设置集合类似于 Settings.Secure
设置,因为它们是只读的,但会应用于
设备上的所有用户空间
有多项现有设置从“Settings.System
”或“Settings.Secure
”转移到了这里。如果您的应用
目前正在更改之前在 Settings.System
中定义的设置
(例如 AIRPLANE_MODE_ON
),那么您应该会发现
在搭载 Android 4.2 或更高版本的设备上,如果上述设置
已移至Settings.Global
。您可以继续查看
Settings.Global
,但由于设置不再安全
更改应用,尝试进行此类更改时将静默失败,并且系统会向
在 Android 4.2 或更高版本上运行应用时,查看系统日志。
RTL 布局支持
Android 现在提供了多个 API,可让您构建能够优雅地转换布局方向的界面,以支持使用从右到左 (RTL) 界面和阅读方向的语言,例如阿拉伯语和希伯来语。
如需开始在应用中支持 RTL 布局,请在清单文件中将 android:supportsRtl
属性设置为 <application>
元素,并将其设置为 “true"
。启用此功能后,系统会启用各种 RTL API,以便您的应用以 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
。 - 或者,如需针对 RTL 布局提供完整优化,您可以使用
ldrtl
资源限定符(ldrtl
代表“布局方向 - 从右到左”)提供完全独立的布局文件。例如,您可以将默认布局文件保存在res/layout/
以及res/layout-ldrtl/
中的 RTL 优化布局。ldrtl
限定符非常适合可绘制资源,因此您可以 朝向与阅读方向对应的方向的图形。
框架中还提供了各种其他 API 来支持 RTL 布局,例如
View
类,以便您可以为自定义
在 Configuration
中查询当前的布局方向。
注意:如果您使用的是 SQlite,并且表或列名称是“仅数字”类型,请务必小心:如果您的设备已设置为阿拉伯语语言区域,使用 String.format(String, Object...)
可能会导致数字转换为其阿拉伯语等效项,从而导致错误。您必须使用 String.format(Locale,String,Object...)
来确保号码
以 ASCII 格式保存。也使用 String.format("%d", int)
,而不是使用
String.valueOf(int)
:
设置数字格式。
嵌套 Fragment
现在,您可以在 fragment 中嵌入 fragment。这对于各种情况下将动态且可重用的界面组件放入本身为动态且可重用的界面组件非常有用。例如,如果您使用 ViewPager
来
创建左右滑动并占用大部分屏幕空间的 fragment,
现在,将片段插入每个片段页面中
如需嵌套 fragment,只需在getChildFragmentManager()
要在其中添加 fragment 的 Fragment
。这将返回一个 FragmentManager
,您可以像往常从顶级 activity 中一样使用它
来创建 fragment 事务。例如,以下代码可从现有 Fragment
类中添加 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();
在嵌套 fragment 中,您可以通过调用 getParentFragment()
来获取对父 fragment 的引用。
Android 支持库现在支持嵌套 fragment,因此您可以实现嵌套式 fragment fragment 设计。
注意:如果某个布局
包含 <fragment>
。嵌套 fragment 只有在添加到
fragment。
Renderscript
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
-
Filterscript 对现有 Renderscript API 定义了限制,以便生成的代码能够在更多类型的处理器(CPU、GPU 和 DSP)上运行。如需创建 Filterscript 文件,请创建
.fs
文件而不是.rs
文件,并将#pragma rs_fp_relaxed
指定为 告知 Renderscript 运行时您的脚本不需要严格的 IEEE 754-2008 浮点精度。 这种精度允许非规格化数清零,还可进行向零舍入。此外,您的 Filterscript 脚本不得使用 32 位内置类型,并且必须使用__attribute__((kernel))
属性,因为 Filterscript 不支持指针, 由root()
函数的默认签名定义。
注意:虽然平台支持 Filterscript,但 SDK 工具版本 21.0.1 中将提供开发者支持。
如需详细了解 Android 4.2 中的所有 API 变更,请参阅 API 差异报告。