专栏名称: 郭霖
Android技术分享平台,每天都有优质技术文章推送。你还可以向公众号投稿,将自己总结的技术心得分享给大家。
目录
相关文章推荐
51好读  ›  专栏  ›  郭霖

Google工程师关于Android 7.0多窗口应用开发的五点建议

郭霖  · 公众号  · android  · 2016-09-19 07:31

正文

请到「今天看啥」查看全文


今日科技快讯


在刚刚过去的中秋小长假当中,首批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 窗口尺寸的调整而更新。


这就引出了我们的第一条建议。


建议1:

使用正确的Context


加载合适的资源需要合适的 Context 。如果你使用 Activity Context inflate 你的 layouts 获取资源 等等,一切都是正确无误的,尽可放心。


然而,如果你使用 Application context 来做任何与UI相关的事,比如加载一个 drawable ,你将会发现 context 完全不知道多窗口这回事,自然也就无法帮你加载合适的资源,除了不使用你为不同配置条件设置的Activity主题外,还可能加载 完全错误 的资源!!!所以, 在多窗口应用中,当你做UI相关的事情时, 切记切记使用 Activity Context


建议2:

正确处理配置变化


当你使用正确的 context 时,你就始终可以根据 Activity 的窗口尺寸获取到正确的资源,不管该窗口是处于全屏状态还是处于与其他应用共享屏幕的分屏状态。每次重新加载资源的过程都基于你怎样处理运行时的配置变化。


应对配置变化的默认处理是 销毁整个Activity并重建它 恢复你在onSaveInstanceState()中保存的任何状态 重新加载所有的资源和layouts 。这样做的好处有两点:


  • 新建的Activity将会与新的配置条件保持一致。


  • 每一种配置的变化都在重建中得到了处理。


毫无疑问,每种配置的变化都应当得到快速连贯的处理,为此,请不要在 onResume 中做过多的工作,并考虑使用 loaders 来确保你的数据不会因配置变化而丢失:


你也可以自己处理配置的变化,在这种情况下,你的 Activity (或者 Fragment )将不会销毁重建,相反,你将会收到一个 onConfigurationChanged() 回调,你需要在回调中 手动更新你的 views 重新加载资源 等等。


为了能够catch住多窗口相关的配置变化,你至少需要在清单文件中为你的 Activity的android:configChanges属性 添加如下值:




当你自己处理配置变更时,请确保处理好每一个可能发生变化的资源。


这里所说的 “每一个可能发生变化的资源” 包括一些在单窗口环境中被认为不会发生变化的资源。比如,你在 values values-sw600dp 文件下有一个 dimension 。在单窗口应用时代,你永远不会在应用运行时切换这个 dimension ,因为最小宽度(smallest width)是不会变化的,它永远是你的设备的高和宽中的较小值。然而,在多窗口应用时代,当你的应用发生 resize 时,你将不得不在不同的 dimension 之间切换。因为此时, 最小宽度 这项配置将不再是一个常量,而是一个变量。


建议3:

处理所有的方向(orientations)


本文开始时,我们提到,当 Activity 的窗口 resize 时, orientation 这项配置将会发生变化。是这样的:即使设备处于 水平(landscape) 方向,你的应用也可能处于 “竖直(portrait)” 方向。


这说明: “竖直(portrait)” 真正的含义是Activity的窗口的高度大于宽度, “水平(landscape)” 的真正含义是窗口的宽度大于高度,牢记这一点后,你就可以在 Activity 的窗口 resize 时,正确地从一种状态过渡到另一种状态。


这也同时意味着,不同的 orientations 间的过渡应尽可能地平滑。这里引用 分屏材料设计规范 中的一段话:


改变一个设备的方向不应该引起应用的UI产生非预料的变化。举例来说,如果一个应用正在多窗口模式下播放一个视频,此时设备处于竖直状态。当把设备旋转到水平状态时,该应用不应该转为全屏播放。


说明: 如果你说,假如我的应用一开始是在竖直全屏播放,设备变成水平时,我想让应用变为水平全屏播放怎么办?你可以用 inMultiWindowMode () 来检查 Activity 当前所处的状态。


以前,你可以通过 android:screenOrientation属性 锁定屏幕方向,但现在情况发生了变化:


  • 如果你的 应用的目标(target)不是 Android N ,那么这个属性意味着你的应用将完全不支持多窗口。在用户使用你的应用时,将会强迫用户退出多窗口模式。


  • 如果你的 应用的目标(target)是Android N ,那么当用户在多窗口模式下使用你的应用时,这个属性将被忽略。


另外,请切记,多窗口模式下,企图通过 setRequestedOrientation() 在运行时锁定屏幕方向是没有任何效果的,无论你的应用的目标(target)是不是 Android N。


在 Activity 的清单文件中添加 android:immersive属性 ,产生的效果与 android:screenOrientation属性 是一样一样的。


建议4:

为所有的屏幕尺寸创建响应式的UI


在设计多窗口应用时, Orientation 是你必须要注意考虑的问题,但仅考虑 Orientation 是不够的。在多窗口时代,你的平板UI将会被缩放到一个微小的尺寸,在以前这是不会发生的。


如果你正在构建一套响应式UI,以便应对不同的 available space ,并且为手机和平板创建的 layo ut 比较相似,你的应用将很容易迁移到多窗口环境中。根据建议,你现在可以将UI缩放到 220dp 的宽/高,并以该尺寸为基础,往上构建全屏尺寸的UI。




但是,如果你的手机和平板的UI差异很大,请不要强制进行转换(即不要把手机的UI强制转换到平板上展示,也不要把平板的UI强制转换到手机上展示)。你有很多种 响应式UI模式 可选择,以便为用户提供良好顺滑的resize体验,并且不需要任何APIs。


建议5:

被其他应用启动的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,但确实是开始测试的最好的一步。


注:文中出现的 蓝色字体 是超链接,这些链接( 需要梯子 文章都是英文 )比较长,我就没有全部贴出,感兴趣的朋友可以通过最后 阅读原文 查看。






如果你有好的技术文章想和大家分享,欢迎向我的公众号投稿,投稿具体细节请在公众号主页点击 “投稿” 菜单查看。


欢迎 长按下图 -> 识别图中二维码 或者 扫一扫 关注我的公众号:








请到「今天看啥」查看全文