API 级别:19
Android 4.4 (KITKAT
) 是 Android 平台的新版本,为用户和应用开发者提供了新功能。本文旨在介绍其中最值得关注的新 API。
作为应用开发者,您应该尽快从 SDK 管理器下载 Android 4.4 系统映像和 SDK 平台。如果您没有运行 Android 4.4 的设备来测试应用,请使用 Android 4.4 系统映像在 Android 模拟器上测试您的应用。然后,针对 Android 4.4 平台构建您的应用,以开始使用最新的 API。
更新目标 API 级别
为了更好地针对搭载 Android 4.4 的设备优化您的应用,您应将 targetSdkVersion
设置为 "19"
,将其安装在 Android 4.4 系统映像上并进行测试,然后发布包含此变更的更新。
您可以使用 Android 4.4 中的 API,同时支持较低版本,方法是在代码中添加条件,在执行您的 minSdkVersion
不支持的 API 之前检查系统 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 小时,则您的同步操作每天可能会在大约一小时的时间窗口内发生,而不是在确切地同一时间发生。
如需为同步操作指定您自己的灵活间隔,您应该开始使用新的 requestSync()
方法。如需了解详情,请参阅以下有关同步适配器的部分。
这种 Flex 间隔行为仅适用于更新后的应用。如果您已将 targetSdkVersion
设为“18”或更低版本,那么在 Android 4.4 上运行时,现有同步请求的行为将继续与以前版本上一样。
打印框架
Android 现在包含一个完整的框架,允许用户使用通过 Wi-Fi、蓝牙或其他服务连接的打印机打印任何文档。系统会处理想要打印文档的应用和向打印机传送打印作业的服务之间的事务。android.print
框架提供了指定打印文档并将其发送到系统进行打印所需的所有 API。对于给定的打印作业,您实际需要哪个 API 取决于您的内容。
打印通用内容
如果要将界面中的内容作为文档输出,您需要先创建 PrintDocumentAdapter
的子类。在此类中,您必须实现几个回调方法,包括用于根据提供的打印属性建立布局的 onLayout()
,以及用于将可打印内容序列化为 ParcelFileDescriptor
的 onWrite()
。
为了将您的内容写入 ParcelFileDescriptor
,您必须向其传递一个 PDF 文件。新的 PdfDocument
API 通过提供来自 getCanvas()
的 Canvas
(您可以在其中绘制可打印内容),提供了一种便捷的方式。然后使用 writeTo()
方法将 PdfDocument
写入 ParcelFileDescriptor
。
定义 PrintDocumentAdapter
的实现后,您可以根据用户请求,使用 print()
方法执行打印作业,该方法将 PrintDocumentAdapter
作为其参数之一。PrintManager
打印图像
如果您只想打印照片或其他位图,那么支持库中的帮助程序 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()
查询设备支持的红外线频率,并使用 transmit()
传递所需的频率和信号模式来传输信号。
请务必先通过调用 hasIrEmitter()
来检查设备是否包含红外线发射器,但如果您的应用仅与具有红外线发射器的设备兼容,则应在清单中为 "android.hardware.consumerir"
(FEATURE_CONSUMER_IR
) 添加一个 <uses-feature>
元素。
多媒体
自适应播放
现在,MediaCodec
API 支持自适应视频播放。该 API 支持在 Surface
上播放期间无缝更改分辨率。您可以为解码器输入帧馈送新分辨率,输出缓冲区的分辨率不会出现明显的差距。
您可以向 MediaFormat
添加 KEY_MAX_WIDTH
和 KEY_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
,并使用 MediaPlayer
或 MediaCodec
等提供方传送图片数据。如需在 Surface 提供新图片时收到通知,请实现 ImageReader.OnImageAvailableListener
接口并向 setOnImageAvailableListener()
注册该接口。
现在,当您将内容绘制到 Surface
时,每当有新的图片帧可用时,您的 ImageReader.OnImageAvailableListener
都会收到对 onImageAvailable()
的调用,并为您提供相应的 ImageReader
。您可以使用 ImageReader
通过调用 acquireLatestImage()
或 acquireNextImage()
获取帧的图片数据作为 Image
对象。
Image
对象可让您直接访问 ByteBuffer
中图片的时间戳、格式、尺寸和像素数据。不过,为了让 Image
类解读您的图片,必须根据 ImageFormat
或 PixelFormat
中的常量定义的任一类型设置图片的格式。
峰值和有效值 (RMS) 测量
您现在可以通过创建 Visualizer.MeasurementPeakRms
的新实例并将其传递给 getMeasurementPeakRms()
,从 Visualizer
查询当前音频流的峰值和 RMS。当您调用此方法时,给定 Visualizer.MeasurementPeakRms
的峰值和 RMS 值将设置为最新的测量值。
音量增强器
LoudnessEnhancer
是 AudioEffect
的新子类,可让您调高 MediaPlayer
或 AudioTrack
的音量。此方法在与上面提到的新 getMeasurementPeakRms()
方法结合使用时尤为有用,可以在其他媒体正在播放时提高语音音轨的音量。
遥控器
Android 4.0(API 级别 14)引入了 RemoteControlClient
API,可让媒体应用使用来自远程客户端的媒体控制器事件,例如锁定屏幕上的媒体控件。现在,您可以利用新的 RemoteController
API 构建自己的遥控器,从而打造创新型新应用和外围设备,以便控制与 RemoteControlClient
集成的任何媒体应用的播放。
如需构建遥控器,您可以随意实现界面,但要向用户的媒体应用传递媒体按钮事件,您必须创建一个扩展 NotificationListenerService
类并实现 RemoteController.OnClientUpdateListener
接口的服务。以 NotificationListenerService
为基础非常重要,因为它提供了适当的隐私权限制,要求用户在系统安全设置中启用您的应用作为通知监听器。
NotificationListenerService
类包含几个您必须实现的抽象方法,但如果您仅关注用于处理媒体播放的媒体控制器事件,可以将这些实现留空,而改为专注于 RemoteController.OnClientUpdateListener
方法。
从遥控器进行评分
Android 4.4 基于遥控器客户端(通过 RemoteControlClient
接收媒体控制事件的应用)的现有功能,添加了用户通过遥控器为当前曲目评分的功能。
新的 Rating
类可封装有关用户评分的信息。评分由其评分样式(RATING_HEART
、RATING_THUMB_UP_DOWN
、RATING_3_STARS
、RATING_4_STARS
、RATING_5_STARS
或 RATING_PERCENTAGE
)和适合该样式的评分值来定义。
要允许用户从遥控器对您的曲目进行评分:
- 通过在
setTransportControlFlags()
中添加FLAG_KEY_MEDIA_RATING
标志,表明您希望向用户公开评分界面(如果适用)。 - 调用
editMetadata()
以检索RemoteControlClient.MetadataEditor
,并通过addEditableKey()
向其传递RATING_KEY_BY_USER
。 - 然后,调用
putObject()
并向其传递RATING_KEY_BY_USER
作为键,传递上述一种评分样式作为值,以指定评分样式。
如需在用户从遥控器更改评分时接收回调,请实现新的 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,可为界面的不同状态之间创建动画效果。一项关键功能是让您能够通过为每种状态创建单独的布局来定义界面的不同状态(称为“场景”)。如果您想在场景之间添加动画效果,请执行“转场”,它会计算将布局从当前场景更改为下一个场景所需的动画。
要在两个场景间进行转场,您通常需要执行以下操作:
- 指定包含您要更改的界面组件的
ViewGroup
。 - 指定表示变更的最终结果的布局(下一个场景)。
- 指定应添加布局变更动画的转场类型。
- 执行转场。
您可以使用 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
的子类(例如 Fade
和 ChangeBounds
)定义的多个预定义类型。如果您未指定转场类型,系统会默认使用 AutoTransition
,它会根据需要自动淡出、移动和调整视图大小。此外,您还可以通过扩展其中任何类来创建自定义转场,以执行您所需的动画。自定义过渡可以跟踪您想要跟踪的任何属性更改,并根据这些更改创建所需的动画。例如,您可以提供 Transition
的子类,用于监听对视图“旋转”属性所做的更改,然后以动画方式呈现任何更改。
如需了解详情,请参阅 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()
- 此方法必须使用
DocumentsContract.Root
中定义的列返回一个Cursor
,用于描述文档存储空间的所有根目录。 queryChildDocuments()
- 此方法必须使用
DocumentsContract.Document
中定义的列返回一个描述指定目录中所有文件的Cursor
。 queryDocument()
- 此方法必须使用
DocumentsContract.Document
中定义的列返回描述指定文件的Cursor
。 openDocument()
- 此方法必须返回表示指定文件的
ParcelFileDescriptor
。用户选择文件且客户端应用通过调用openFileDescriptor()
请求对该文件的访问权限后,系统便会调用此方法。
如需了解详情,请参阅存储访问框架指南。
外部存储空间访问
现在,您可以在辅助外部存储媒介上读取和写入应用专属文件,例如当设备提供模拟存储和 SD 卡时。新方法 getExternalFilesDirs()
的工作方式与现有 getExternalFilesDir()
方法相同,只不过它会返回一个 File
对象数组。在读取或写入此方法返回的任何路径之前,请将 File
对象传递给新的 getStorageState()
方法,以验证存储空间当前是否可用。
访问应用专用缓存目录和 OBB 目录的其他方法现在也具有相应的版本来提供辅助存储设备的访问权限:分别为 getExternalCacheDirs()
和 getObbDirs()
。
返回的 File
数组中的第一个条目被视为设备的主外部存储空间,与 getExternalFilesDir()
等现有方法返回的 File
相同。
注意:从 Android 4.4 开始,当应用使用上述方法仅访问应用专属区域时,Android 平台不再要求应用获取 WRITE_EXTERNAL_STORAGE
或 READ_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_DETECTOR
和 FEATURE_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(可从 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.TranslucentDecor
和 Theme.Holo.Light.NoActionBar.TranslucentDecor
将系统栏设置为部分透明。启用半透明系统栏后,您的布局将填充系统栏后面的区域,因此您还必须为不应被系统栏覆盖的布局部分启用 fitsSystemWindows
。
如果您要创建自定义主题,请将其中一个主题设为父主题,或在主题中添加 windowTranslucentNavigation
和 windowTranslucentStatus
样式属性。
增强的通知侦听器
Android 4.3 添加了 NotificationListenerService
API,让应用能够在系统发布新通知时接收有关它们的信息。在 Android 4.4 中,通知监听器可以检索通知的其他元数据,并填写有关通知操作的详细信息:
新的 Notification.extras
字段包含一个 Bundle
,用于为您的通知构建器提供附加元数据,例如 EXTRA_TITLE
和 EXTRA_PICTURE
。新的 Notification.Action
类定义了附加到通知的操作的特性,您可以从新的 actions
字段中检索这些特性。
可绘制的 RTL 布局镜像
在以前的 Android 版本中,如果您的应用包含应逆向从右到左布局的水平方向的图片,您必须在 drawables-ldrtl/
资源目录中添加镜像图片。现在,通过在可绘制资源上启用 autoMirrored
属性或调用 setAutoMirrored()
,系统可以自动为您镜像图片。启用后,当布局方向为从右到左时,系统会自动镜像 Drawable
。
无障碍功能
View
类现在允许您通过向 XML 布局添加新的 accessibilityLiveRegion
属性或调用 setAccessibilityLiveRegion()
,为界面中会动态更新为新文本内容的部分声明“实时区域”。例如,应将包含显示“密码不正确”通知的文本字段的登录屏幕标记为实时区域,以便屏幕阅读器在消息发生变化时读出消息。
提供无障碍服务的应用现在也可以使用 AccessibilityNodeInfo.CollectionInfo
和 AccessibilityNodeInfo.CollectionItemInfo
提供有关视图集合(例如列表视图或网格视图)的信息的新 API,从而增强其功能。
应用权限
您的应用必须使用 <uses-permission>
标记请求以下新权限,才能使用特定的新 API:
INSTALL_SHORTCUT
- 允许应用在启动器中安装快捷方式
UNINSTALL_SHORTCUT
- 允许应用在启动器中卸载快捷方式
TRANSMIT_IR
- 允许应用使用设备的红外线发射器(如果有)
注意:从 Android 4.4 开始,当您想使用 getExternalFilesDir()
等方法访问应用专属的外部存储空间区域时,平台不再要求应用获取 WRITE_EXTERNAL_STORAGE
或 READ_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 差异报告。