在刚刚过去的中秋小长假当中,首批iPhone 7终于发货了,相信现在有不少人已经用上新的iPhone了。之前华尔街的分析师们都是普遍看衰iPhone 7的,认为这一代的iPhone创新点不足,销量应该不及同期的iPhone 6或者6s。然而事实却打了所有分析师的脸,美国多家运营商表示,iPhone 7的预定量是当年iPhone 6的四倍,首批iPhone 7也早早就卖断货了。首此影响,苹果的股票大涨,市值重回6000亿美元时代。
有不少网友认为,iPhone 7之所以能卖这么火爆,主要要归功于老对手三星的Galaxy Boom 7的神助攻。
本篇来自
milter
的投稿,翻译了外国开发者有关多窗口的建议。本文并不介绍具体如何开发多窗口(需要的了解的童鞋可以自己搜索),而是帮助大家在具体开发中如何避免“一些坑”。
milter
的博客地址:
http://www.jianshu.com/users/511ba5d71aef
这两天,关于Android最大的新闻莫过于
Android 7.0正式版
的发布,开发多窗口应用将成为广大Android开发者必须get的新技能点。在这篇文章里,google工程师 Ian Lake 给出了5点建议,帮助你快速掌握多窗口应用的开发。原文在这里(可能要自备梯子):
https://medium.com/google-developers/5-tips-for-preparing-for-multi-window-in-android-n-7bed803dda64
如果你之前浏览过
Android N的新特性
(需科学上网):
https://www.youtube.com/watch?v=CsulIu3UaUM&utm_campaign=adp_series_prepareformultiwindow_032316&utm_source=medium&utm_medium=blog
你应该已经发现了Android N对多窗口的支持。
当把屏幕拆分成多窗口后,两个APP可以并排可见,如下图所示:
我很兴奋,很想知道背后的原理,于是迅速查看了说明文档,寻找那些实现这一魔术般效果的新的API。
结果有点小失望,我没有发现许多新的API,新的系统只增加了
一些XML属性
和
一些Activity方法
。
XML属性
可以用来说明你的应用是否支持多窗口,
Activity方法
用来帮你检查Activity是否正处于多窗口模式中。那么,神奇的多窗口功能在哪里实现的呢?答案是Android一直都具备实现多窗口的功能,只不过刚被挖掘出来而已。
秘密就隐藏在Android的资源系统中,该系统最重要的能力就是根据应用所处设备的配置条件和应用中的资源标识符,提供不同的资源,如
layouts,drawables,menus
等等。举例来说,通过创建一个
drawable-sw600dp文件夹
,并在其中放置合适的
layout
资源文件,你的应用可以在大屏幕设备和小屏幕设备上呈现不一样的布局。
多窗口功能的实现正是利用了资源系统的这一特性,根据你的Activity窗口的尺寸调整相应的设备配置条件----最明显的条件就是屏幕尺寸,但同时,
最小宽度
(即
sw值
,
屏幕宽和高中的较小值
)和
屏幕方向
(orientation)也将随着
Activity
窗口尺寸的调整而更新。
这就引出了我们的第一条建议。
使用正确的Context
加载合适的资源需要合适的
Context
。如果你使用
Activity Context
来
inflate
你的
layouts
,
获取资源
等等,一切都是正确无误的,尽可放心。
然而,如果你使用
Application context
来做任何与UI相关的事,比如加载一个
drawable
,你将会发现
该
context
完全不知道多窗口这回事,自然也就无法帮你加载合适的资源,除了不使用你为不同配置条件设置的Activity主题外,还可能加载
完全错误
的资源!!!所以,
在多窗口应用中,当你做UI相关的事情时,
切记切记使用 Activity Context
。
正确处理配置变化
当你使用正确的
context
时,你就始终可以根据
Activity
的窗口尺寸获取到正确的资源,不管该窗口是处于全屏状态还是处于与其他应用共享屏幕的分屏状态。每次重新加载资源的过程都基于你怎样处理运行时的配置变化。
应对配置变化的默认处理是
销毁整个Activity并重建它
、
恢复你在onSaveInstanceState()中保存的任何状态
、
重新加载所有的资源和layouts
。这样做的好处有两点:
毫无疑问,每种配置的变化都应当得到快速连贯的处理,为此,请不要在
onResume
中做过多的工作,并考虑使用
loaders
来确保你的数据不会因配置变化而丢失:
你也可以自己处理配置的变化,在这种情况下,你的
Activity
(或者
Fragment
)将不会销毁重建,相反,你将会收到一个
onConfigurationChanged()
回调,你需要在回调中
手动更新你的
views
,
重新加载资源
等等。
为了能够catch住多窗口相关的配置变化,你至少需要在清单文件中为你的
Activity的android:configChanges属性
添加如下值:
当你自己处理配置变更时,请确保处理好每一个可能发生变化的资源。
这里所说的
“每一个可能发生变化的资源”
包括一些在单窗口环境中被认为不会发生变化的资源。比如,你在
values
和
values-sw600dp
文件下有一个
dimension
。在单窗口应用时代,你永远不会在应用运行时切换这个
dimension
,因为最小宽度(smallest width)是不会变化的,它永远是你的设备的高和宽中的较小值。然而,在多窗口应用时代,当你的应用发生
resize
时,你将不得不在不同的
dimension
之间切换。因为此时,
最小宽度
这项配置将不再是一个常量,而是一个变量。
处理所有的方向(orientations)
本文开始时,我们提到,当
Activity
的窗口
resize
时,
orientation
这项配置将会发生变化。是这样的:即使设备处于
水平(landscape)
方向,你的应用也可能处于
“竖直(portrait)”
方向。
这说明:
“竖直(portrait)”
真正的含义是Activity的窗口的高度大于宽度,
“水平(landscape)”
的真正含义是窗口的宽度大于高度,牢记这一点后,你就可以在
Activity
的窗口
resize
时,正确地从一种状态过渡到另一种状态。
这也同时意味着,不同的
orientations
间的过渡应尽可能地平滑。这里引用
分屏材料设计规范
中的一段话:
改变一个设备的方向不应该引起应用的UI产生非预料的变化。举例来说,如果一个应用正在多窗口模式下播放一个视频,此时设备处于竖直状态。当把设备旋转到水平状态时,该应用不应该转为全屏播放。
说明:
如果你说,假如我的应用一开始是在竖直全屏播放,设备变成水平时,我想让应用变为水平全屏播放怎么办?你可以用
inMultiWindowMode
()
来检查
Activity
当前所处的状态。
以前,你可以通过
android:screenOrientation属性
锁定屏幕方向,但现在情况发生了变化:
另外,请切记,多窗口模式下,企图通过
setRequestedOrientation()
在运行时锁定屏幕方向是没有任何效果的,无论你的应用的目标(target)是不是 Android N。
在 Activity 的清单文件中添加
android:immersive属性
,产生的效果与
android:screenOrientation属性
是一样一样的。
为所有的屏幕尺寸创建响应式的UI
在设计多窗口应用时,
Orientation
是你必须要注意考虑的问题,但仅考虑
Orientation
是不够的。在多窗口时代,你的平板UI将会被缩放到一个微小的尺寸,在以前这是不会发生的。
如果你正在构建一套响应式UI,以便应对不同的
available space
,并且为手机和平板创建的
layo
ut
比较相似,你的应用将很容易迁移到多窗口环境中。根据建议,你现在可以将UI缩放到
220dp
的宽/高,并以该尺寸为基础,往上构建全屏尺寸的UI。
但是,如果你的手机和平板的UI差异很大,请不要强制进行转换(即不要把手机的UI强制转换到平板上展示,也不要把平板的UI强制转换到手机上展示)。你有很多种
响应式UI模式
可选择,以便为用户提供良好顺滑的resize体验,并且不需要任何APIs。
被其他应用启动的Activity必须始终支持多窗口
在多窗口的世界里,一个
任务(task)
是用
一个单独的
窗口来表示的,也就是说,
窗口(Window)
与
任务(Task)
是一一对应的。所以,当你想启动一个Activity,并让它与当前Activity分享屏幕时,你必须启动一个新的任务,新的窗口。
反过来也成立,当你在
当前
Activity
所属任务栈中启动
另一个Activity
时,
这个
Activity
将会在同一个窗口中替代
当前Activity
,并继承它所有的多窗口属性。
这意味着,当你有一个可被其他应用启动的
Activity
时,你的
Activity
将会继承启动它的
Activity
的多窗口属性,包括最小尺寸等。当你的
Activity
是以
startActivityForResult()
方式启动时,你的
Activity
还必须成为启动它的
Activity
所在任务栈的一部分。也就是说,这时候不能以新的任务栈的方式启动你的
Activity
。
即使当你的
Activity
是被一个
隐式Inte
nt
启动时,你也不能确定该Intent就一定包含
FLAG_ACTIVITY_NEW_TASK
标记,这就是说,你的
Activity
还是可能会继承启动它的
Activity
的多窗口属性。
因此,每一个被其他应用启动的Activity都必须支持多窗口,所以要进行彻底的测试!
应对多窗口最好的办法就是全面测试你的应用。最好的测试就是把你的应用安装到一个
Android N
的设备或者模拟器上,这种办法不需要你改动代码,也不需要你设置 Android N SDK,但确实是开始测试的最好的一步。
注:文中出现的
蓝色字体
是超链接,这些链接(
需要梯子
且
文章都是英文
)比较长,我就没有全部贴出,感兴趣的朋友可以通过最后
阅读原文
查看。
如果你有好的技术文章想和大家分享,欢迎向我的公众号投稿,投稿具体细节请在公众号主页点击
“投稿”
菜单查看。
欢迎
长按下图 -> 识别图中二维码
或者
扫一扫
关注我的公众号: