重要的行为变更
如果您之前发布过 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()
创建同步将在默认的 Flex 间隔内(在您指定期间的 4% 左右)执行您的同步操作。例如,如果您的轮询频率是 24 小时,则您的同步操作每天可能会在大约一小时的时间窗口内发生,而不是在确切地同一时间发生。
要指定您自己的 Flex 间隔进行同步操作,您应开始使用新的 requestSync()
方法。如需了解更多详情,请参阅下面的同步适配器部分。
这个 Flex 间隔行为仅适用于更新后的应用。如果您已将 targetSdkVersion
设置为“18”或更低版本,那么在 Android 4.4 上运行时,您的现有同步请求的行为方式和在以前版本上一样。
打印框架
现在,Android 包含一个完整框架,允许用户使用通过 WLAN、蓝牙或其他服务连接的打印机打印任何文档。系统在需要打印文档的应用和向打印机传输打印作业的服务之间处理此事务。android.print
框架提供指定打印文档并将其传输到系统进行打印所需要的所有 API。对于给定的打印作业,您实际需要哪个 API 取决于您的内容。
打印通用内容
如果您要从 UI 将内容打印为文档,首先,您需要创建一个 PrintDocumentAdapter
的子类。在此类中,您必须实现几个回调方法,包括 onLayout()
和 onWrite()
,前者是为了基于提供的打印属性建立布局,后者是为了将可打印内容序列化为一个 ParcelFileDescriptor
。
为了将您的内容写入 ParcelFileDescriptor
,您必须向其传递一个 PDF。新的 PdfDocument
API 简化了此操作,它提供来自 getCanvas()
的 Canvas
,您可以在上面绘制可打印内容。然后,使用 writeTo()
方法将 PdfDocument
写入 ParcelFileDescriptor
。
在针对 PrintDocumentAdapter
定义您的实现后,您可以根据用户请求使用 PrintManager
方法 print()
执行打印作业,该方法将 PrintDocumentAdapter
作为它的一个参数。
打印图像
如果您只想打印照片或其他位图,则支持库中的帮助程序 API 可以为您完成所有工作。只需创建一个新的 PrintHelper
实例,使用 setScaleMode()
设置缩放模式,然后将您的 Bitmap
传递到 printBitmap()
。就这么简单。支持库将处理与系统进行的所有剩余交互,以将位图传输到打印机。
构建打印服务
作为打印机原始设备制造商,您可以通过 Android 设备使用 android.printservice
框架为您的打印机提供互操作性,您可以以 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 限制为在前台时仅读取 Activity 感兴趣的标记类型。您可以使用 enableReaderMode()
为您的 Activity 启用读取器模式,提供一个 NfcAdapter.ReaderCallback
的实现,用于在检测到新的标记时接收回调。
这个新功能与主机卡模拟结合使用,将允许 Android 同时在移动支付接口的两端运行:一个设备作为支付终端运行(运行读取器模式 Activity 的设备),另一个设备作为支付客户端运行(模拟 NFC 卡的设备)。
红外线发射器
现在,在附带红外线 (IR) 发射器的设备上运行时,您可以使用 ConsumerIrManager
API 发射红外线信号。要获取 ConsumerIrManager
的实例,请使用 CONSUMER_IR_SERVICE
调用 getSystemService()
作为参数。然后,您可以使用 getCarrierFrequencies()
查询设备支持的红外线频率,并通过使用 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)
来验证设备是否支持自适应播放。
注:是否支持自适应播放因供应商而异。某些编解码器可能需要更多内存来实现较大的分辨率 hint。因此,您应基于您正在解码的源材料设置分辨率最大值。
音频点播时间戳
为促进音频视频同步,新的 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
。通过调用 acquireLatestImage()
或 acquireNextImage()
,您可以使用 ImageReader
获取帧的图像数据作为 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
标记指示系统您想要向用户公开评分 UI(如果适用)。 - 调用
editMetadata()
以检索RemoteControlClient.MetadataEditor
,并使用addEditableKey()
向其传递RATING_KEY_BY_USER
。 - 然后,指定评分样式,方法是调用
putObject()
并向其传递RATING_KEY_BY_USER
作为密钥,同时向其传递上述某个评分样式作为值。
要在用户从遥控器更改评分时接收回调,则实现新的 RemoteControlClient.OnMetadataUpdateListener
接口,并向 setMetadataUpdateListener()
传递一个实例。当用户更改评分时,您的 RemoteControlClient.OnMetadataUpdateListener
将收到一个对 onMetadataUpdate()
的调用,传递 RATING_KEY_BY_USER
作为密钥,同时传递一个 Rating
对象作为值。
隐藏式字幕
现在,播放 HTTP Live Stream (HLS) 视频时,VideoView
支持 WebVTT 字幕跟踪,根据用户在系统设置中定义的隐藏式字幕首选项显示字幕跟踪。
您也可以使用 addSubtitleSource()
方法为 VideoView
提供 WebVTT 字幕跟踪。此方法接受一个 InputStream
,其携带字幕数据和指定该字幕数据格式的 MediaFormat
对象,您可以使用 createSubtitleFormat()
指定该对象。这些字幕也会按照用户的首选项显示在视频上。
如果您不使用 VideoView
显示您的视频内容,则应尽可能使您的字幕叠加层与用户的隐藏式字幕首选项匹配。新的 CaptioningManager
API 允许您查询用户的隐藏式字幕首选项,包括 CaptioningManager.CaptionStyle
定义的样式,如字体和颜色。如果用户在视频已开始后调整部分首选项,您应侦听首选项的变化,方法是注册一个 CaptioningManager.CaptioningChangeListener
实例以在任意首选项发生变化时接收回调,然后根据需要更新您的字幕。
动画和图形
场景和转场
新的 android.transition
框架提供有诸多 API,可为在不同用户界面状态之间创建动画提供便利。一个关键的功能是让您能够通过为每个状态创建单独的布局,定义不同的 UI 状态,称为“场景”。当您需要制作从一个场景到另一个场景的动画时,可执行“转场”,其计算更改从当前场景到下一场景的布局所需的动画。
要在两个场景间进行转场,您通常需要执行以下操作:
- 指定包含您要更改的 UI 组件的
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
操作,其允许用户选择特定类型的文件并授予应用对该文件的长期读取权限(可能也授予写入权限),无需向您的应用导入此文件。
如果您要开发为文件提供存储服务(如云保存服务)的应用,可以加入这个统一的 UI,通过实现一个内容提供程序作为新 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_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,这些 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()
,为使用新增文本内容动态更新的 UI 部分声明“实时区域”。例如,应将带有显示“密码错误”通知的文本字段的登录屏幕标记为一个实时区域,以便当它发生变化时,屏幕阅读器可以复述此消息。
现在,提供无障碍服务的应用还可以利用新 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
此设备附带硬件步测器。