Android4.2新特性及新增API

jopen 10年前

Android 4.2 系统,名字仍为 Jelly Bean。以下是 Android 4.2 的新特性汇总。

 

无线视频

Android 4.2 支持 Miracast 影像传输协议。据 The Verge 介绍,这是一种符合业界标准的 Wifi 显示共享协议。这个功能可以让 Nexus 4 等新设备将音频、视频无线传输到电视上去,你可以把它理解为“开放版本的 AirPlay”。

据悉,类似 Apple TV 的 Miracast 机顶盒将很快开售,Google 希望它们的售价保持在 99 美元以下。不仅如此,Miracast 将会很快直接内置到电视里,比如 LG 就已经承诺将其内置到 2013 年的智能电视里。 此外,Google 还透露开发者们可以在电视屏幕及手机屏幕上运行不同的程序。

 

Android 平板的多账户支持

Android 将支持多账户已经不是什么新鲜的传言。在 Android 4.2 上,Google 终于正式发布了这个功能,不过只针对平板用户。

每个账户可以拥有自己的主屏、壁纸、插件和应用,并且应用数据都可以区分开来。Android 4.2 在处理应用数据的时候非常聪明。假如账户 A 已经下载了某个应用,其他的账户无需再次下载,并且 Android 4.2 能确保其他用户新装的是一个“干净”的版本。

切换账户的时候,原账户的应用将保持在后台运行。不过,这种“后台运行”的方式只能让你完成下载等任务,其他任务几乎处于关闭状态。比如你不能在账户 A 的后台运行着一个音乐播放器,然后在保持播放器运行的情况切换到账户 B。


Gesture Typing,滑动输入

如果你对 Swype 输入法有所耳闻,Android 4.2 的这个新功能你应该毫不陌生。

用户可以通过手指在字母之间的滑行完成输入操作,滑行过程中键盘上会显示出单词列表。这个新功能搭配上 Android 原有的单词预测功能,The Verge 体验的感觉是“相当不错”,并称这个功能的表现要比 Swype 更灵敏和准确。

Photo Sphere 全景相片

Android 4.0,Google 引进了全景拍照功能。iOS 6,苹果紧随其后。现在 Android 4.2 又把自家的全景拍照功能发展到了一个新的高度。

Android 4.2 新推出的“Photo Sphere 全景相片”功能可以让用户将四个方向的图像全部拍摄下来,最终生成一张全景照片。据悉,这个功能使用了一些跟街景相关的技术

其他

Android 4.2 的其他新功能还有:

  • Daydream(白日梦)功能,可以将其理解为一个“屏保”。
  • 锁屏界面现在也支持放置 Widgets,并且支持滑动开启相机。
  • 通知抽屉(notification drawer)加入了更多的操作,可以打开 WiFi,调整屏幕亮度,打开飞行模式等等。
  • Gmail 支持缩放。
  • 辅助功能方面的改进:三击放大屏幕,可以用两指来平移和缩放,并为盲人用户引进了语音输出和手势模式导航功能。
  • Gmail 现在也是 Google Now 的信息来源。Google Now 改进了航班追踪、酒店和餐馆预定、音乐及电影推荐的功能。Photo Spot 可以根据你的位置向你推荐拍照的好去处。

 

 

Android4.2新增API

API等级:17

Android4.2JELLY_BEAN_MR1)是一个为用户和应用程序开发人员提供了新功能的JellyBean升级版本。本文档为开发者提供了最显著的和最有用的新API的简介。

作为应用程序开发人员,您应该尽快用SDK管理器下载Android4.2系统映像和SDK平台的SDK管理器。如果您没有Android4.2的设备用以测试您的应用,您可以在模拟器上使用Android4.2系统映像来测试您的应用。

重要的行为变化

如果您先前发表过Android应用,请注意下列变化,它们可能会影响您应用程序的行为:

  • Contentprovider默认不再有导出属性。也就是说,android:exported属性的默认值为"false"。如果别的应用能访问您的contentprovider对您意义重大,您必须显式的设置android:exported="true"
    此更改仅在您设置targetSdkVersionandroid:minSdkVersion17或更高时生效。否则,即使运行在Android4.2版本上时,默认值仍然是“true”

  • 相对以前的版本的Android,如果您的应用程序请求了ACCESS_COARSE_LOCATION权限而没有请求ACCESS_FINE_LOCATION权限,用户定位的精度会有所下降。
    为保护用户隐私,当您的应用仅请求了大概位置权限(而没有请求准确位置权限)时,系统提供的位置精度将小于一个街区。

  • 一些Settings.System中所定义的设备设置变为了只读。一些原先在Settings.System中现在移到了Settings.Global中。在Android4.2或更高系统上,如果您的应用试图修改这些设置,操作将不起作用。
    即便您的android:targetSdkVersionandroid:minSdkVersion低于17,您的应用也无法在Android4.2上修改已经移至Settings.Global中的设置项。

白日梦

白日梦是Android设备的新型互动屏保模式。当设备置入底座或充电闲置状态时(屏幕没有关闭),此模式自动激活。白日梦模式每次显示一个,可以是纯粹的视觉效果,在用户触摸时消失,也可以是响应用户所有输入的交互式应用。您的白日梦将运行在您应用的进程内,并可以访问所有的AndroidUI工具包,可以使用视图、布局和动画等。所以它比动态壁纸或应用窗口小部件更具表现力。

您可以由实现DreamService的子类来创建一个白日梦。DreamServiceAPI被设计成类似Activity。在通过诸如onAttachedToWindows()之类的方法获得窗口后,就可以给setContentView()设定一个布局资源IDView,来为您的白日梦设置UI

DreamService类在基础的ServiceAPI上添加了很多其它重要的生命周期回调方法。如onDreamingStarted()、onDreamingStopped()和onDetachedFromWindow()。您无法从您的应用中启动DreamService,它是由系统自动启动的。

如果您设计的是互动型的白日梦,您可以由白日梦将用户导入到您应用中的Activity中,以获得更详尽的内容和更多控制方法。您可以使用finish()来结束白日梦,之后用户就可以看到新的Activity

为了使您的白日梦对系统可用,您需要在manifest文件中的元素下声明您的DreamService。然后,您必须在其中加入具有"android.service.dreams.DreamService"动作的intentfilter。例如:

        <service
            android:name=".MyDream"
            android:exported="true"
            android:icon="@drawable/dream_icon"
            android:label="@string/dream_label" >
            <intent-filter>
                <action android:name="android.service.dreams.DreamService" />
                <category android:name="android.intent.category.DEFAULT" />
            </intent-filter>
        </service>

DreamService中还有一些其它有用的方法需要留意:

setInteractive(boolean)用于设定您的白日梦在收到输入事件时是不是立刻退出。如果白日梦是交互式的,用户可以使用“后退”或“主页”按钮退出,或者您可以调用finish()来停止。

如果您想提供身临其境的显示,您可以调用setFullscreen()来隐藏状态栏。

白日梦开始之前,显示屏会渐暗以提示用户空闲超时时间接近。调用setScreenBright(true)则会去除这个过程。

欲了解更多信息,,请参阅DreamService文档。

辅助显示器

Android现在可以让您的应用在辅助显示器上显示不同的内容程序,以有线或Wi-Fi将外接显示输出连接到用户设备上,显示独特的内容。要为辅助显示屏创建独特的内容,您需要扩展Presentation类,并实现onCreate()回调方法。在onCreate()中,调用setContentView()来指定您要在辅助显示屏上显示的UI。作为Dialog类的扩展,Presentation类提供了一个区域,在其中,您的应用可以在辅助显示屏上显示不同的UI

为了获取显示Presentation的辅助显示屏,您可以使用DisplayManager或者MediaRouterAPI。其中,使用DisplayManagerAPI可以使您获得当前连接的所有显示屏的枚举,而MediaRouter则可以使您直接访问系统为Presentation设置的默认显示输出。

您可以给MediaRouter.getSelectedRoute()传一个ROUTE_TYPE_LIVE_VIDEO来获得演示的默认显示器。它将返回一个MediaRouter.RouteInfo对象,描述了系统为视频演示所选择的当前路由。如果MediaRouter.RouteInfo不空,调用getPresentationDisplay()即可获取当前连接的显示屏对象:Display

然后,您可以将这个Display对象传入Presentation的构造函数。演示就会出现在辅助显示屏上了。

为在运行时即时检测新接入的显示器,需要先创建一个MediaRouter.SimpleCallback的实例。在其中,您需要实现onRoutePresentationDisplayChanged()回调方法。当新的显示器连接时,系统会调用这个回调方法。然后将MediaRouter.SimpleCallback加上ROUTE_TYPE_LIVE_VIDEO路由类型传递给MediaRoute.addCallback()来进行注册。当收到onRoutePresentationDisplayChanged()回调时,只要如上所述的调用MediaRouter.getSelectedRoute()即可。

为针对辅助显示进一步优化PresentationUI,您需要为您的应用或activity指定标签为android:presentationTheme主题。

请留意,连接到用户移动设备的屏幕往往有较大的屏幕尺寸和不同的屏幕密度。由于屏幕特征可能不同,您需要为大型显示设备提供特定优化的资源。如果您需要从Presentation中获取额外的资源,调用getContext().getResources()来获取针对这种显示的资源对象。这样,您的应用就可以根据辅助显示器的尺寸和密度提供最合适的资源了。

欲了解更多信息以及一些代码示例,请参阅Presentation类文档。

锁屏小部件

Android现在允许用户添加应用窗口小部件至锁屏界面。为了使您应用程序的窗口小部件可用于在锁屏,您需要在指定了AppWidgetProviderInfoXML文件中加入android:widgetCategory属性。此属性支持两个取值:home_screenkeyguard。默认情况下,属性设置为home_screen,由此用户可以添加应用的窗口小部件到主屏幕。如果您希望应用的窗口小部件同样支持锁屏,则加入keyguard取值:

<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
    ...
    android:widgetCategory="keyguard|home_screen">
</appwidget-provider>

您应该用
android:initialKeyguardLayout属性来为您的应用窗口小部件指定一个锁屏显示初始化布局。它作用的方式与android:initialLayout相同:先立刻在屏幕上显示一个布局,当应用窗口小部件初始化完毕后,再对布局进行更新。

欲了解更多关于锁屏窗口小部件的信息,包括如何为您的应用小部件设置适合的尺寸,请参阅应用程序部件指南。

多用户

Android现在允许平板等可共享的设备,拥有多个用户空间。设备上的每个用户都有他或她自己的帐户、应用程序、系统设置、文件,以及任何其他用户相关的数据集。

作为应用程序开发人员,您毋须为多用户模式做任何额外工作。不管设备上有多少用户,特定用户所用的应用数据都是跟其它用户分开的。系统会跟踪用户运行的应用数据的归属,并限定您的应用仅能访问所属用户的数据,而无法访问其它用户的数据。

多用户环境中的数据保存

当您的应用程序保存用户喜好,创建数据库,或向用户的内部或外部存储空间写入文件时,这些数据仅能被当前运行此应用的用户所访问。

为确保您的应用在多用户环境中表现正常,请不要对应用内的路径或外部存储路径使用硬编码路径,而是要使用相应的API

访问内部存储时,使用getFilesDir()getCacheDir()、和openFileOutput()方法。

访问外部存储时,使用getExternalFilesDir()getExternalStoragePublicDirectory()

无论您使用这些API中的哪个,它们保存的数据都无法被其它用户访问。从应用程序的角度来看,每个用户都运行在完全独立的设备上。

多用户环境中的用户识别

如果您的应用要区分用户以进行搜集分析或创建其他帐户联系,您都应当以下遵循建议方法来进行识别。无论有多少用户在设备上安装了您的应用,您的应用在首次运行时都要生成唯一的UUID,您可以用这ID来对每个用户进行甄别。或者,您也可以保存从您的服务器获取的本地令牌或由谷歌云消息服务所提供的注册ID来进行甄别。

要注意的是,如果您的应用使用硬件设备标识符(如WiFiMAC地址,序列号,或ANDROID_ID数),它们会为每个用户提供相同的值,因为这些标识符依赖的硬件,而不是用户。更不用说使用这些标识符还会引起各种各样的其它问题。

新的“全局设置”

系统设置已经为支持多用户作了更新,添加了Settings.Global类。这一系列设置与Settings.Secure设置类似,也是只读的,但对于设备上的所有用户空间生效。

很多原来位于Settings.SystemSettings.Secure的设置移到了这里。如果您应用对曾经在Settings.System中定义的设置(比如AIRPLANE_MODE_ON)进行过更改的话,那么您就应该想到,在Android4.2和更高版本的设备上,这些设置已经移至Settings.Global,从而您的代码不会再起作用了。您仍然可以由Settings.Global中读取设置,但在Android4.2和更高的版本中,因为觉得这些设置不应当被应用修改,所以所有的修改操作将不被执行,并在系统日志中记下一条警告记录。

RTL布局支持

Android现在提供了一些API,使您可以构建更优雅的变换布局方向的用户界面。这些界面将支持由右到左(RTL)的语言和阅读方向。比如阿拉伯语和希伯来语。

为了使您的应用支持RTL布局,需要在manifest文件中设置元素的android:supportsRtl属性为“true”。一旦启用,该系统将启用各种RTLAPI来用RTL布局显示您的应用。举例来说,在操作栏中将操作按钮显示在左侧,而把图标和标题显示在右侧。所有您用框架提供的View类所构建的布局也会以相反的方向显示。

如果您需要在显示RTL布局时进一步优化您应用的外观,有两个基本层面的优化:

  1. 将左——右方向的布局属性转变为开始——结束方向的布局属性。
    例如,用android:layout_marginStart替换android:layout_marginLeft,用android:layout_marginEnd替换android:layout_marginRight
    RelativeLayout
    类也提供了相应的布局属性,来替换左/右位置,如:android:layout_alignParentStart替换android:layout_alignParentLeft,用android:layout_toStartOf替换android:layout_toLeftOf

  2. 或者,使用ldrtl资源限定词(ldrtl意味着布局方向由右至左)资源提供完整的针对RTL布局优化过的布局文件。例如,您可以在res/layout/目录保存您默认的配置文件,而在res/layout-ldrtl/目录下保存您针对RTL优化过的布局。
    ldrtl
    限定词对drawable资源也很适用,这样您就可以提供与阅读方向相同的图片了。

框架中还有各种其它的支持RTL布局的API,比如,在View类中,您可以在定制的view中实现适当的行为;在Configuration类中,可以查询当前的布局方向。

注意:如果您用SQLite而表名或列名使用了“仅允许数字”特性。请小心:当您的设备设置为阿拉伯地区,使用String.format(String,Object...) 方法时会因为数字转换成对应的阿拉伯文而导致错误。您必须使用String.format(Locale,String,Object...),以确保数字以ASCII的编码保存。还可以使用String.format("%d",int)来取代String.valueOf(int)以格式化数字。

嵌套Fragment

现在,您可以嵌套FragementFragment中。当您遇到想在一个可复用的动态UI组件里放入另一个可复用的UI组件时,这个方案就非常有用。例如,如果您用ViewPager做了个可左右滑动的Fragment,并占用了大部分屏幕空间,您可以在其中的每个fragment页面中嵌入别的fragment了。

想要实现嵌套Fragment,只需在您想进行嵌入的Fragment中调用getChildFragmentManager() 方法。这样会返回一个FragmentManager,然后您就可以用和在顶层的Acitivity中嵌入fragment一样的方法进行操作了。例如,以下代码在一个现有的Fragment类中加上了另一个Fragment

Fragment videoFragment = new VideoPlayerFragment();  FragmentTransaction transaction = getChildFragmentManager().beginTransaction();  transaction.add(R.id.video_fragment, videoFragment).commit();

在嵌套的fragment中,您可以通过调用getParentFragment()方法来获取父fragment的引用。

Android支持库现在也加入了嵌套Fragment支持,因此在Android1.6及更高版本上,您都可以使用嵌套fragment来进行设计。

注意:不能在fragment中导入一个包含标签的布局文件。嵌套fragment仅支持动态加入fragment