Android 8.0(API 级别 26)为用户和开发者引入了各种新特性和功能。本文重点介绍了面向开发者的新变化。
请务必查看 Android 8.0 行为变更,了解平台变更可能会在哪些方面影响您的应用。
用户体验
画中画模式
Android 8.0 中的画中画功能。
Android 8.0(API 级别 26)允许以画中画 (PIP) 模式启动 activity。画中画是一种特殊的多窗口模式,最常用于视频播放。画中画模式最初仅适用于 Android TV;Android 8.0 将该功能提供给其他 Android 设备使用。
当某个 activity 处于画中画模式时,它会处于暂停状态,但应继续显示内容。因此,您应确保您的应用不会在其 onPause()
处理程序中暂停播放。您应在 onStop()
中暂停视频,在 onStart()
中继续播放。如需了解详情,请参阅多窗口生命周期。
如需指定您的 activity 可以使用画中画模式,请在清单中将 android:supportsPictureInPicture
设为 true。(从 Android 8.0 开始,画中画不需要 android:resizeableActivity
清单属性。不过,如果 activity 支持其他多窗口模式,则必须将 android:resizeableActivity
设为“true”。)
Android 8.0(API 级别 26)引入了一个新对象 PictureInPictureParams
,您可以将该对象传递给画中画方法,以指定 activity 在画中画模式下的行为方式。此对象可指定 activity 的首选宽高比等属性。
添加画中画中介绍的现有画中画方法现在可用于所有 Android 设备,而不仅仅是 Android TV。此外,Android 8.0 还提供了以下方法来支持画中画模式:
Activity.enterPictureInPictureMode(PictureInPictureParams args)
:将 activity 置于画中画模式。activity 的宽高比和其他配置设置由 args 指定。如果 args 中的任何字段为空,系统将使用您上次调用Activity.setPictureInPictureParams()
时设置的值。指定的 activity 位于屏幕的一角;屏幕的其余部分填充屏幕上的上一个 activity。进入画中画模式的 activity 会进入暂停状态,但仍处于启动状态。如果用户点按画中画 activity,系统会显示一个菜单供用户与之互动;在 activity 处于画中画状态时,系统不会触发任何触摸事件。
-
Activity.setPictureInPictureParams()
:更新 activity 的画中画配置设置。如果 activity 当前处于画中画模式,则系统会更新设置;如果 activity 的宽高比发生变化,这非常有用。如果 activity 未处于画中画模式,那么无论您调用什么enterPictureInPictureMode()
方法,系统都会使用这些配置设置。
通知
在 Android 8.0(API 级别 26)中,我们重新设计了通知,以便提供一种更轻松、更统一的方式来管理通知行为和设置。这些更改包括:
- 通知渠道:Android 8.0 引入了通知渠道,可让您为要显示的每种通知类型创建一个可由用户自定义的渠道。界面将通知渠道称为通知类别。如需了解如何实现通知渠道,请参阅管理通知渠道。
- 通知圆点:Android 8.0 引入了对在应用启动器图标上显示圆点或标记的支持。通知圆点反映是否存在用户尚未关闭或操作的通知。 如需了解如何使用通知圆点,请参阅通知标记。
- 延后:用户可以暂停通知,这会导致通知在一段时间后会重新出现。通知重新出现时,其重要性级别与首次显示时相同。应用可以移除或更新已延后的通知,但更新已延后的通知不会导致它重新显示。
- 通知超时:您可以在创建通知时使用
setTimeoutAfter()
设置超时。 您可以使用此方法指定一个时长,超过该时长后,通知应取消。如果需要,您可以在指定的超时持续时间过去之前取消通知。 - 通知设置:您可以调用
setSettingsText()
,设置使用Notification.INTENT_CATEGORY_NOTIFICATION_PREFERENCES
intent 从通知创建指向应用通知设置的链接时显示的文本。系统可能会提供以下 extra 以及 intent,以过滤您的应用必须向用户显示的设置:EXTRA_CHANNEL_ID
、NOTIFICATION_TAG
和NOTIFICATION_ID
。 - 通知关闭:用户可以自行关闭通知,应用也可以以编程方式移除通知。您可以通过实现
NotificationListenerService
类中的onNotificationRemoved()
方法来确定通知何时关闭及其原因。 - 背景颜色:您可以为通知设置和启用背景颜色。您应仅在针对持续性任务的通知中使用此功能,此类任务对用户一眼即可看清。例如,您可以为与行车路线或正在进行的通话相关的通知设置背景颜色。您还可以使用
setColor()
设置所需的背景颜色。这样,您就可以使用setColorized()
为通知启用背景颜色。 - 消息样式:在 Android 8.0 中,使用
MessagingStyle
类的通知会在其收起形式中显示更多内容。对于与消息相关的通知,您应使用MessagingStyle
类。您还可以使用addHistoricMessage()
方法,通过向与消息相关的通知添加历史消息为对话提供上下文。
![Android 8.0(API 级别 26)中的通知长按菜单。](https://developer.android.google.cn/static/images/about/versions/oreo/notification-long-press.png?authuser=5&hl=th)
在 Android 8.0 中,用户可以长按应用启动器图标来查看通知。
自动填充框架
帐号创建、登录和信用卡交易需要时间并且容易出错。对于需要执行这些重复性任务的应用,用户很容易感到失望。
Android 8.0(API 级别 26)引入了自动填充框架,可让您更轻松地填写表单(例如登录表单和信用卡表单)。用户选择启用自动填充功能后,现有应用和新应用都可以使用自动填充框架。
您可以采取一些措施来优化应用与该框架的协作方式。如需了解详情,请参阅自动填充框架概览。
可下载字体
借助 Android 8.0(API 级别 26)和 Android 支持库 26,您可以从提供程序应用请求字体,而不是将字体捆绑到 APK 中或让 APK 下载字体。此功能可缩减 APK 大小,提高应用安装成功率,并允许多个应用共用同一种字体。
如需详细了解如何下载字体,请参阅可下载字体。
XML 中的字体
Android 8.0(API 级别 26)引入了“XML 中的字体”这项新功能,可让您将字体用作资源。这意味着,不需要将字体捆绑为资源。字体在 R
文件中编译,在系统中可自动作为资源使用。然后,您可以借助新的资源类型 font
访问这些字体。
支持库 26 在搭载 API 版本 14 及更高版本的设备上为此功能提供全面支持。
如需详细了解如何以资源形式使用字体,以及如何检索系统字体,请参阅 XML 中的字体。
自动调整 TextView 的大小
Android 8.0(API 级别 26)允许您根据 TextView 的大小自动设置文本展开或收缩的大小。这意味着,在不同屏幕上优化文本大小或者优化包含动态内容的文本大小要容易得多。如需详细了解如何在 Android 8.0 中自动调整 TextView 的大小,请参阅自动调整 TextView 的大小。
自适应图标
Android 8.0(API 级别 26)引入了自适应启动器图标。自适应图标支持视觉效果,并且可以在不同设备型号上显示各种形状。如需了解如何创建自适应图标,请参阅自适应图标指南。
颜色管理
图像应用的 Android 开发者现在可以利用具有广色域彩色显示屏的新设备。如需显示广色域图片,应用需要在其清单中(针对每个 activity)启用一个标志,并使用嵌入式广色域配置文件(AdobeRGB、Pro Photo RGB、DCI-P3 等)加载位图。
WebView API
Android 8.0 提供了几个 API 来帮助您管理在应用中显示 Web 内容的 WebView
对象。这些 API 有助于提高应用的稳定性和安全性,其中包括:
- Version API
- Google SafeBrowsing API
- Termination Handle API
- Renderer Importance API
如需详细了解如何使用这些 API,请参阅管理 WebView。
WebView
类现在包含 Safe Browsing API,以增强网络浏览的安全性。如需了解详情,请参阅 Google Safe Browsing API。
固定快捷方式和微件
Android 8.0(API 级别 26)引入了应用内固定的快捷方式和 widget。在您的应用中,您可以根据用户权限为受支持的启动器创建固定快捷方式和 widget。
如需了解详情,请参阅固定快捷方式和 widget 功能指南。
最大屏幕纵横比
Android 8.0(API 级别 26)对配置应用的最大宽高比的方式进行了变更。
首先,Android 8.0 引入了 maxAspectRatio 属性,该属性可用于设置应用的最大宽高比。此外,在 Android 8.0 及更高版本中,应用的默认最大宽高比是运行应用的设备的原生宽高比。
如需详细了解如何声明最大宽高比,请参阅支持多种屏幕。
多显示屏支持
从 Android 8.0(API 级别 26)开始,平台增强了对多显示屏的支持。如果 activity 支持多窗口模式,并且在具有多个显示屏的设备上运行,则用户可以将 activity 从一个显示屏移到另一个显示屏。当应用启动 activity 时,它可以指定 activity 应在哪个显示屏上运行。
注意 :如果 activity 支持多窗口模式,则 Android 8.0 会自动为该 activity 启用多显示屏支持。您应测试您的应用,以确保它能够在多显示屏环境中正常运行。
一次只能有一个 activity 处于已恢复状态,即使应用有多个显示屏也是如此。获得焦点的 activity 将处于继续状态;所有其他可见的 activity 均已暂停,但不会停止。如需详细了解当多个 activity 可见时的 activity 生命周期,请参阅多窗口生命周期。
当用户将 activity 从一个显示屏移动到另一个显示屏时,系统会调整 activity 的大小,并根据需要发出运行时更改。activity 可以自行处理配置变更,也可以允许系统销毁包含 activity 的进程,并使用新的尺寸重新创建该 activity。如需了解详情,请参阅处理配置变更。
ActivityOptions
提供了两种新方法来支持多个显示屏:
setLaunchDisplayId()
- 指定 activity 在启动时应显示在哪个显示屏。
getLaunchDisplayId()
- 返回 activity 的当前启动显示画面。
对 adb shell 进行了扩展,以支持多个显示屏。shell start
命令现在可用于启动 activity,并指定 activity 的目标显示屏:
adb shell start <activity_name> --display <display_id>
统一的布局外边距和内边距
Android 8.0(API 级别 26)可让您更轻松地指定 View
元素的对边使用相同的外边距或内边距的情况。具体而言,您现在可以在布局 XML 文件中使用以下属性:
-
layout_marginVertical
,同时定义layout_marginTop
和layout_marginBottom
。 -
layout_marginHorizontal
,同时定义layout_marginLeft
和layout_marginRight
。 -
paddingVertical
,同时定义paddingTop
和paddingBottom
。 -
paddingHorizontal
,同时定义paddingLeft
和paddingRight
。
注意:如果您自定义应用的逻辑以支持不同的语言和文化(包括文本方向),请记住,这些属性不会影响
layout_marginStart
、
layout_marginEnd
、
paddingStart
或
paddingEnd
的值。除了新的垂直和水平布局属性外,您可以自行设置这些值,以创建依赖于文本方向的布局行为。
指针捕获
某些应用(例如游戏、远程桌面和虚拟化客户端)大大受益于对鼠标指针的控制。指针捕获是 Android 8.0(API 级别 26)中的一项新功能,可通过将所有鼠标事件传递到应用中聚焦的视图来提供此类控制。
从 Android 8.0 开始,应用中的 View
可以请求指针捕获并定义监听器来处理捕获的指针事件。在此模式下,鼠标指针会隐藏起来。当不再需要鼠标信息时,视图可以释放指针捕获。系统还可以在视图失去焦点时(例如,当用户打开另一个应用时)释放指针捕获。
如需了解如何在应用中使用此功能,请参阅指针捕获。
应用类别
Android 8.0(API 级别 26)允许每个应用声明其所属的类别(如果适用)。在向用户展示具有类似用途或功能的应用(例如在“流量消耗”“电池用量”或“存储空间用量”)时,系统会将这些类别归为一组。您可以通过在 <application>
清单标记中设置 android:appCategory
属性来为您的应用定义一个类别。
Android TV 启动器
Android 8.0(API 级别 26)提供了以内容为中心的全新 Android TV 主屏幕体验,适用于 Android 8.0 的 Android TV 模拟器和 Nexus Player 设备映像。新的主屏幕按与频道对应的行整理视频内容,每个频道由系统上的应用填充节目。应用可以发布多个频道,用户可以配置他们希望在主屏幕上看到哪些频道。Android TV 主屏幕上还包含“接下来观看”行,该行根据用户的观看习惯填充应用中的节目。应用还可以提供视频预览,视频预览会在用户聚焦于某个节目时自动播放。用于填充频道和节目的 API 属于 TvProvider API,这些 API 作为 Android 8.0 中的 Android 支持库模块分发。
AnimatorSet
从 Android 8.0(API 级别 26)开始,AnimatorSet
API 现在支持寻道和反向播放。借助跳转功能,您可以将动画的位置设置为特定的时间点。如果您的应用包含可撤消的操作的动画,反向播放非常有用。您可以将同一个动画集倒放,而无需定义两个单独的动画集。
输入和导航
键盘导航键区
如果应用中的 activity 使用复杂的视图层次结构(例如图 2 中的视图层次结构),不妨考虑将界面元素组整理成聚类,以便在这些元素之间更轻松地进行键盘导航。用户可以在 Chromebook 设备上按 Meta+Tab 或 Search+Tab,从一个集群导航到另一个集群。聚类的典型示例包括:侧边栏、导航栏、主要内容区域以及可包含多个子元素的元素。
![包含五个导航键区的 activity 示例,用户可以使用键盘导航键区快捷键进行导航。这些聚类按以下方式显示:顶部面板、左侧面板、主内容区域、底部面板和悬浮操作按钮。](https://developer.android.google.cn/static/images/about/versions/oreo/keyboard-navigation-clusters.png?authuser=5&hl=th)
如需将 View
或 ViewGroup
元素设为聚类,请在元素的布局 XML 文件中将
android:keyboardNavigationCluster
属性设置为 true
,或将 true
传递到应用界面逻辑中的 setKeyboardNavigationCluster()
。
注意:集群不能嵌套,但非嵌套集群可能显示在层次结构的不同级别。如果您尝试嵌套聚类,框架只会将最顶部的 ViewGroup
元素视为聚类。
在有触摸屏的设备上,您可以将仪表板指定的 ViewGroup
对象的 android:touchscreenBlocksFocus
元素设置为 true
,以允许从仅限仪表板进入和离开此仪表板导航。如果您将此配置应用于某个仪表板,用户将无法使用 Tab 键或箭头键导航到或离开此仪表板;必须按仪表板导航键盘组合键。
视图默认焦点
在 Android 8.0(API 级别 26)中,您可以分配在(重新创建)的 activity 恢复且用户按下键盘导航键(如 Tab 键)后应获得焦点的 View
。如需应用此“默认聚焦”设置,请在包含界面元素的布局 XML 文件中将 View
元素的
android:focusedByDefault
属性设置为 true
,或在应用的界面逻辑中将 true
传入 setFocusedByDefault()
。
语音输出
activity 和服务可以使用 TextToSpeech
的实例说出和读出内容。从 Android 8.0(API 级别 26)开始,您的应用可以获取有关文字转语音引擎何时开始朗读单个合成字词的更精确的时间信息,前提是该引擎提供此信息。您可以使用此功能在文字转语音引擎朗读特定字词时吸引用户注意这些字词。
如需在您的应用中使用这些文字转语音引擎改进,请注册 UtteranceProgressListener
实例。在注册过程中,请为 onRangeStart()
方法添加一个处理程序。
文字转语音引擎会调用 rangeStart()
来记录预期在什么时间点开始对特定范围的文本进行音频播放。当相应文本范围的音频开始播放时,应用的 onRangeStart()
方法会执行。然后,您的应用就可以响应此回调(例如,通过突出显示与语音内容关联的文本范围)。
如需详细了解如何跟踪文字转语音引擎的播放进度,请参阅 UtteranceProgressListener
类参考文档。
系统
新的 StrictMode 检测程序
Android 8.0(API 级别 26)添加了三个新的 StrictMode 检测器,以帮助识别应用中的潜在 bug:
detectUnbufferedIo()
将检测您的应用何时在未缓冲的情况下读取或写入数据,这可能会严重影响性能。detectContentUriWithoutPermission()
将检测您的应用在外部启动 activity 时何时意外忘记向其他应用授予权限。detectUntaggedSockets()
将检测您的应用何时执行网络流量,而无需出于调试目的使用setThreadStatsTag(int)
标记流量。
缓存的数据
Android 8.0(API 级别 26)针对缓存的数据提供了更好的指导和行为。每个应用现在都会获得缓存数据的磁盘空间配额,由 getCacheQuotaBytes(UUID)
返回。
当系统需要释放磁盘空间时,首先会从超出所分配配额的应用中删除缓存文件。因此,如果您将缓存数据控制在分配的配额以下,则缓存文件将是系统上需要时最后清除的文件。当系统决定从您的应用内删除哪些缓存文件时,将首先考虑最早的文件(由修改时间确定)。
您还可以针对每个目录启用两种新行为,以控制系统如何释放缓存数据:
StorageManager.setCacheBehaviorAtomic()
可用于指示某个目录及其所有内容应作为一个原子单元删除。setCacheBehaviorTombstone(File, boolean)
可用于指示不应删除某个目录中的文件,而应将其截断为 0 字节长度,而使空文件保持完好。
最后,当您需要为大型文件分配磁盘空间时,请考虑使用新的 allocateBytes(FileDescriptor, long)
API,它会根据需要自动清除属于其他应用的缓存文件,以满足您的请求。在确定设备是否有足够的磁盘空间来保存新数据时,请调用 getAllocatableBytes(UUID)
而不是使用 getUsableSpace()
,因为前者会考虑系统愿意为您清除的任何缓存数据。
内容提供程序分页
我们更新了 content provider,现在支持以一次一页加载的方式加载大型数据集。例如,具有数千张图片的照片应用可查询要在页面中显示的部分数据。content provider 返回的每页结果都由一个 Cursor 对象表示。客户端和提供程序都必须实现分页才能使用此功能。
如需详细了解 content provider 的变更,请参阅 ContentProvider
和 ContentProviderClient
。
内容刷新请求
ContentProvider
和 ContentResolver
类现在分别包含一个 refresh()
方法,从而使客户端可以更轻松地了解其请求的信息是否为最新信息。
您可以通过扩展 ContentProvider
来添加自定义内容刷新逻辑。请务必替换 refresh()
方法以返回 true
,告知提供程序的客户端您已尝试自行刷新数据。
您的客户端应用可以通过调用另一个方法(也称为 refresh()
)来明确请求已刷新的内容。调用此方法时,请传入要刷新的数据的 URI。
注意:由于您可能会通过网络请求数据,因此仅当有明显迹象表明内容已过时,您才应从客户端调用 refresh()
。执行此类内容刷新的最常见原因是响应下拉刷新手势,从而明确请求当前界面显示最新内容。
JobScheduler 改进
Android 8.0(API 级别 26)引入了对 JobScheduler
的多项改进。这些改进可让您的应用更轻松地符合新的后台执行限制要求,因为您通常可以使用预定作业来替换现在受到限制的后台服务或隐式广播接收器。
对 JobScheduler
的更新包括:
-
您现在可以将工作队列与预定作业相关联。如需将工作项添加到作业的队列,请调用
JobScheduler.enqueue()
。当作业运行时,它可以将待处理的工作从队列中移除并进行处理。此功能可以处理以前需要启动后台服务(尤其是实现IntentService
的服务)的许多用例。 -
Android 支持库 26.0.0 引入了一个新的
JobIntentService
类,该类提供与IntentService
相同的功能,但在 Android 8.0(API 级别 26)或更高版本上运行时会使用作业而不是服务。 -
您现在可以调用
JobInfo.Builder.setClipData()
以将ClipData
与作业相关联。通过此选项,您可以将 URI 权限授予与作业相关联,类似于这些权限可以传播到Context.startService()
的方式。您还可以将 URI 权限授予用于工作队列上的 intent。 -
预定作业现在支持几个新的约束条件:
JobInfo.isRequireStorageNotLow()
- 如果设备的可用存储空间不足,作业将不会运行。
JobInfo.isRequireBatteryNotLow()
- 如果电池电量等于或低于临界阈值,则作业不会运行;临界阈值是指设备显示“低电量警告”系统对话框的电量。
NETWORK_TYPE_METERED
- 与大多数移动数据网络方案一样,作业需要按流量计费的网络连接。
自定义数据存储
Android 8.0(API 级别 26)允许您为您的偏好设置提供自定义数据存储,如果您的应用将偏好设置存储在云端或本地数据库中,或者偏好设置因设备而异,这会非常有用。如需详细了解如何实现数据存储区,请参阅自定义数据存储区。
媒体增强功能
VolumeShaper
有一个新的 VolumeShaper
类。可用于执行简短的自动音量转换,如淡入、淡出和淡入淡出。如需了解详情,请参阅使用 VolumeShaper 控制振幅。
音频焦点增强功能
音频应用通过请求和放弃音频焦点在设备上共享音频输出。
应用通过开始或停止播放或者降低音量来处理获得焦点的变化。有一个新的 AudioFocusRequest
类。通过将此类用作 requestAudioFocus()
的参数,应用在处理音频焦点变化时将具有新的功能:自动降低音量和延迟焦点获取。
媒体指标
新的 getMetrics()
方法会返回一个包含配置和性能信息的 PersistableBundle
对象(表示为属性和值的对应关系)。可以为以下媒体类定义 getMetrics()
方法:
MediaPlayer.getMetrics()
MediaRecorder.getMetrics()
MediaCodec.getMetrics()
MediaExtractor.getMetrics()
系统会为每个实例分别收集相关指标,并在实例的整个生命周期内保留这些指标。如果没有任何可用指标,则该方法会返回 null。返回的实际指标取决于类。
MediaPlayer
从 Android 8.0(API 级别 26)开始,MediaPlayer 可以播放受 DRM 保护的材料和 HLS 样本级加密媒体。
Android 8.0 引入了一个新的过载 seekTo()
命令,可以在跳转至某个帧时提供精细的控制。它包含用于指定跳转模式的第二个参数:
SEEK_PREVIOUS_SYNC
将媒体位置移动到与位于给定时间之前或时间点的数据源相关联的同步(或按键)帧。SEEK_NEXT_SYNC
将媒体位置移动到与数据源(位于给定时间之后或给定时间之后)相关联的同步帧(或按键)帧。SEEK_CLOSEST_SYNC
将媒体位置移动到与位于最近或给定时间的数据源相关联的同步帧(或按键)帧。SEEK_CLOSEST
用于将媒体位置移动到与位于最接近或位于给定时间的数据源相关联的帧(不一定是同步帧或关键帧)。
在连续跳转时,应用应使用任意 SEEK_
模式,而非 SEEK_CLOSEST
,后者运行相对缓慢,但可能更精确。
音频录制器
- MediaRecorder 现在支持对流式传输非常有用的 MPEG2_TS 格式:
Kotlin
mediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_2_TS)
Java
mediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_2_TS);
MediaMuxer
现在可以处理任意数量的音频和视频流。您不再局限于一个音轨和/或一个视频轨道。使用addTrack()
可以混录任意数量的曲目。MediaMuxer
还可以添加一个或多个包含用户定义的每帧信息的元数据轨道。元数据的格式由您的应用定义。只有 MP4 容器支持元数据轨道。
元数据对于离线处理非常有用。例如,来自传感器的陀螺仪信号可用于执行视频防抖。
添加元数据轨道时,轨道的 MIME 格式必须以前缀“application/”开头。写入元数据与写入视频/音频数据相同,只是数据不是来自 MediaCodec
。相反,该应用会将带有关联时间戳的 ByteBuffer
传递给 writeSampleData()
方法。时间戳必须与视频和音轨采用相同的时间基准。
生成的 MP4 文件使用 ISOBMFF 第 12.3.3.2 节中定义的 TextMetaDataSampleEntry
来指示元数据的 MIME 格式。使用 MediaExtractor
提取包含元数据轨道的文件时,元数据的 MIME 格式将提取到 MediaFormat
中。
增强的媒体文件访问功能
存储访问框架 (SAF) 允许应用公开自定义 DocumentsProvider
,以便其他应用能够访问数据源中的文件。事实上,文档提供程序甚至可以提供对驻留在网络存储空间或使用媒体传输协议 (MTP) 等协议的文件的访问权限。
但是,访问远程数据源中的大型媒体文件会带来一些挑战:
- 媒体播放器需要可寻址访问来自文档提供程序的文件。如果大型媒体文件位于远程数据源上,文档提供程序必须提前提取所有数据并创建快照文件描述符。如果没有相应的文件描述符,媒体播放器将无法播放该文件,因此在文档提供程序下载完该文件之前,媒体播放器无法开始播放。
- 媒体集合管理器(如照片应用)必须遍历一系列访问 URI,才能通过限定范围的文件夹访问存储在外部 SD 卡上的媒体。这种访问模式会使得对媒体执行的批量操作(例如移动、复制和删除)变得非常缓慢。
- 媒体集合管理器无法根据文档的 URI 确定其位置。因此,这些类型的应用很难允许用户选择媒体文件的保存位置。
Android 8.0 通过改进存储访问框架解决了上述每一个挑战。
自定义文档提供程序
从 Android 8.0 开始,存储访问框架允许自定义文档提供程序为驻留在远程数据源中的文件创建可查找的文件描述符。SAF 可以打开一个文件,以获取原生可查找的文件描述符。然后,SAF 向文档提供程序传送离散字节请求。此功能允许文档提供程序返回媒体播放器应用已请求的确切字节范围,而不必提前缓存整个文件。
如需使用此功能,您需要调用新的 StorageManager.openProxyFileDescriptor()
方法。openProxyFileDescriptor()
方法接受 ProxyFileDescriptorCallback
对象作为回调。每当客户端应用对从文档提供程序返回的文件描述符执行文件操作时,SAF 都会调用回调。
直接文档访问
从 Android 8.0(API 级别 26)开始,您可以使用 getDocumentUri()
方法获取与给定 mediaUri
引用相同文档的 URI。不过,由于返回的 URI 由 DocumentsProvider
提供支持,因此媒体集合管理器可以直接访问文档,而无需遍历限定作用域的目录树。因此,媒体管理器可以更快地对文档执行文件操作。
注意:getDocumentUri()
方法只能定位媒体文件,不会授予应用访问这些文件的权限。如需详细了解如何获取媒体文件的访问权限,请参阅参考文档。
文档路径
在 Android 8.0(API 级别 26)中使用存储访问框架时,您可以使用 DocumentsContract
和 DocumentsProvider
类中提供的 findDocumentPath()
方法,根据文档 ID 确定从文件系统根目录开始的路径。该方法会在 DocumentsContract.Path
对象中返回此路径。如果文件系统对于同一个文档有多个已定义的路径,该方法会返回访问具有指定 ID 的文档时最常使用的路径。
此功能在以下情况下特别有用:
- 应用使用显示特定文档位置的“另存为”对话框。
- 您的应用在搜索结果视图中显示文件夹,如果用户选择特定文件夹,则必须加载该文件夹内的子文档。
注意:如果您的应用只能访问路径中的部分文档,那么 findDocumentPath()
的返回值将仅包含应用可以访问的文件夹和文档。
监控音频播放
AudioManager
系统服务会维护一个活跃 AudioPlaybackConfiguration
对象列表,其中每个对象都包含有关特定音频播放会话的信息。您的应用可以通过调用 getActivePlaybackConfigurations()
检索当前活跃的配置集。
从 Android 8.0(API 级别 26)开始,您可以注册一个回调,用于在一个或多个 AudioPlaybackConfiguration
对象发生更改时通知您的应用。为此,请调用 registerAudioPlaybackCallback()
,并传入 AudioManager.AudioPlaybackCallback
的实例。AudioManager.AudioPlaybackCallback
类包含 onPlaybackConfigChanged()
方法,系统会在音频播放配置发生更改时调用此方法。
畅连乐享
Wi-Fi 感知
Android 8.0(API 级别 26)添加了对 Wi-Fi 感知的支持,这项支持基于近邻感知网络 (NAN) 规范。在具有相应 Wi-Fi 感知硬件的设备上,应用和附近的设备可以在没有互联网接入点的情况下,通过 Wi-Fi 发现和通信。我们正在与硬件合作伙伴合作,以尽快将 Wi-Fi 感知技术应用于设备。如需了解如何将 Wi-Fi 感知集成到您的应用中,请参阅 Wi-Fi 感知。
蓝牙
Android 8.0(API 级别 26)通过添加以下功能,丰富了平台对蓝牙的支持:
- 支持 AVRCP 1.4 标准,该标准支持音乐库浏览。
- 支持蓝牙低功耗 (BLE) 5.0 标准。
- 将 Sony LDAC 编解码器集成到蓝牙堆叠中。
配套设备配对
Android 8.0(API 级别 26)提供的 API 可让您在尝试通过蓝牙、BLE 和 Wi-Fi 与配套设备配对时自定义配对请求对话框。如需了解详情,请参阅配套设备配对。
如需详细了解如何在 Android 上使用蓝牙,请参阅蓝牙指南。如需了解特定于 Android 8.0(API 级别 26)的蓝牙更改,请参阅 Android 8.0 行为变更页面的蓝牙部分。
分享
智能共享
Android 8.0(API 级别 26)能够了解用户的个性化分享偏好设置,并且能够更好地了解每类内容,判断哪种内容适合用来分享内容。例如,如果用户拍摄收据照片,Android 8.0 可以推荐一款费用跟踪应用;如果用户进行自拍,则社交媒体应用可以更好地处理该图片。Android 8.0 会根据用户的个性化偏好设置自动学习所有这些模式。
智能分享适用于 image
以外的内容类型,例如 audio
、video
、text
、URL
等。
如需启用智能分享,请向分享内容的 intent 添加 ArrayList
(最多包含三个字符串注解)。注释应描述内容中的主要组成部分或主题。以下代码示例展示了如何向 intent 添加注释:
Kotlin
val annotations: ArrayList<String> = arrayListOf( "topic1", "topic2", "topic3" ) intent.putStringArrayListExtra( Intent.EXTRA_CONTENT_ANNOTATIONS, annotations )
Java
ArrayList<String> annotations = new ArrayList<>(); annotations.add("topic1"); annotations.add("topic2"); annotations.add("topic3"); intent.putStringArrayListExtra( Intent.EXTRA_CONTENT_ANNOTATIONS, annotations );
如需详细了解智能共享注释,请参阅 EXTRA_CONTENT_ANNOTATIONS
。
文本分类器
在兼容的设备上,应用可以使用新的文本分类器来检查字符串是否与已知的分类器实体类型匹配,并获取建议的替代方案选项。系统识别的实体包括地址、网址、电话号码和电子邮件地址。如需了解详情,请参阅 TextClassifier
。
无障碍功能
Android 8.0(API 级别 26)为创建自己的无障碍服务的开发者提供了几项新的无障碍功能:
- 新增了一个用于调整无障碍音量的音量类别。
- 指纹手势作为输入机制。
- 多语言文字转语音功能。
- 基于硬件的无障碍快捷方式,用于快速访问首选无障碍服务。
- 支持连续手势或程序化笔画序列。
- 一个“无障碍”按钮,用于调用已启用的多项无障碍功能之一(仅适用于使用软件渲染的导航区域的设备)。
- 标准化单端范围值。
- 几项功能有助于更轻松地处理文本,包括提示文本和屏幕文本字符的位置。
安全与隐私权
权限
Android 8.0(API 级别 26)引入了若干与电话相关的新权限:
-
ANSWER_PHONE_CALLS
权限允许您的应用以编程方式接听来电。如需在您的应用中处理来电,您可以使用acceptRingingCall()
方法。 -
READ_PHONE_NUMBERS
权限会授予您的应用对设备中存储的电话号码的读取权限。
新的账号访问和 Discovery API
Android 8.0(API 级别 26)针对应用访问用户帐号的方式引入了多项改进。对于其管理的账号,身份验证器可以使用自己的政策来决定是向应用隐藏账号还是向应用显示账号。Android 系统会跟踪可以访问特定账号的应用。
在以前的 Android 版本中,想要跟踪用户帐号列表的应用必须获取有关所有帐号的更新,包括具有不相关的类型的帐号。Android 8.0 添加了 addOnAccountsUpdatedListener(android.accounts.OnAccountsUpdateListener, android.os.Handler, boolean, java.lang.String[])
方法,可让应用指定应接收哪些帐号类型的帐号更改列表。
API 变更
AccountManager 提供了六种新方法,帮助身份验证器管理哪些应用可以看到帐号:
setAccountVisibility(android.accounts.Account, java.lang.String, int)
:设置特定用户帐号和软件包组合的可见性级别。-
getAccountVisibility(android.accounts.Account, java.lang.String)
:获取特定用户帐号和软件包组合的可见性级别。 -
getAccountsAndVisibilityForPackage(java.lang.String, java.lang.String)
:允许身份验证器获取给定软件包的帐号和可见性级别。 -
getPackagesAndVisibilityForAccount(android.accounts.Account)
:允许身份验证器获取存储的给定帐号的可见性值。 -
addAccountExplicitly(android.accounts.Account, java.lang.String, android.os.Bundle, java.util.Map<java.lang.String, java.lang.Integer>)
:允许身份验证器初始化帐号的可见性值。 -
addOnAccountsUpdatedListener(android.accounts.OnAccountsUpdateListener, android.os.Handler, boolean, java.lang.String[])
:向AccountManager
对象添加OnAccountsUpdateListener
监听器。每当设备上的帐号列表发生更改时,系统都会调用此监听器。
Android 8.0(API 级别 26)引入了两个特殊的软件包名称值,用于为未使用 setAccountVisibility(android.accounts.Account, java.lang.String, int)
方法设置的应用指定可见性级别。PACKAGE_NAME_KEY_LEGACY_VISIBLE
可见性值会应用于具有 GET_ACCOUNTS
权限、目标 Android 版本低于 Android 8.0 的应用,或其签名与针对任何 Android 版本的身份验证器相匹配的应用。PACKAGE_NAME_KEY_LEGACY_NOT_VISIBLE
可为之前未设置且 PACKAGE_NAME_KEY_LEGACY_VISIBLE
不适用的应用提供默认的可见性值。
如需详细了解新的帐号访问 API 和发现 API,请参阅 AccountManager
和 OnAccountsUpdateListener
参考文档。
测试
仪器测试
Android 8.0(API 级别 26)为应用的插桩测试提供了以下几项额外的支持。
针对非默认应用进程运行
现在,您可以指定应针对应用默认进程之外的进程运行特定的插桩测试。如果您的应用包含多个在不同进程中运行的 activity,此配置非常有用。
如需定义非默认进程插桩,请转到清单文件,然后找到所需的
<instrumentation>
元素。添加 android:targetProcess
属性,并将其值设置为以下值之一:
- 特定进程的名称。
- 以逗号分隔的进程名称列表。
- 通配符 (
"*"
),允许针对执行android:targetPackage
属性中所指定软件包内代码的任何已启动进程运行插桩测试。
在执行插桩测试时,您可以通过调用 getProcessName()
检查正在测试的进程。
在测试过程中报告结果
您现在可以通过调用 addResults()
在插桩测试执行期间(而不是之后)报告结果。
用于测试的模拟 Intent
为了更轻松地为应用的 activity 创建隔离的独立界面测试,Android 8.0(API 级别 26)引入了 onStartActivity()
方法。您可以在 Instrumentation.ActivityMonitor
类的自定义子类中替换此方法,以处理测试类调用的特定 intent。
当测试类调用 intent 时,该方法会返回桩 Instrumentation.ActivityResult
对象,而不是执行 intent 本身。通过在测试中使用这种模拟 intent 逻辑,您可以专注于 activity 如何准备和处理您传递给不同 activity 或完全不同的应用的 intent。
运行时和工具
平台优化
Android 8.0(API 级别 26)为平台带来了运行时优化和其他优化,从而显著提升了性能。这些优化包括并发压缩垃圾回收、更高效的内存使用以及代码位置。
这些优化可以缩短启动时间,并提高操作系统和应用的性能。
更新了 Java 语言支持
Android 8.0(API 级别 26)添加了对多个其他 OpenJDK Java API 的支持:
- OpenJDK 8 中的
java.time
。 - OpenJDK 7 中的
java.nio.file
和java.lang.invoke
。
如需详细了解这些新添加的软件包中的类和方法,请参阅 API 参考文档。
如果您想在 Android Studio 中 使用 Java 8 语言功能,则应下载最新的预览版。
更新的 ICU4J Android Framework API
Android 8.0(API 级别 26)扩展了 ICU4J Android 框架 API(ICU4J API 的子集),供应用开发者通过 android.icu
软件包使用。这些 API 使用设备上存在的本地化数据,因此您不需要在 APK 中编译 ICU4J 库,从而减少 APK 占用的空间。
表 1. Android 中使用的 ICU、CLDR 和 Unicode 版本。
Android API 级别 | ICU 版本 | CLDR 版本 | Unicode 版本 |
---|---|---|---|
Android 7.0(API 级别 24),Android 7.1(API 级别 25) | 56 | 28 | 8.0 |
Android 8.0(API 级别 26) | 58.2 | 30.0.3 | 9.0 |
如需详细了解 Android 的国际化(包括 ICU4J 支持),请参阅 Android 上的国际化。
Android 企业版
我们针对搭载 Android 8.0(API 级别 26)的设备引入了新的企业功能和 API。亮点包括:
- 借助全代管式设备上的工作资料,企业可以在管理工作与个人数据的同时,将工作数据与个人数据分隔开来。
- API 委派允许设备所有者和资料所有者将应用管理分配给其他应用。
- 配置流程中的用户体验改进(包括新的自定义选项)缩短了设置时间。
- 通过蓝牙、Wi-Fi、备份和安全性的新控制功能,企业可以管理更多设备。网络活动日志记录可帮助企业查明问题。
如需详细了解这些 API 和功能,请参阅企业中的 Android。