Android 4.4 API

API 级别:19

Android 4.4 (KITKAT) 是 Android 平台的新版本,为用户和应用开发者提供了新功能。本文旨在介绍其中最值得关注的新 API。

作为应用开发者,您应尽快从 SDK 管理器下载 Android 4.4 系统映像和 SDK 平台。如果您没有搭载 Android 4.4 的设备来测试您的应用,请在 Android 模拟器上使用 Android 4.4 系统映像测试应用。然后,针对 Android 4.4 平台构建应用,以开始使用最新的 API。

更新目标 API 级别

为了更好地针对搭载 Android 4.4 的设备优化您的应用,您应将 targetSdkVersion 设置为 "19",将其安装在 Android 4.4 系统映像上并进行测试,然后发布包含此变更的更新。

您可以在使用 Android 4.4 中的 API 的同时支持旧版本,方法是在代码中添加条件,先检查系统 API 级别,然后再执行 minSdkVersion 不支持的 API。如需详细了解如何保持向后兼容性,请参阅支持不同平台版本

如需详细了解 API 级别的工作原理,请参阅什么是 API 级别?

重要的行为变更

如果您之前发布过 Android 应用,请注意您的应用可能会受到 Android 4.4 变更的影响。

如果您的应用从外部存储空间读取...

您的应用在 Android 4.4 上运行时无法读取外部存储空间中的共享文件,除非该应用具有 READ_EXTERNAL_STORAGE 权限。也就是说,如果没有此权限,就不能再访问 getExternalStoragePublicDirectory() 返回的目录中的文件。不过,如果您只需要访问 getExternalFilesDir() 提供的应用专用目录,则无需 READ_EXTERNAL_STORAGE 权限。

如果您的应用使用 WebView...

在 Android 4.4 上运行时,应用的行为可能会有所不同,尤其是将应用的 targetSdkVersion 更新为“19”或更高版本时。

WebView 类的基础代码和相关 API 已升级为基于新式 Chromium 源代码快照。这会带来诸多性能改进、对新 HTML5 功能的支持,以及对 WebView 内容远程调试的支持。此次升级的范围意味着,如果您的应用使用 WebView,在某些情况下,其行为可能会受到影响。虽然只有您将应用的 targetSdkVersion 更新为“19”或更高版本时,才会记录已知的行为变更,并且这些变更主要会影响您的应用,但新的 WebView 会以“怪异模式”运行,以便在以 API 级别 18 及更低级别为目标平台的应用中提供一些旧版功能,但您的应用可能依赖于先前 WebView 版本的未知行为。

因此,如果您的现有应用使用 WebView,请务必尽快在 Android 4.4 上进行测试,并参阅迁移到 Android 4.4 中的 WebView,了解将 targetSdkVersion 更新为“19”或更高版本时可能会受到的影响。

如果您的应用使用 AlarmManager...

将应用的 targetSdkVersion 设为“19”或更高的值后,您使用 set()setRepeating() 创建的闹钟将不准确。

为提高电源效率,Android 现在批处理在合理的相似时间发生的所有应用的闹铃,以便系统仅唤醒设备一次,而不是多次唤醒设备来处理每个闹铃。

如果您的闹钟没有与确切的时钟时间相关联,但仍有必要在特定时间范围内(例如下午 2 点到 4 点之间)调用闹钟,则可以使用新的 setWindow() 方法,该方法接受闹钟的“最早”时间以及系统调用闹钟的最早时间之后的“窗口”。

如果您的闹钟必须固定到一个确切的时钟时间(例如对于日历活动提醒),则可以使用新的 setExact() 方法。

这种不精确的批处理行为仅适用于更新后的应用。如果您已将 targetSdkVersion 设为“18”或更低版本,那么在 Android 4.4 上运行时,闹钟的行为方式将与在之前版本上一样。

如果您的应用使用 ContentResolver 同步数据...

如果您将应用的 targetSdkVersion 设为“19”或更高级别,则创建与 addPeriodicSync() 同步的操作会在默认的灵活间隔(约为您所指定时间段的 4%)内执行同步操作。例如,如果您的轮询频率是 24 小时,则您的同步操作每天可能会在大约一小时的时间窗口内发生,而不是在确切地同一时间发生。

如需自行为同步操作指定 Flex 间隔,您应该开始使用新的 requestSync() 方法。如需了解详情,请参阅下文的同步适配器部分。

这种 Flex 间隔行为仅适用于更新后的应用。如果您将 targetSdkVersion 设为“18”或更低版本,那么在 Android 4.4 上运行时,现有同步请求的行为方式与在先前版本中的行为相同。

打印框架

Android 现在包含一个完整框架,可让用户使用通过 Wi-Fi、蓝牙或其他服务连接的打印机打印任何文档。系统会处理想要打印文档的应用和向打印机传送打印任务的服务之间的事务。android.print 框架提供了指定打印文档并将其传送到系统进行打印所需的所有 API。对于给定的打印作业,您实际需要哪个 API 取决于您的内容。

打印通用内容

如果要将界面中的内容作为文档输出,您需要先创建 PrintDocumentAdapter 的子类。在此类中,您必须实现一些回调方法,其中包括用于根据提供的打印属性建立布局的 onLayout(),以及用于将可打印内容序列化为 ParcelFileDescriptoronWrite()

为了将内容写入 ParcelFileDescriptor,您必须向其传递一个 PDF 文件。新的 PdfDocument API 通过提供来自 getCanvas()Canvas(您可在其上绘制可打印内容),便捷地执行此操作。然后,使用 writeTo() 方法将 PdfDocument 写入 ParcelFileDescriptor

定义 PrintDocumentAdapter 的实现后,您可以根据用户请求,使用 PrintManager 方法 print() 执行打印任务,该方法会将 PrintDocumentAdapter 作为其参数之一。

打印图像

如果您只需要打印照片或其他位图,那么支持库中的帮助程序 API 可以为您完成所有工作。只需创建一个新的 PrintHelper 实例,使用 setScaleMode() 设置缩放模式,然后将 Bitmap 传递给 printBitmap() 即可。大功告成。支持库将处理与系统进行的所有剩余交互,以将位图传输到打印机。

构建打印服务

作为打印机 OEM,您可以使用 android.printservice 框架通过 Android 设备提供与打印机的互操作性。您可以以 APK 的形式构建和分发打印服务,以供用户在其设备上安装。打印服务应用主要作为无头服务运行,具体方法是为 PrintService 类创建子类,该类从系统接收打印任务,并使用适当的协议将任务传输给其打印机。

如需详细了解如何打印应用内容,请参阅打印内容

短信提供程序

Telephony 内容提供程序(简称“短信提供程序”)允许应用在设备上读取和写入短信和彩信。它包含已进行接收、起草、发送、挂起等操作的短信和彩信的表格。

从 Android 4.4 开始,系统设置允许用户选择“默认短信应用”。选择后,只有默认短信应用才能向短信提供程序写入数据,并且当用户收到短信时,只有默认短信应用会收到 SMS_DELIVER_ACTION 广播;在用户收到彩信时,则只有默认短信应用会收到 WAP_PUSH_DELIVER_ACTION 广播。默认短信应用有责任在收到或发送新消息时将消息的详细信息写入短信提供程序。

未被选为默认短信应用的其他应用只能读取短信提供程序,但也可以在收到新短信时通过监听 SMS_RECEIVED_ACTION 广播(一种不可中止的广播,可能会发送到多个应用)收到通知。此广播主要用于那些没有被选为默认短信应用、但需要读取特殊传入消息(例如进行手机号码验证)的应用。

有关详情,请阅读博文为您的短信应用为 KitKat 做好准备

无线和连接

主机卡模拟

Android 应用现在可以模拟使用 APDU 进行数据交换的 ISO14443-4 (ISO-DEP) NFC 卡(如 ISO7816-4 中所指定)。这让运行 Android 4.4 并启用 NFC 的设备可以同时模拟多个 NFC 卡,并允许 NFC 支付终端或其他 NFC 读取器基于应用标识符 (AID) 通过适当的 NFC 卡发起交易。

如果您要在应用中模拟使用这些协议的 NFC 卡,请基于 HostApduService 类创建一个服务组件。然而,如果您的应用改用安全元件进行卡模拟,则您需要基于 OffHostApduService 类创建一项服务,该服务并不直接参与交易,但对于注册应由安全元件处理的 AID 而言是必需的。

如需了解详情,请参阅 NFC 卡模拟指南。

NFC 读取器模式

新的 NFC 读取器模式允许 Activity 限制所有 NFC Activity,使其仅在前台运行时读取其感兴趣的标签类型。您可以使用 enableReaderMode() 为 activity 启用读取器模式,从而提供 NfcAdapter.ReaderCallback 的实现,以便在检测到新代码时接收回调。

这项新功能与主机卡模拟相结合,可以让 Android 在移动支付接口的两端运行:一部设备作为付款终端运行(运行读取器模式 activity 的设备),另一部设备作为付款客户端运行(模拟 NFC 卡的设备)。

红外线发射器

在包含红外 (IR) 发射器的设备上运行时,您现在可以使用 ConsumerIrManager API 发射 IR 信号。如需获取 ConsumerIrManager 的实例,请使用 CONSUMER_IR_SERVICE 作为参数调用 getSystemService()。然后,您可以使用 getCarrierFrequencies() 查询设备支持的 IR 频率,并通过使用 transmit() 传递所需的频率和信号模式来传输信号。

您始终应首先通过调用 hasIrEmitter() 来检查设备是否包含 IR 发射器,但如果您的应用仅与具有 IR 发射器的设备兼容,则应在清单中为 "android.hardware.consumerir" (FEATURE_CONSUMER_IR) 添加一个 <uses-feature> 元素。

多媒体

自适应播放

现在,通过 MediaCodec API 支持自适应视频播放,以便在 Surface 上播放期间实现分辨率无缝更改。您可以馈送新分辨率的解码器输入帧,输出缓冲区的分辨率不会出现明显的间隙。

如需启用自适应播放,您可以向 MediaFormat 添加两个键(KEY_MAX_WIDTHKEY_MAX_HEIGHT 以指定您的应用所需的编解码器最大分辨率)。将上述代码添加到 MediaFormat 后,使用 configure()MediaFormat 传递给 MediaCodec 实例。

编解码器将以无缝方式在等于或小于这些值的分辨率之间进行转换。编解码器可能还支持大于指定最大值的分辨率(只要在受支持配置文件的限制内),但可能无法以无缝方式转换到较大分辨率。

要在解码 H.264 视频时更改分辨率,请继续使用 MediaCodec.queueInputBuffer() 为帧排队,但请确保在一个缓冲区中通过即时解码刷新 (IDR) 帧同时提供新的序列参数集 (SPS) 和图像参数集 (PPS) 值。

不过,在尝试配置编解码器以进行自适应播放之前,您必须先使用 FEATURE_AdaptivePlayback 调用 isFeatureSupported(String),以验证设备是否支持自适应播放。

注意:是否支持自适应播放因供应商而异。某些编解码器可能需要更多内存才能提供更大的分辨率提示。因此,您应基于您正在解码的源材料设置分辨率最大值。

音频点播时间戳

为促进音频和视频同步,新的 AudioTimestamp 类提供了有关由 AudioTrack 处理的音频流中特定“帧”的时间轴详细信息。如需获取最新的可用时间戳,请实例化一个 AudioTimestamp 对象并将其传递给 getTimestamp()。如果针对时间戳的请求成功,则系统会使用帧单元中的某个位置以及呈现或承诺呈现该帧的预计时间填充 AudioTrack 实例。

您可以使用 AudioTimestamp(单调)中 nanoTime 的值查找与 framePosition 相比最接近的相关视频帧,以便丢弃、复制或插值视频帧以匹配音频。或者,您也可以确定 nanoTime 的值与未来视频帧的预计时间之间的增量时间(需考虑采样率),以预测哪个音频帧会与视频帧同时出现。

Surface 图像读取器

新的 ImageReader API 可让您在图像缓冲区渲染为 Surface 时直接访问图像缓冲区。您可以使用静态方法 newInstance() 获取 ImageReader。然后,调用 getSurface() 以创建新的 Surface,并使用 MediaPlayerMediaCodec 等提供方传送您的图片数据。如需在 Surface 提供新图片时收到通知,请实现 ImageReader.OnImageAvailableListener 接口并向 setOnImageAvailableListener() 注册该接口。

现在,当您将内容绘制到 Surface 时,ImageReader.OnImageAvailableListener 会在每个新图片帧可用时收到对 onImageAvailable() 的调用,并为您提供相应的 ImageReader。您可以通过调用 acquireLatestImage()acquireNextImage(),使用 ImageReaderImage 对象的形式获取帧的图片数据。

Image 对象支持直接访问 ByteBuffer 中图片的时间戳、格式、尺寸和像素数据。不过,为了让 Image 类能解读您的图片,必须根据 ImageFormatPixelFormat 中的常量定义的类型之一来设置图片格式。

峰值和有效值 (RMS) 测量

您现在可以查询来自 Visualizer 的当前音频流的峰值和 RMS,方法是创建新的 Visualizer.MeasurementPeakRms 实例并将其传递给 getMeasurementPeakRms()。当您调用此方法时,给定 Visualizer.MeasurementPeakRms 的峰值和 RMS 值会设为最新的测量值。

音量增强器

LoudnessEnhancerAudioEffect 的新子类,可让您调高 MediaPlayerAudioTrack 的音量。结合上述新的 getMeasurementPeakRms() 方法,此功能特别有用,可以在播放其他媒体时提高语音音轨的音量。

遥控器

Android 4.0(API 级别 14)引入了 RemoteControlClient API,可让媒体应用使用来自远程客户端的媒体控制器事件,例如锁定屏幕上的媒体控件。现在,借助新的 RemoteController API,您可以构建自己的遥控器,从而创建能够控制与 RemoteControlClient 集成的任何媒体应用的播放的创新型新应用和外围设备。

如需构建遥控器,您可以随意实现界面,但如需将媒体按钮事件传递到用户的媒体应用,您必须创建一项服务来扩展 NotificationListenerService 类并实现 RemoteController.OnClientUpdateListener 接口。使用 NotificationListenerService 作为基础非常重要,因为它提供了适当的隐私权限制,这就要求用户在系统安全设置中启用您的应用作为通知监听器。

NotificationListenerService 类包含几个您必须实现的抽象方法,但如果您只关注用于处理媒体播放的媒体控制器事件,则可以将这些实现留空,而专注于 RemoteController.OnClientUpdateListener 方法。

从遥控器进行评分

Android 4.4 在远程控制客户端(使用 RemoteControlClient 接收媒体控制事件的应用)的现有功能的基础上,添加了让用户通过遥控器对当前曲目进行评分的功能。

新的 Rating 类封装了有关用户评分的信息。评分由其评分样式(RATING_HEARTRATING_THUMB_UP_DOWNRATING_3_STARSRATING_4_STARSRATING_5_STARSRATING_PERCENTAGE)和适合该样式的评分值定义。

要允许用户从遥控器对您的曲目进行评分:

如需在用户通过遥控器更改评分时接收回调,请实现新的 RemoteControlClient.OnMetadataUpdateListener 接口并向 setMetadataUpdateListener() 传递一个实例。当用户更改评分时,RemoteControlClient.OnMetadataUpdateListener 会收到对 onMetadataUpdate() 的调用,并传递 RATING_KEY_BY_USER 作为键和 Rating 对象作为值。

字幕

现在,VideoView 支持在播放 HTTP Live Stream (HLS) 视频时使用 WebVTT 字幕轨道,根据用户在系统设置中定义的字幕偏好设置来显示字幕轨道。

您还可以使用 addSubtitleSource() 方法为 VideoView 提供 WebVTT 字幕轨道。此方法接受包含字幕数据的 InputStream 和用于指定字幕数据格式的 MediaFormat 对象,您可以使用 createSubtitleFormat() 指定该对象。这些字幕也会根据用户的偏好设置显示在视频上。

如果您不使用 VideoView 显示视频内容,则应使字幕叠加层尽可能匹配用户的字幕偏好设置。借助新的 CaptioningManager API,您可以查询用户的字幕偏好设置,包括由 CaptioningManager.CaptionStyle 定义的样式,例如字体和颜色。如果用户在视频开始播放后调整了某些偏好设置,您应注册一个 CaptioningManager.CaptioningChangeListener 实例,以便在任何偏好设置发生变化时接收回调,从而监听偏好设置的变化,然后根据需要更新字幕。

动画和图形

场景和转场

新的 android.transition 框架提供了一些 API,可为在界面的不同状态之间添加动画效果。一项关键功能是,您可以为每个状态创建单独的布局,从而定义不同的界面状态(称为“场景”)。如果您想以动画形式从一个场景切换到另一个场景,请执行“过渡”,以计算将布局从当前场景更改为下一个场景所需的动画。

要在两个场景间进行转场,您通常需要执行以下操作:

  1. 指定包含您要更改的界面组件的 ViewGroup
  2. 指定表示变更的最终结果的布局(下一个场景)。
  3. 指定应添加布局变更动画的转场类型。
  4. 执行转场。

您可以使用 Scene 对象完成第 1 步和第 2 步。Scene 包含描述执行过渡所需的布局属性的元数据,包括场景的父视图和场景的布局。您可以使用类构造函数或静态方法 getSceneForLayout() 创建 Scene

然后,您必须使用 TransitionManager 完成第 3 步和第 4 步。一种方法是将 Scene 传递给静态方法 go()。这会在当前布局中找到场景的父视图,并对子视图执行过渡,以达到由 Scene 定义的布局。

或者,您也根本不需要创建 Scene 对象,而是可以调用 beginDelayedTransition(),指定包含您要更改的视图的 ViewGroup。然后,添加、移除或重新配置目标视图。在系统根据需要进行更改后,转场开始以动画方式呈现所有受影响的视图。

如需进行其他控制,您可以使用项目 res/transition/ 目录中的 XML 文件,定义应在预定义场景之间发生的转场集。在 <transitionManager> 元素内,指定一个或多个 <transition> 标记,每个标记都指定一个场景(对布局文件的引用)以及进入和/或退出该场景时要应用的过渡。然后,使用 inflateTransitionManager() 膨胀这组过渡。使用返回的 TransitionManager 通过 transitionTo() 执行每个转换,并传递由其中一个 <transition> 标记表示的 Scene。您还可以使用 TransitionManager API 以编程方式定义过渡集。

指定过渡时,您可以使用多种由 Transition 的子类(例如 FadeChangeBounds)定义的预定义类型。如果您未指定过渡类型,系统将默认使用 AutoTransition,它会根据需要自动淡出、移动和调整视图大小。此外,您还可以通过扩展其中任何类来创建自定义过渡,以按照自己的喜好执行动画。自定义过渡可跟踪您想要的任何属性更改,并根据这些更改创建您想要的任何动画。例如,您可以提供一个 Transition 的子类,用于监听对视图“rotation”属性的更改,然后为任何更改添加动画效果。

如需了解详情,请参阅 TransitionManager 文档。

动画暂停

借助 Animator API,您现在可以使用 pause()resume() 方法暂停和继续播放正在播放的动画。

如需跟踪动画的状态,您可以实现 Animator.AnimatorPauseListener 接口,该接口在动画暂停和继续播放时提供回调:pause()resume()。然后使用 addPauseListener() 将监听器添加到 Animator 对象。

或者,您也可以创建 AnimatorListenerAdapter 抽象类的子类,该类现在包含 Animator.AnimatorPauseListener 定义的暂停和恢复回调的空实现。

可重复使用的位图

现在,您可以在 BitmapFactory 中重复使用任何可变位图来解码任何其他位图(即使新位图具有不同的大小),只要生成的已解码位图的字节数(可从 getByteCount() 获取)小于或等于分配的已重用位图的字节数(可从 getAllocationByteCount() 获取)即可。如需了解详情,请参阅 inBitmap

适用于 Bitmap 的新 API 允许进行类似的重新配置,以便在 BitmapFactory 之外重复使用(用于手动生成位图或自定义解码逻辑)。现在,您可以使用 setHeight()setWidth() 方法设置位图的尺寸,并使用 setConfig() 指定新的 Bitmap.Config,而不会影响底层位图分配。reconfigure() 方法还提供了一种通过一次调用来合并这些更改的便捷方式。

不过,您不应重新配置视图系统当前使用的位图,因为底层像素缓冲区将无法以可预测的方式重新映射。

用户内容

存储访问框架

在以前的 Android 版本中,如果您希望应用从其他应用检索特定类型的文件,则必须调用包含 ACTION_GET_CONTENT 操作的 intent。此操作仍然是请求要导入到应用中的文件的适当方式。不过,Android 4.4 引入了 ACTION_OPEN_DOCUMENT 操作,可让用户选择特定类型的文件并授予应用对该文件的长期读取权限(可能具有写入权限),而无需将文件导入应用。

如果您要开发为文件提供存储服务(例如云端存档服务)的应用,则可以将 content provider 实现为新的 DocumentsProvider 类的子类,从而参与此统一界面来选择文件。您的 DocumentsProvider 子类必须包含一个接受 PROVIDER_INTERFACE 操作 ("android.content.action.DOCUMENTS_PROVIDER") 的 intent 过滤器。然后,您必须在 DocumentsProvider 中实现四个抽象方法:

queryRoots()
此方法必须返回一个Cursor,使用DocumentsContract.Root中定义的列来描述文档存储空间的所有根目录。
queryChildDocuments()
此方法必须返回一个 Cursor,使用 DocumentsContract.Document 中定义的列描述指定目录中的所有文件。
queryDocument()
此方法必须使用 DocumentsContract.Document 中定义的列返回描述指定文件的 Cursor
openDocument()
此方法必须返回表示指定文件的 ParcelFileDescriptor。用户选择文件,并且客户端应用通过调用 openFileDescriptor() 请求对该文件的访问权限后,系统就会调用此方法。

如需了解详情,请参阅存储访问框架指南。

外部存储空间访问

现在,您可以在辅助外部存储媒介上读取和写入应用专用文件,例如当设备同时提供模拟存储空间和 SD 卡时。新方法 getExternalFilesDirs() 的工作原理与现有的 getExternalFilesDir() 方法相同,只不过它会返回一个 File 对象的数组。在读取或写入此方法返回的任何路径之前,请将 File 对象传递给新的 getStorageState() 方法,以验证存储空间当前是否可用。

用于访问应用专用缓存目录和 OBB 目录的其他方法现在也具有提供辅助存储设备访问权限的相应版本:getExternalCacheDirs()getObbDirs()

返回的 File 数组中的第一个条目被视为设备的主要外部存储设备,与 getExternalFilesDir() 等现有方法返回的 File 相同。

注意:从 Android 4.4 开始,当您使用上述方法仅访问应用专属的外部存储空间区域时,平台不再要求应用获取 WRITE_EXTERNAL_STORAGEREAD_EXTERNAL_STORAGE。但是,如果您要访问由 getExternalStoragePublicDirectory() 提供的外部存储空间的可共享区域,则需要这些权限。

同步适配器

ContentResolver 中新增的 requestSync() 方法将请求封装在新的 SyncRequest 对象中(您可以使用 SyncRequest.Builder 创建该对象),从而简化了为 ContentProvider 定义同步请求的一些过程。SyncRequest 中的属性提供与现有 ContentProvider 同步调用相同的功能,但添加了相关功能,通过启用 setDisallowMetered() 指定在网络按流量计费时应丢弃某同步。

用户输入

新传感器类型

新的 TYPE_GEOMAGNETIC_ROTATION_VECTOR 传感器基于磁力计提供旋转矢量数据,当陀螺仪不可用或与批处理传感器事件配合使用以记录手机处于休眠状态时的设备方向时,该传感器可以有效地替代 TYPE_ROTATION_VECTOR 传感器。该传感器所需的功耗低于 TYPE_ROTATION_VECTOR,但可能很容易产生噪音事件数据,因此在用户户外时效果最佳。

Android 现在也在硬件中支持内置计步传感器:

TYPE_STEP_DETECTOR
每当用户迈步时,此传感器就会触发一个事件。每发生一个用户步,此传感器都会传递一个值为 1.0 的事件和一个指示该步伐发生时间的事件。
TYPE_STEP_COUNTER
该传感器还会在检测到每个步数时触发一个事件,但会传递自应用首次注册该传感器以来累计的总步数。

请注意,这两个计步传感器提供的结果并非总是一样。与来自 TYPE_STEP_DETECTOR 的事件相比,TYPE_STEP_COUNTER 事件的发生延迟时间更长,但这是因为 TYPE_STEP_COUNTER 算法会进行更多处理以消除假正例。因此,TYPE_STEP_COUNTER 传递事件的速度可能较慢,但其结果应该会更准确。

这两种步测传感器都依赖于硬件(Nexus 5 是首款支持它们的设备),因此您应使用 FEATURE_SENSOR_STEP_DETECTORFEATURE_SENSOR_STEP_COUNTER 常量检查 hasSystemFeature() 的可用性。

批处理传感器事件

为了更好地管理设备电源,SensorManager API 现在允许您指定您希望系统向应用传输批量传感器事件的频率。这不会减少给定时间段内应用可用的实际传感器事件数量,而是会降低系统通过传感器更新调用 SensorEventListener 的频率。也就是说,系统会将一段时间内发生的所有事件保存起来,然后一次性将它们传输到您的应用,而不是在每个事件发生时将其传输到您的应用。

为了提供批处理功能,SensorManager 类添加了 registerListener() 方法的两个新版本,您可以使用这两个方法指定“最大报告延迟”。这个新参数指定了您的 SensorEventListener 可容忍新传感器事件的最大延迟。例如,如果指定一分钟的批量延迟时间,系统将连续调用 onSensorChanged() 方法(针对批量处理的每个事件一次),以不超过一分钟的间隔传递最近的批量事件集。传感器事件的延迟时间绝不会超过最大报告延迟时间值,但如果其他应用针对相同的传感器请求了较短的延迟时间,则事件可能会较快到达。

但请注意,仅当 CPU 处于唤醒状态时,传感器才会根据报告延迟时间向应用传送批处理事件。虽然支持批处理的硬件传感器在 CPU 处于休眠状态时会继续收集传感器事件,但它不会唤醒 CPU 来向应用传递批处理事件。当传感器最终耗尽事件的内存时,它将开始删除最早的事件以保存最新的事件。您可以在传感器填满内存之前唤醒设备,然后调用 flush() 来捕获最新批次的事件,从而避免丢失事件。如需估算内存已满且应该刷新的时间,请调用 getFifoMaxEventCount() 以获取它可以保存的最大传感器事件数,然后将该数字除以应用处理每个事件的速率。使用该计算值可以通过 AlarmManager 设置唤醒闹钟,后者会调用您的 Service(用于实现 SensorEventListener)来刷新传感器。

注意:并非所有设备都支持批处理传感器事件,因为这需要硬件传感器的支持。不过,从 Android 4.4 开始,您应始终使用新的 registerListener() 方法,因为如果设备不支持批处理,系统会妥善忽略批处理延迟时间参数,并实时传递传感器事件。

控制器身份

Android 现在使用唯一整数识别每个已连接的控制器,您可以使用 getControllerNumber() 查询该整数,以便您更轻松地将每个控制器与游戏中的不同玩家相关联。每个控制器的编号可能会因用户断开连接、连接或重新配置控制器而发生变化,因此您应通过注册 InputManager.InputDeviceListener 实例来跟踪每个输入设备所对应的控制器编号。然后,当发生更改时,为每个 InputDevice 调用 getControllerNumber()

已连接的设备现在还提供产品和供应商 ID,这些 ID 可通过 getProductId()getVendorId() 获取。如果您需要根据设备上的可用按键集修改按键映射,可以查询设备,以检查 hasKeys(int...) 中是否有某些按键。

界面

沉浸式全屏模式

为了提供填充整个屏幕的布局,setSystemUiVisibility() 的新 SYSTEM_UI_FLAG_IMMERSIVE 标志(与 SYSTEM_UI_FLAG_HIDE_NAVIGATION 结合使用时)会启用新的沉浸模式。在启用沉浸式全屏模式后,您的 activity 会继续接收所有触摸事件。用户可以沿着系统栏的正常显示区域向内滑动,以显示系统栏。这会清除 SYSTEM_UI_FLAG_HIDE_NAVIGATION 标志(以及 SYSTEM_UI_FLAG_FULLSCREEN 标志,如果应用),使系统栏保持可见状态。不过,如果您希望系统栏在片刻后再次隐藏,可以改用 SYSTEM_UI_FLAG_IMMERSIVE_STICKY 标记。

透明系统状态栏

现在,您可以使用新主题 Theme.Holo.NoActionBar.TranslucentDecorTheme.Holo.Light.NoActionBar.TranslucentDecor 将系统栏设置为部分透明。启用半透明系统栏后,您的布局将填充系统栏后面的区域,因此您还必须为不应被系统栏覆盖的布局部分启用 fitsSystemWindows

如果您要创建自定义主题,请将其中一个主题设置为父主题,或在主题中添加 windowTranslucentNavigationwindowTranslucentStatus 样式属性。

增强的通知侦听器

Android 4.3 添加了 NotificationListenerService API,使应用能够在系统发布新通知时接收有关这些通知的信息。在 Android 4.4 中,通知监听器可以检索通知的其他元数据,并完成有关通知操作的详细信息:

新的 Notification.extras 字段包含一个 Bundle,用于为通知构建器提供其他元数据,例如 EXTRA_TITLEEXTRA_PICTURE。新的 Notification.Action 类定义了附加到通知的操作的特性,您可以从新的 actions 字段中检索这些特性。

可绘制的 RTL 布局镜像

在以前的 Android 版本中,如果应用包含的图片在从右到左布局时水平方向应反转,那么您必须将镜像图片添加到 drawables-ldrtl/ 资源目录中。现在,系统可以通过对可绘制资源启用 autoMirrored 属性或通过调用 setAutoMirrored() 自动为您镜像图片。启用后,当布局方向为从右到左时,系统会自动镜像 Drawable

无障碍

现在,借助 View 类,您可以为使用新文本内容动态更新的界面部分声明“实时区域”,方法是将新的 accessibilityLiveRegion 属性添加到 XML 布局或调用 setAccessibilityLiveRegion()。例如,应将带有显示“密码不正确”通知的文本字段的登录屏幕标记为动态区域,以便屏幕阅读器在消息发生变化时读出消息。

提供无障碍服务的应用现在也可以使用 AccessibilityNodeInfo.CollectionInfoAccessibilityNodeInfo.CollectionItemInfo 提供与列表视图或网格视图等视图集合相关的信息的新 API,从而增强其功能。

应用权限

您的应用必须使用 <uses-permission> 标记请求以下新权限,才能使用某些新 API:

INSTALL_SHORTCUT
允许应用在启动器中安装快捷方式
UNINSTALL_SHORTCUT
允许应用卸载启动器中的快捷方式
TRANSMIT_IR
允许应用使用设备的 IR 发射器(如果有)

注意:从 Android 4.4 开始,当您想要使用 getExternalFilesDir() 等方法访问应用专属的外部存储空间区域时,平台不再要求应用获取 WRITE_EXTERNAL_STORAGEREAD_EXTERNAL_STORAGE。但是,如果您要访问由 getExternalStoragePublicDirectory() 提供的外部存储空间的可共享区域,则仍需要这些权限。

设备功能

以下是您可以使用 <uses-feature> 标记声明的新设备功能,以声明应用要求并在 Google Play 上启用过滤功能或在运行时检查应用要求:

FEATURE_CONSUMER_IR
设备能够与消费类 IR 设备通信。
FEATURE_DEVICE_ADMIN
设备支持通过设备管理器强制执行设备政策。
FEATURE_NFC_HOST_CARD_EMULATION
设备支持基于主机的 NFC 卡模拟。
FEATURE_SENSOR_STEP_COUNTER
设备包含一个硬件计步器。
FEATURE_SENSOR_STEP_DETECTOR
设备包含硬件步测器。

如需详细了解 Android 4.4 中的所有 API 变更,请参阅 API 差异报告