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 小时,则您的同步操作每天可能会在大约一小时的时间窗口内发生,而不是在确切地同一时间发生。
如需为同步操作指定自己的 flex 间隔时间,您应开始使用新的 requestSync()
方法。如需了解详情,请参阅下面的同步适配器部分。
这种 flex 间隔时间行为仅适用于更新后的应用。如果您将 targetSdkVersion
设置为“18”或更低版本,则在 Android 4.4 上运行时,现有同步请求将继续像在之前的版本中一样运行。
打印框架
Android 现在包含一个完整的框架,让用户可以使用通过 Wi-Fi、蓝牙或其他服务连接的打印机打印任何文档。系统会处理想要打印文档的应用与将打印作业传送到打印机的服务之间的事务。android.print
框架提供了指定打印文档并将其提交给系统进行打印所需的所有 API。对于给定的打印作业,您实际需要哪个 API 取决于您的内容。
打印通用内容
如果您想将界面中的内容作为文档打印,则需要先创建 PrintDocumentAdapter
的子类。在此类中,您必须实现一些回调方法,包括 onLayout()
(用于根据提供的打印属性建立布局)和 onWrite()
(用于将可打印内容序列化为 ParcelFileDescriptor
)。
如需将内容写入 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
广播(这是一种不可中止的广播,可能会传送给多个应用)来接收新短信的通知。此广播主要用于那些没有被选为默认短信应用、但需要读取特殊传入消息(例如进行手机号码验证)的应用。
如需了解详情,请参阅博文 Preparing SMS Apps for 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 传输红外信号。如需获取 ConsumerIrManager
的实例,请使用 CONSUMER_IR_SERVICE
作为实参调用 getSystemService()
。然后,您可以使用 getCarrierFrequencies()
查询设备支持的 IR 频率,并使用 transmit()
传递所需的频率和信号模式来传输信号。
您应始终先通过调用 hasIrEmitter()
检查设备是否包含红外发射器,但如果您的应用仅与具有红外发射器的设备兼容,则应在清单中为 "android.hardware.consumerir"
(FEATURE_CONSUMER_IR
) 添加 <uses-feature>
元素。
多媒体
自适应播放
MediaCodec
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
操作,该操作允许用户选择特定类型的文件,并向您的应用授予对该文件的长期读取权限(可能还有写入权限),而无需将该文件导入到您的应用。
如果您正在开发提供文件存储服务(例如云端存档服务)的应用,则可以通过将内容提供程序实现为新 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 开始,如果您只需使用上述方法访问外部存储空间中的应用专用区域,平台不再要求您的应用获取 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_COUNTER
事件的延迟时间比 TYPE_STEP_DETECTOR
事件的延迟时间更长,但这是因为 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()
。
现在,已连接的设备还提供可从 getProductId()
和 getVendorId()
获取的产品和供应商 ID。如果您需要根据设备上可用的按键集修改按键映射,可以使用 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
会自动镜像。
无障碍
现在,您可以通过向 XML 布局添加新的 accessibilityLiveRegion
属性或调用 setAccessibilityLiveRegion()
,为界面中会使用新文本内容动态更新的部分声明“实时区域”。View
例如,如果登录界面中有一个文本字段显示“密码不正确”通知,则应将该文本字段标记为动态区域,以便屏幕阅读器在消息发生变化时朗读该消息。
提供无障碍服务的应用现在还可以使用新的 API 增强其功能,这些 API 使用 AccessibilityNodeInfo.CollectionInfo
和 AccessibilityNodeInfo.CollectionItemInfo
提供有关列表或网格视图等视图集合的信息。
应用权限
您的应用必须使用 <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
- 设备能够与消费类红外线设备通信。
FEATURE_DEVICE_ADMIN
- 设备支持通过设备管理员强制执行设备政策。
FEATURE_NFC_HOST_CARD_EMULATION
- 设备支持基于主机的 NFC 卡模拟。
FEATURE_SENSOR_STEP_COUNTER
- 设备包含硬件计步器。
FEATURE_SENSOR_STEP_DETECTOR
- 设备包含硬件步测器。
如需详细了解 Android 4.4 中的所有 API 变更,请参阅 API 差异报告。