Android 如何在自己的应用中android 弹出系统键盘的最近任务列表

在交互细节上,Android 与 iOS 有哪些区别?
集思广益,把能想到的区别都添加进来。
按投票排序
在交互细节上有哪些区别,这问题回答起来估计就有难度了!事先声明,文长...... -_-'首先从导航模式开始,iOS 应用大多数情况,只提供单一的路径。无论什么样的程序,都只有一个窗口,这个窗口用于放置程序的内容和功能,用户不会意识到这个窗口。在
iOS 设备中,用户觉得程序就是依次呈现的一屏又一屏图像。可以把一屏图像想象成一个离散的视觉状态或者模态。一个程序拥有的屏数或多或少,每一屏都是各种素材和控件的组合,由此而衍生了iOS 应用内的多种导航模式,如:平铺、列表及树状等。涉及到层级导航通过应用内左上角back键进行返回操作(图1)。图1应用内的导航与系统导航分隔开,iOS应用内一般无「退出」选项,通过实体home按键返回主屏界面及退出应用(手势支持)。Android 2.3和更早的系统依赖于手机硬件的返回键来支持应用程序的导航。Android
3.0 中引入了操作栏,于是出现了第二种导航机制:
“向上”按钮(图2)。图2 向上按钮被用于基于层级关系的应用程序中的界面切换。系统的“返回”按键是基于用户最近查看,以时间倒叙的方式连接的界面历史的导航(但有时候又不遵循这条逻辑)。Android应用导航主要分为以下三类:1.应用程序内的导航
通过多个入口进入到界面
界面内的视图间导航
同一层级的界面间导航2.应用程序外的导航(通过主屏Widgets和通知)
间接通知(通知栏内的消息、mail内的日历等)
弹出通知3.应用程序间的导航
当上一个查看的界面是当前界面的父层级时,点击“返回”按键和点击“向上”按键的结果是一样的。然而,与“向上”按键不同的是,
“向上”按键可以确保用户停留在应用程序中,而“返回”按键可以让用户回到系统首页,甚至会回到另一个应用户程序。图3Android 4.x后采用将四大天王实体键修改为三个虚拟按键(返回、Home、多任务),意在解决Android设备碎片化的问题,并希望能够解决Android一直以为存在的导航问题,但在实际当中该问题依然存在(魅族的Smart bar同样在尝试解决这个问题,通过有效的设计形成与其它手机的差异化)。图4在为Android应用进行设计时,请充分考虑导航问题,避免用户在使用过程中迷失,并且在考虑按钮位置及操作方式时注意Android虚拟键的误操作问题。2. 操作栏(工具栏)iOS工具栏一般处于屏幕的底部,但iPad端也可能出现在顶部。工具栏上的控件等宽放置。控件会随着屏上内容的切换而改变,因为内容与用来操纵它的控件是匹配起来的。在工具栏上放置当前情景下用户最常用的功能。每个工具栏上的控件至少要保持
44×44 points的面积(Retina屏宽高均提高2倍
one point equals two pixels ),方便用户操作。图5Android操作栏是 Android
应用程序的最重要的结构元素。它几乎在应用程序的每个界面的顶部都有一块专用的区域(图6)。 图6大多数应用程序的操作栏被划分为四个不同的功能区域 :1.应用程序的图标:图标能够帮助用户对应用进行识别,如果当前显示的不是应用程序的最高层界面,保证在图标左边显示“向上”符号。
2.视图控件 :如果你的应用程序在不同的视图展示内容,操作栏的这个部分可以允许用户切换视图
3.操作按钮
:操作栏里的操作按钮会展示你的应用程序的最重要的操作。4.更多操作 :把不常用的操作放到更多操作里。 Android 3.0在某些应用界面引入了长按进入选择模式,4.x后对选择模式进行了改良引入了情境操作栏(CAB,contextual action bar),与操作栏出现在同一个位置(图7),后面会与iOS的编辑模式进行比较。图7Ps. Android里也有底部操作栏,但仅为顶部操作栏的扩展,官方称为「Split Action Bar」(图7)。图8在进行设计的时候需要考虑操作栏如何适应不同的屏幕方向和屏幕尺寸,进行动态的调整以达到最优的效果。3. 多任务iOS通过双击Home键及四指手势激活多任务选择器(图6)。大多数程序在转移到后台的时候,会被挂起。被挂起的程序会展示在“多任务选择器
(multitasking
bar)”中,帮助用户快速找到近期使用的程序。当用户重启挂起的程序时,它能够从退出时所在的那个点迅速恢复,无需重新渲染界面。 当用户激活多任务选择器后:1.向左滑动,查看更多其它任务。2.向右滑动(首屏任务界面),
进入侧快捷面板区域。3.长按任务,进入删除模式。图9为iOS 应用进行设计时,请考虑iOS双层状态栏(double-high status bar),显示当前正在进行的任务:通话中、录音中等,应用布局不会因高度的变化而出现问题。Android的多任务界面提供了一个最近使用的应用程序之间切换的有效方式。并被赋予一个独立的虚拟按键,位于导航栏的最右侧,用以显示用户最近使用的应用程序及任务,它们通过时间顺序进行组织排列,最近使用的应用程序放置在近期任务界面的最底部。 近期任务管理,当用户点击近期任务按键后:1.选中任务左/右滑动,删除任务。2.长按任务,将弹出任务弹窗,「从列表中删除」、「应用信息」图104. 通知中心早期iOS系统并没有通知中心,后引入Android系统中通知中心设计,这是一种能够使用户更为简单、方便的查看各种通知信息的方案。用户通过手指从顶部边缘下滑激活通知中心(与Android一样),在应用全屏时用户需要两次操作才可激活通知中心(防止误操作)。用户在通知中心内可实现应用间的调用或跳转,需要通过iOS的多任务才可返回之前应用(Android采用系统的back键,导致应用与应用之前的逻辑复杂性的增加)。通知中心一般承载以下类型信息:1.消息。2.事件。3.更新。4.状态图11通知中心是早期Android系统中的优秀设计,在之后的更新中也不断被赋予新的意义。Android的通知系统被设计为当用户聚焦某个任务时能快速告知用户一些事件,但还是应该谨慎决定创建一个通知。用户在通知中心内实现应用间的调用或跳转,但需要详尽考虑Android系统导航「back」、「up」对跳转逻辑的影响。因Android的开放性,导致通知中心所显示的信息可进行相应的设计,但需注意以下几条:1.使其私有化
。2.导航到正确的地方 3.对时间敏感事件请增加时间戳
4.对通知进行合并5.自我清理,如某个事件在具体时间发生,过期后该通知可能对用户来说并不重要。6.使用不同的图标或提示。图12写到这插个题外话,微软的Win8木有通知中心的设计,不知道是因为赶工还是设计理念的原因,导致Surface平台的通知有点像早期iOS的情况,Win8主要依靠三种通知方式进行提示:1.屏幕右上角通知。 2.锁屏界面的更新和详细状态。 3.「开始」屏幕上的磁贴。5. 通知方式目前iOS中的通知具体有四种方式:1.条幅式通知。2.弹出式通知。3.Icon右上角消息式通知。4.声音通知。每种通知方式给用户的通知强度及心理影响均不同,在设计时考虑希望给用户呈现的消息级别及相对应的通知强度。应用的通知及是否显示在通知中心,用户均可在设置中进行设置,请谨慎使用通知,不要让用户感到困扰及厌烦。图13Android中的通知具体有以下四种方式1.通知区域提醒。2.进行中的通知3.弹出式通知。4.提示条通知。其中弹出式及提示条通知仅在当前运行的应用中出现,显示需要用户立即处理的任务或提醒。进行中的通知可让用户了解正在后台运行的进程。例如音乐播放器会在通知系统里一直显示
当前正在播放的曲目直到用户手动停止播放。在顶部状态栏通知区域以图标表示最近的通知,打开通知中心即可查看这些通知,平板电脑通知区域被集成到屏幕底部的系统栏中。图146. 编辑模式(选择模式)iOS应用在可供用户编辑的界面一般通过Table view的「编辑」键进入编辑模式,进入编辑后顶部导航栏发生变化,根据内容的不同出现不同的编辑选项,允许对内容进行多项,执行操作时将应用到多项所选内容,在编辑项过多时,可采用底部操作栏的设计。用户在编辑模式下执行完编辑后点击「完成」退出当前模式。图15Android通过长按进入选择模式,选择内容后出现的情境操作栏(CAB)是一个覆盖在你的应用程序当前操作栏上的临时操作栏,它在用户长按某个可被选择的内容项后出现(图7,往上找哦)。 进入选择模式后,通过点击可选择多个内容项,在情境操作栏触发一个操作会应用到所有被选中的内容,执行操作后将退出选择模式,情景操作栏也随着消失。应用程序需要支持同时选择多个内容项时,Android官方建议使用情境操作栏,并对长按手势进行预留。图16iOS在文本视图、web 视图和图片视图里调出编辑菜单,来执行剪切、粘贴和选择等操作,菜单出现在需要进行处理的内容附近,与内容产生关联,轻量的悬浮式设计避免了模式化的状态(用户可点击任何区域取消悬浮菜单)。应用程序可调整菜单的行为,给用户更多控制内容的操作。图17Android可以在文本框及其它文本视图中长按选择任何文字,这个操作会触发一个文本选择模式,便于扩展选择或对选定文本进行操作。同样,该选择模式会激活情境操作栏。Android 4.x对选择滑块的处理很优秀,便于用户选择,能够精确进行定位,单滑块进行光标定位时尤为管用。图187. Widgets(小部件)这个应该先从Android谈起,Widgets一直是Android系统的亮点(个人不太喜欢,可能是因为Android系统的复杂性),Android系统导航层级就分为了主屏幕和应用列表,主屏幕是一个可定制的区域,用以放置应用程序的快捷方式、文件夹、及Widgets,通过用户左右划动屏幕切换到不同的主屏幕面板。 应用列表内区分为App区域及Widgets区域,随着用户安装的应用越来越多,相应的Widgets也越来越多... -_-'
一个应用可以弄多个不同size的Widgets,好像又有点扯远了!Android系统的Widgets分为以下四种类型:1. 信息型Widgets2. 聚合型Widgets3. 控制型Widgets4. 混合型Widgets图19iOS平台可能大多数人觉得并没有Widgets的概念,通知中心内的天气及股票可以算是iOS对Widgets的试水(个人感受),虽然简单,但相信应该会在未来看到iOS对这一方面更深入的尝试吧。 ^_^8. Tab栏iOS的Tab栏用于切换子任务、视图和模式。Tab栏位于屏幕的底部,并且始终可见。Tab 栏上展示图标和文字,当用户选中某个tab时,这个tab处于高亮状态。在 iPhone 上,tab 栏一次只能显示 5 个以内的页签。如果程序需要更多的tab,tab栏可以展示前四个,第五个放置「更多」,用列表的方式呈现其余的项目。 图20Android的Tab栏用于探索和切换不同视图或功能,也可用于浏览不同分类的内容集合。主要有三种tab类型:1. 滚动tab2. 固定tab3. 堆叠tab图21头又开始痛了,不想写了,就到这吧... T_T两个系统还有很多细节上的不同,像Android的边界反馈效果与iOS的回拉效果、Activity Indicator的对比、dialog上确认键两个系统分别在不同的位置等,以及iOS特有功能上的一些交互特性Passbook、iCloud、iAd等等......Ps.以上每个点均能单独拿出来写个长文
做一下补充和自己的总结,从实际做ios移植到安卓的角度出发:从做app设计上的安卓差异点(设计师需要注意的,一些基础操作尽量用原生控件,否则安卓开发会扎你小人的)1.编辑a)安卓采用长按出浮层,而非ios的滑动删除(但通知中心是滑动删除的)b)安卓的下拉菜单样式是右下角的小三角,并紧贴浮现,而非ios的上拉滚轮盘,见下图2c)安卓的选择以弹出浮层为主,而非ios的上拉选择盘2.操作栏a)安卓操作或tab均放上方,以免与虚拟键盘冲突,而非ios的下方,但许多安卓应用也按ios的来设计,因此这个点的设计更改可以酌情考量;b)需要为安卓菜单设计呼出的内容,一般是全局导航;c)需要为安卓搜索设计应用内的搜索;3.搜索,上文没有提到这个安卓的搜索完成按钮一般不明显,最好在搜索框后放置搜索按钮;4.拍照模块安卓的拍照页面无法提前为取景框加边框。从设计处理上不知道有没有更多的设计点呢?系统上的差异比如硬件的返回,但是界面中同样也可以有返回,因此设计上无需特意改变,设计师心知即可;多任务的唤出;等等刚开始研究,之后再补充。
根据android4,0规范与IOS规范,android与IOS主要的不容之处表现在:1.android4.0包括三个虚拟按键:返回、home和最近任务,而IOS只有一个物理Home按键,返回按钮一般放置在导航栏左上方2.android的主要操作栏在屏幕上方包括:向上+图标+页面名称+主要操作+更多(次要操作),主要操作栏还提供视图切换功能。IOS包括导航栏、工具栏、tab栏,导航栏包括返回+标题+主要操作,工具栏包括一些次要操作,Tab栏承担页面视图切换的功能。3.android规定tab栏应在屏幕上方,主要操作栏下面,尽量不要放置在屏幕下方,防止与虚拟按键误操作,而IOS的tab栏在屏幕下方4.android长按会出现情境操作栏,对内容项进行选择及内容项的主要操作功能,而IOS很少使用长按功能5.在手势操作上,android可以向左滑动删除单条内容,或滑动屏幕切换不同视图,而IOS向右滑动删除内容,并且提供摇一摇返回等功能。6.界面表现形式不同如:文本输入框、弹出框、选择器、操作按钮图标等但是,可以看到,为了保持用户体验及平台的一致性,以及资源的可重复利用,两个平台在界面布局上应尽量统一,有些app也会打破这些差异性,好多android的app在布局上与IOS相同。
细节太多,最烦人的就几条:iOS 用导航栏左上角的返回钮,android 用户习惯按全局 back 键。Android 见啥都想长按;iOS用户则非常不习惯,只会点来点去。iOS上面捏合手势是标配;Android 上不是跑太快就卡的狠要么没反应,总之各种难过少人用。Android 下边缘有软键,交互元素要离远点;iOS 好点,不过 7 开始也不能划了。
最详细,最仔细的区分可能可以从google和apple的界面参考(规定)里看出苹果的是这个&iOS Human Interface Guidelines&,很详细Android holo的可看腾讯CDC的翻译
第一名的回答已经有不少年头了,随便扯点这()上面的东西都能拿那么多赞=_=容我补充一下MD和ios9……—————————————————————————————————————我从设计语言的高度来分析——MD是机械物理和电磁物理,iOS是镜头运动和景深变化……在material Design中,用户的手指是magnetic(磁铁性),伸出手指把element吸过来,点击泛起ripple(涟漪)。而其他物体是基于一个经典的机械物理模型,在这个机械物理模型中,Android用 elevated surfaces 和shadows表现depth,离你手指越近则越亮且阴影越多,当贴近你手指的时候,就亮到FFFFFF,阴影为24dp。反之离你越远,你按键力度越弱,阴影越少,它越往后面的黑暗中隐没,直至000000。而iOS是驱动作为“镜头”的屏幕运动,靠近或远离物体,由mater view转化为detail view。所以当需要聚焦或者模糊,iOS用blur effect表现depth,所以它不在远近,而在你的焦点,你越需要,它越清晰,你越不需要,它就越模糊,所谓毛玻璃,就是把前景和背景拉开了。就好像人的眼睛,太远了、太近了都看不清……iOS的桌面像个宇宙,特别是基于watchOS之后的系统更像一个寰宇星空,每个APP就是一颗星,每个文件夹就是一片星云。而在这星空中点击APP或者APP的文件夹,就会使iOS镜头远近运动,请想象一个无人机从太阳系的某一处窜入地球,前一秒能看见地球以及它周围的星辰,后一秒就看见了海洋和大气层,这是沉浸式体验。有些还会有浅景深和运动模糊。至于滚动操作确实矛盾……但是iOS也好MD也好,这些设计语言不过是一套物理模型,让用户把客观经验直接移植过来从而更好滴认知,如果这套物理模型有不适合用户的地方,便会修改成理想的状态。所以这些喜欢转牛角尖的设计师不用想不通。设计语言这种模型也会随着设计的发展不断被完善,就像相对论之于经典力学。Android在MD之后出现了一个48dp的原型button像涟漪一样展开,有仿于iOS的沉浸式体验。但在Android系统早期的交互设计中,工程师的文化思想使得他们把一个个APP做成了activitie(活动)的collection(集合)。而每个活动由intent(意图)连接起来,它每次执行一个APP的时候就是launch(页面由下至上出现)。如果给iOS和Android建立一套3D模型图大概是这样ios的父子页面转换是以镜头运动为模型的,它的父子层级是在X轴上左右分布的,它的兄弟视图是Z轴上下分布的,例如知乎for iOS上滑下滑切换下一个回答(参考:)Android,它的父子层级是Z轴上下分布的,兄弟层级是X轴左右分布的,如知乎、GMail的子页面左右滑动切换上下回答或上下邮件(参考:)动画:iOS是pop animation ,Android是Bouncy Animation动画:iOS是pop animation ,Android是Bouncy Animation(参见:)边界反馈:iOS是弹回来,Android是边缘出现一个小圆弧瓣儿手势:Android左右边缘侧滑是drawer,中间部分左右滑是切换tab,而iOS右滑是返回
推荐一个安卓设计与开发全解析的地址:
1、返回的入口不一致,android基本上是硬件返回,iphone则是屏幕软键返回。但这点很可能随着Android4.0的出现而改变;
2、长按为android的一个基本的标配操作,但iOS应尽量避免;这点造成了很多操作上的不一样,例如删除操作,iOS为滑动,android为长按
3、Android有menu键,点击后调出menu菜单,iOS没有;
4、tab的处理上也不一致,因为iPhone没有menu菜单,更多的操作很可能放在最后一个tab里,叫“more”;
5、应用的通知处理也不一致,iOS为图标右上角的小红圈,Android为statuesbar中的滚动显示;
6、iPhone有子tab,android好像还没有看到有,除非是第三方应用自己添加的控件。
我能想到的就这些了
首先,IOS有很多控件都是现成的,并且系统版本比较少。安卓系统的基本都是自定义控件,不同版本不同手机会造成交互效果的很大不同。区别于这两样系统,就要在做需求评审的时候仔细区分,并且分别研究两种手机用户的用户习惯。其实细节很多,但是大多数情况自己死记硬背是学不来的,只有在工作和实践中提升!!
两者的本质区别是,IOS UI是一款的产品,用户可以立即使用。 Android UI是一个设计参考范例,主要目的是展示Android OS的功能和性能,最终的产品由各个手机厂商在此基础上完成。所以造成了两者细节设计上很大的不同。
总结的不错。不过如果提问者认真想要做好这事情的话。建议做两件事:1、把两个平台的官方规范下载了好好研读下。2、每周至少好好研究一个做的很赞的App,每个平台各一个或者是一个跨平台App的两个版本。
ios拟物,android拟真。ios拟物,android拟真。
田荣荣童鞋说的比较详细了我补充点吧:Android4.0 iOS的体验正在趋向一致,比如在1.x和2.x的Android中menu键的使用和长按按钮的使用在4.0+的版本就不被推荐了,取而代之的是Action Bar以及滑动(类似iOS的那种),也就是不用按键的直接操作体验。
只说一点,滑动屏幕的感受,iOS是最顺畅最自然的。在商场里体验过很多android,滑动的感受总有那么点怪怪的,或者说有点生硬,低配置的还有卡顿等现象。。。
不能在交互设计师面前卖弄,就算吐槽一下android。做交互设计的时候要适当注意android硬件有实体按键,和虚拟按键,设计不好误操作很多。android在4.0之后引入了标准设计规范,之前没有任何规范可言,完全野蛮生长。用户使用过程中养成积累的操作习惯很难短期按照规范的路线走,这个用户群体还很大。请适当的注意围观4.0+系统的用户情绪。
Android的硬件返回键,我喜欢IOS太追求精简了,一个HOME键总觉得麻烦
Android的交互设计有统一的趋势,用户使用时的逻辑是统一的,iOS没怎么用过不好多说,不过在某些情景下很讨厌(比如全屏游戏中突然蹦出来个通知栏,这个在玩水果忍者类的游戏的时候很困扰;还有“多任务”切换/最近任务删除很反人类,一个是调出那个的时候需要连续按两下Home键严重降低物理按键寿命,还有就是那个删除最近任务的X图标太小对于手大的人来说就是噩梦;ETC.)
1 iOS只有一个物理键,android有三个物理键2 iOS和android的底层交互设计不同所以开发前要仔细研究开发文档,android4.0有很多设计有些借鉴winphone和iOS,ios也有借鉴android的地方,比如通知。这样其实很好,用户从一种系统到另一种系统很快上手。
android的机型太多屏幕太多甚至卡的情况都有区别……开发难度增加……还是iOS开发更便捷!
anroid的交互在一些细节上,相比IOS来说做得并不是太好,,而一些Android的APP不仅仅是设计风格的问题,在交互上面也比较混乱。虽然说在android4.0之后已经将用户的交互统一设置了,但是还有很多碎片化的问题,无处不在功能菜单,和没有必要的重复的菜单,比如一些APP在同一个交互层面上就有三个菜单当中存在设置这个选项,为了保持一致性的风格,而使得交互变得混乱。菜单要在有必要的时候才添加,添加时哪些功能是必须存在的都要考虑清楚。还有在一些APP当中,添加上手势操作,也要考虑和APP的契合度问题,不要有了新的交互模式就要加入进去。对Android近期任务列表(Recent Applications)的简单分析
编辑:www.fx114.net
本篇文章主要介绍了"对Android近期任务列表(Recent Applications)的简单分析",主要涉及到对Android近期任务列表(Recent Applications)的简单分析方面的内容,对于对Android近期任务列表(Recent Applications)的简单分析感兴趣的同学可以参考一下。
/coding-way/archive//3118732.html
这里的近期任务列表就是长按Home键出来的那个Dialog,里面放着近期打开过的应用,当然3.0以上系统的多任务切换键也是。
这个Dialog的实现在Android源码的/frameworks/base/policy/src/com/android/internal/policy/impl/RecentApplicationsDialog.java中。
接下来就对这个源码分析一下。
public class RecentApplicationsDialog extends Dialog implements OnClickListener {
// Elements for debugging support
private static final String LOG_TAG = &RecentApplicationsDialog&;
private static final boolean DBG_FORCE_EMPTY_LIST =
static private StatusBarManager sStatusB
private static final int NUM_BUTTONS = 8;
private static final int MAX_RECENT_TASKS = NUM_BUTTONS * 2;
// allow for some discards
final TextView[] mIcons = new TextView[NUM_BUTTONS];
View mNoAppsT
IntentFilter mBroadcastIntentFilter = new IntentFilter(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
class RecentTag {
ActivityManager.RecentTaskI
Handler mHandler = new Handler();
Runnable mCleanup = new Runnable() {
public void run() {
// dump extra memory we're hanging on to
for (TextView icon: mIcons) {
icon.setCompoundDrawables(null, null, null, null);
icon.setTag(null);
public RecentApplicationsDialog(Context context) {
super(context, com.android.internal.R.style.Theme_Dialog_RecentApplications);
* We create the recent applications dialog just once, and it stays around (hidden)
* until activated by the user.
* @see PhoneWindowManager#showRecentAppsDialog
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Context context = getContext();
if (sStatusBar == null) {
sStatusBar = (StatusBarManager)context.getSystemService(Context.STATUS_BAR_SERVICE);
Window window = getWindow();
window.requestFeature(Window.FEATURE_NO_TITLE);
window.setType(WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG);
window.setFlags(WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM,
WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM);
window.setTitle(&Recents&);
setContentView(com.android.internal.R.layout.recent_apps_dialog);
final WindowManager.LayoutParams params = window.getAttributes();
params.width = WindowManager.LayoutParams.MATCH_PARENT;
params.height = WindowManager.LayoutParams.MATCH_PARENT;
window.setAttributes(params);
window.setFlags(0, WindowManager.LayoutParams.FLAG_DIM_BEHIND);
//默认显示8个
mIcons[0] = (TextView)findViewById(com.android.internal.R.id.button0);
mIcons[1] = (TextView)findViewById(com.android.internal.R.id.button1);
mIcons[2] = (TextView)findViewById(com.android.internal.R.id.button2);
mIcons[3] = (TextView)findViewById(com.android.internal.R.id.button3);
mIcons[4] = (TextView)findViewById(com.android.internal.R.id.button4);
mIcons[5] = (TextView)findViewById(com.android.internal.R.id.button5);
mIcons[6] = (TextView)findViewById(com.android.internal.R.id.button6);
mIcons[7] = (TextView)findViewById(com.android.internal.R.id.button7);
mNoAppsText = findViewById(com.android.internal.R.id.no_applications_message);
//关键在哪,你懂得...
for (TextView b: mIcons) {
b.setOnClickListener(this);
public boolean onKeyDown(int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_TAB) {
// Ignore all meta keys other than SHIFT.
The app switch key could be a
// fallback action chorded with ALT, META or even CTRL depending on the key map.
// DPad navigation is handled by the ViewRoot elsewhere.
final boolean backward = event.isShiftPressed();
final int numIcons = mIcons.
int numButtons = 0;
while (numButtons & numIcons && mIcons[numButtons].getVisibility() == View.VISIBLE) {
numButtons += 1;
if (numButtons != 0) {
int nextFocus = backward ? numButtons - 1 : 0;
for (int i = 0; i & numB i++) {
if (mIcons[i].hasFocus()) {
if (backward) {
nextFocus = (i + numButtons - 1) % numB
nextFocus = (i + 1) % numB
final int direction = backward ? View.FOCUS_BACKWARD : View.FOCUS_FORWARD;
if (mIcons[nextFocus].requestFocus(direction)) {
mIcons[nextFocus].playSoundEffect(
SoundEffectConstants.getContantForFocusDirection(direction));
// The dialog always handles the key to prevent the ViewRoot from
// performing the default navigation itself.
return super.onKeyDown(keyCode, event);
* Dismiss the dialog and switch to the selected application.
public void dismissAndSwitch() {
final int numIcons = mIcons.
RecentTag tag =
for (int i = 0; i & numI i++) {
if (mIcons[i].getVisibility() != View.VISIBLE) {
if (i == 0 || mIcons[i].hasFocus()) {
tag = (RecentTag) mIcons[i].getTag();
if (mIcons[i].hasFocus()) {
if (tag != null) {
switchTo(tag);
dismiss();
* Handler for user clicks.
If a button was clicked, launch the corresponding activity.
public void onClick(View v) {
for (TextView b: mIcons) {
if (b == v) {
RecentTag tag = (RecentTag)b.getTag();
switchTo(tag);
dismiss();
private void switchTo(RecentTag tag) {
if (.id &= 0) {
// Th it should just go to the foreground.
final ActivityManager am = (ActivityManager)
getContext().getSystemService(Context.ACTIVITY_SERVICE);
am..id, ActivityManager.MOVE_TASK_WITH_HOME);
} else if (tag.intent != null) {
tag.intent.addFlags(Intent.FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY
| Intent.FLAG_ACTIVITY_TASK_ON_HOME);
getContext().startActivity(tag.intent);
} catch (ActivityNotFoundException e) {
Log.w(&Recent&, &Unable to launch recent task&, e);
* Set up and show the recent activities dialog.
public void onStart() {
super.onStart();
reloadButtons();
if (sStatusBar != null) {
sStatusBar.disable(StatusBarManager.DISABLE_EXPAND);
// receive broadcasts
getContext().registerReceiver(mBroadcastReceiver, mBroadcastIntentFilter);
mHandler.removeCallbacks(mCleanup);
* Dismiss the recent activities dialog.
public void onStop() {
super.onStop();
if (sStatusBar != null) {
sStatusBar.disable(StatusBarManager.DISABLE_NONE);
// stop receiving broadcasts
getContext().unregisterReceiver(mBroadcastReceiver);
mHandler.postDelayed(mCleanup, 100);
* Reload the 6 buttons with recent activities
private void reloadButtons() {
final Context context = getContext();
final PackageManager pm = context.getPackageManager();
final ActivityManager am = (ActivityManager)
context.getSystemService(Context.ACTIVITY_SERVICE);
final List&ActivityManager.RecentTaskInfo& recentTasks =
am.getRecentTasks(MAX_RECENT_TASKS, ActivityManager.RECENT_IGNORE_UNAVAILABLE);
ActivityInfo homeInfo =
new Intent(Intent.ACTION_MAIN).addCategory(Intent.CATEGORY_HOME)
.resolveActivityInfo(pm, 0);
IconUtilities iconUtilities = new IconUtilities(getContext());
// Performance note:
Our android performance guide says to prefer Iterator when
// using a List class, but because we know that getRecentTasks() always returns
// an ArrayList&&, we'll use a simple index instead.
int index = 0;
int numTasks = recentTasks.size();
for (int i = 0; i & numTasks && (index & NUM_BUTTONS); ++i) {
final ActivityManager.RecentTaskInfo info = recentTasks.get(i);
// for debug purposes only, disallow first result to create empty lists
if (DBG_FORCE_EMPTY_LIST && (i == 0))
Intent intent = new Intent(info.baseIntent);
if (info.origActivity != null) {
intent.setComponent(info.origActivity);
// Skip the current home activity.
if (homeInfo != null) {
if (homeInfo.packageName.equals(
intent.getComponent().getPackageName())
&& homeInfo.name.equals(
intent.getComponent().getClassName())) {
intent.setFlags((intent.getFlags()&~Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED)
| Intent.FLAG_ACTIVITY_NEW_TASK);
final ResolveInfo resolveInfo = pm.resolveActivity(intent, 0);
if (resolveInfo != null) {
final ActivityInfo activityInfo = resolveInfo.activityI
final String title = activityInfo.loadLabel(pm).toString();
Drawable icon = activityInfo.loadIcon(pm);
if (title != null && title.length() & 0 && icon != null) {
final TextView tv = mIcons[index];
tv.setText(title);
icon = iconUtilities.createIconDrawable(icon);
tv.setCompoundDrawables(null, icon, null, null);
RecentTag tag = new RecentTag();
tag.intent =
tv.setTag(tag);
tv.setVisibility(View.VISIBLE);
tv.setPressed(false);
tv.clearFocus();
// handle the case of &no icons to show&
mNoAppsText.setVisibility((index == 0) ? View.VISIBLE : View.GONE);
// hide the rest
for (; index & NUM_BUTTONS; ++index) {
mIcons[index].setVisibility(View.GONE);
* This is the listener for the ACTION_CLOSE_SYSTEM_DIALOGS intent.
It's an indication that
* we should close ourselves immediately, in order to allow a higher-priority UI to take over
* (e.g. phone call received).
private BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (Intent.ACTION_CLOSE_SYSTEM_DIALOGS.equals(action)) {
String reason = intent.getStringExtra(PhoneWindowManager.SYSTEM_DIALOG_REASON_KEY);
if (! PhoneWindowManager.SYSTEM_DIALOG_REASON_RECENT_APPS.equals(reason)) {
dismiss();
RecentApplicationsDialog.java完整源码
从源码可以看出,关键部分有三处。
一个很关键的内部类:
// 每个任务都包含一个Tag,这个Tag保存着这个App的一些非常有用的信息
class RecentTag {
ActivityManager.RecentTaskI
这个RecentTag保存在每个近期任务的图标里,并且保存着这个任务的原始信息。
刚启动Dialog时对每个任务的初始化:
private void reloadButtons() {
final Context context = getContext();
final PackageManager pm = context.getPackageManager();
final ActivityManager am = (ActivityManager)
context.getSystemService(Context.ACTIVITY_SERVICE);
//拿到最近使用的应用的信息列表
final List&ActivityManager.RecentTaskInfo& recentTasks =
am.getRecentTasks(MAX_RECENT_TASKS, ActivityManager.RECENT_IGNORE_UNAVAILABLE);
//自制一个home activity info,用来区分
ActivityInfo homeInfo =
new Intent(Intent.ACTION_MAIN).addCategory(Intent.CATEGORY_HOME)
.resolveActivityInfo(pm, 0);
IconUtilities iconUtilities = new IconUtilities(getContext());
int index = 0;
int numTasks = recentTasks.size();
//开始初始化每个任务的信息
for (int i = 0; i & numTasks && (index & NUM_BUTTONS); ++i) {
final ActivityManager.RecentTaskInfo info = recentTasks.get(i);
//复制一个任务的原始Intent
Intent intent = new Intent(info.baseIntent);
if (info.origActivity != null) {
intent.setComponent(info.origActivity);
//跳过home activity
if (homeInfo != null) {
if (homeInfo.packageName.equals(
intent.getComponent().getPackageName())
&& homeInfo.name.equals(
intent.getComponent().getClassName())) {
intent.setFlags((intent.getFlags()&~Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED)
| Intent.FLAG_ACTIVITY_NEW_TASK);
final ResolveInfo resolveInfo = pm.resolveActivity(intent, 0);
if (resolveInfo != null) {
final ActivityInfo activityInfo = resolveInfo.activityI
final String title = activityInfo.loadLabel(pm).toString();
Drawable icon = activityInfo.loadIcon(pm);
if (title != null && title.length() & 0 && icon != null) {
final TextView tv = mIcons[index];
tv.setText(title);
icon = iconUtilities.createIconDrawable(icon);
tv.setCompoundDrawables(null, icon, null, null);
//new一个Tag,保存这个任务的RecentTaskInfo和Intent
RecentTag tag = new RecentTag();
tag.intent =
tv.setTag(tag);
tv.setVisibility(View.VISIBLE);
tv.setPressed(false);
tv.clearFocus();
...//无关紧要的代码
这里的过程是:先用ActivityManager获取RecentTasks并生成一个List,然后利用这个List为Dialog中的每个任务初始化,并生成对应的信息RecentTag。
需要注意的是,RecentTag中的Intent是从对应任务的原始Intent复制过来的,这意味着那个原始Intent的一些Extra参数将会一并复制过来,
我来举个例子:比如我的App支持从第三方启动,并且第三方要提供一个token,当然这个token就以Extra参数的形式放进Intent里,然后通过startActivity()启动我的App;然后我的App根据这个token来处理,注意这里,当我的App退出后,再从近期任务里启动这个App,之前的那个token还会传递给我的App,这里就会出现错误了,原因就是上面分析的。这就是为什么从第三方跳转的应用不会出现在近期任务的列表里(比如点击短信里的url启动一个浏览器,之后近期任务里只有短信app,不会出现浏览器app)。要想不出现在近期任务里,可以给Intent设置FLAG_ACTIVITY_NO_HISTORY标志。
响应每个任务的点击事件:
private void switchTo(RecentTag tag) {
if (.id &= 0) {
// 这个Task没有退出,直接移动到前台
final ActivityManager am = (ActivityManager)
getContext().getSystemService(Context.ACTIVITY_SERVICE);
am..id, ActivityManager.MOVE_TASK_WITH_HOME);
} else if (tag.intent != null) {
//task退出了的话,id为-1,则使用RecentTag中的Intent重新启动
tag.intent.addFlags(Intent.FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY
| Intent.FLAG_ACTIVITY_TASK_ON_HOME);
getContext().startActivity(tag.intent);
} catch (ActivityNotFoundException e) {
Log.w(&Recent&, &Unable to launch recent task&, e);
如果该Task没有退出,只是切到后台,则切换到前台;如果已经退出,就要重新启动了。
这里的Intent就是之前说的,重复使用的旧Intent了,这里注意,系统添加了FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY和FLAG_ACTIVITY_TASK_ON_HOME标志,所以我们可以在App中通过判断Intent的flag是否包含这两个来判断是否是从近期任务里启动的。注意FLAG_ACTIVITY_TASK_ON_HOME标志是Api 11添加的,所以11一下的之判断FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY就行了。
本文标题:
本页链接:

我要回帖

更多关于 android 最近任务列表 的文章

 

随机推荐