Android Activity使用拾遗
一、onWindowFocusChanged
有时我们需要测量一个Activity多长时间才能显示出来,那么在代码中打点计时的时机选在哪儿呢?在onCreate和onResume执行完成后,Activity的界面仍不可见,在onResume之后,framework还会回调一个叫onWindowFocusChanged的函数,它表示用户是否已经可以与Activity的界面进行交互了。onWindowFocusChanged为true意味着Activity的界面已经能够被用户看到了(自然也能和用户交互了)。实际上activity变为visible的时间点出现在onWindowFocusChanged之前,但是这个状态只能在ActivityManagerService中获取,在客户端还是只能通过onWindowFocusChanged作为界面可见或不可见的标志。
在界面变为不可见时,先调用onPause,然后再是onWindowFocusChanged为false。这也容易理解,onPause本来就是Activity被部分遮住时调用的,调用完onPause后才会让界面不能与用户继续交互。
如果想加快Activity的启动时间,把在onCreate里一些耗时操作挪到onResume里,有时会发现并没有什么变化,所以如果要想先让Activity的界面尽快展现给用户还是得把这些逻辑放在onWindowFocusChanged变为true之后执行。
二、onUserLeaveHint
这个回调函数主要用来监听按Home键退出到桌面的动作,发生在onPause之前。在启动一个新的Activity时,ActivityStackSupervisor里会调用startActivityUncheckedLocked,在它里面会给mUserLeaving赋值。mUserLeaving用于指示当前activity退到后台时函数onUserLeaving是否被调用。
可见,只有当设置了FLAG_ACTIVITY_NO_USER_ACTION标志时mUserLeaving才会为false,其他情况下mUserLeaving均为true,也就是onUserLeaveHint会被调用,注释里也说了onUserLeaveHint会在onPause之前被调用。
三、taskAffinity
task是一组用来处理某一任务的Activity的集合,位于一个回退栈内,当新启动一个应用时framework就会创建一个新的task来承载相应的Activity。taskAffinity用来描述Activity的亲和性,即Activity属于哪个task。如果在AndroidManifest.xml的application中没显式定义taskAffinity,那么缺省的affinity名字就是包名。同一affinity的Activity会被放在同一task里,task的affinity名字由根Activity的taskAffinity决定,如果根Activity没设taskAffinity属性,则affinity就由application的affinity决定。
如果taskAffinity设为空字符串,那说明该Activity和其他的task都不存在亲和性。不同应用的Activity也可以设置相同的affinity,这样当启动后它们就会位于同一task中。
四、launchMode
1. standard
默认的launchMode,可以实例化多次。
2.singleTop
使用这种launchMode的情况是,如果要启动的Activity已经在栈的最顶端,那么startActivity时不再会重新调用它的onCreate,而是调用它的onNewIntent。但如果要启动的Activity不在栈顶,比如A –> B à C,这时C再启动B,就会再实例化一个新的B,栈里面变成A à Bà C à B。
如果A中点击一个button来启动B,但系统反应慢,用户在极短的时间内点了两次,如果是B是standard,则会有两个B,如果是singleTop则只会有一个。更典型的场景是用户使用外卖App支付了一笔订单后,从支付页面返回到订单详情页面,如果订单的状态有发生变化,比如商家接单了,这时通知栏会有通知,点击通知会跳入订单详情页面。如果此时订单详情页面是standard的话,那么用户按back键后发现还是在订单详情页面,体验就很差了。如果是singleTop,只需在onNewIntent里更新状态信息,就可以显示出最新的信息,而不必再新创建一个相同的Activity了。
3.singleTask
以这种模式启动的Activity,如果在task中已经存在该Activity的实例,就调用它的onNewIntent方法,进入该task中。如果没有该Activity的实例,就创建一个新的task,把该Activity作为新task的根Activity。所以以singleTask启动的Activity不一定会新创建一个task。需要注意的是,即使Activity位于新的task里,按back键仍然会回到启动它的上一个Activity中,虽然它们不在同一个task里。
如果singleTask的Activity的taskAffinity和现有task的affinity相同,那就直接在现有的task里创建该Activity,所以以singleTask启动的Activity未必就是位于栈底的根Activity。
4.singleInstance
以这种模式启动的Activity自己独占一个task,如果已经有该Activity的实例,再次启动时会调它的onNewIntent。但以singleInstance启动的Activity按back的行为却与singleTask不同。比如 A启动B,B是singleInstance,B再启动C,则B自己单独位于一个新的task中,A和C位于一个task中,则按back键时,从C不会退回到B,而是先退回到A,再按back键再退回到B。
注意,在代码中也可以设置Intent的flag来控制Activity的启动模式,代码中动态设置的比AndroidManifest.xml中静态写的Android:lauchMode优先级高。
五、Intent的flags
1.FLAG_ACTIVITY_NEW_TASK
为Activity新创建一个task,如果startActivity的context不是Activity,而是service或Application,那一定要加上这个flag。以这个flag启动Activity的行为跟launchMode为singleTask的一致。但并不是每次都新创建一个task,把Activity放在里面,而是会先找是否已经有taskAffinity相同的task,如果有就把要启动Activity放在该task里,如果没有taskAffinity相同的task,才会新建一个task。
2.FLAG_ACTIVITY_SINGLE_TOP
作用同singleTop。
3.FLAG_ACTIVITY_CLEAR_TOP
启动Activity时,如果所在task里已经有该Activity的实例,则会清除在它上面所有的Activity。例如,task里的Activity启动关系是Aà Bà Cà D,然后在D启动B时,加上了FLAG_ACTIVITY_CLEAR_TOP标志,在B启动后task里就只有A和B了,C和D被清除了。如果B的launchMode是standard,那么当它收到Intent后,会先销毁掉原来B的实例,然后重新onCreate构建一个新的B;如果B是singleTask类型,那么会保留原有的B的实例,调用它的onNewIntent,传入新的Intent。
4.FLAG_ACTIVITY_CLEAR_TASK
启动Activity时,会清除所在task里其他所有的Activity。例如,task里的Activity启动关系是A à Bà C,在B启动C时,加上FLAG_ACTIVITY_CLEAR_TASK,那么在C启动后,task里就只剩C了,A、B被清除了。如果这个应用中只有这一个task,那么在C中按back键就退回到桌面了。
5.FLAG_ACTIVITY_REORDER_TO_FRONT
以该标志启动的Activity如果已经在task中存在,会被移动到栈顶,其他的Activity顺序不变。如果在task中不存在,则新建一个。例如,task里的Activity启动关系是A ->B ->C->D,在D启动B时,加上这个flag,则B就被移到了栈顶,task里就变成了A ->C ->D -> B了。如果B已经调了finish,但系统还没来得及把它从task中移出,这时以FLAG_ACTIVITY_REORDER_TO_FRONT方式启动B,则无法启动B。只有当B destroy以后才可以启动B。
6.FLAG_ACTIVITY_NO_HISTORY
这个FLAG可以让启动的Activity一旦退出,就finish掉,不再存在于栈中。例如,Activity的启动关系是A-> C->D,在B启动C时加上FLAG_ACTIVITY_NO_HISTORY,在C启动完D后,task里仍然是 A-> B->C->D的栈布局,C并没从栈中清除。当在D中按back键,不会退到C而是退到B,这时dumpsysactivity会发现task中没有C了,只有A和B,在D中按back键时,C就finish掉了。
7.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS
以这个flag启动的Activity将不会在最近启动的应用列表中出现。
8.FLAG_ACTIVITY_FORWARD_RESULT
我们用startActivityForResult和setResult在两个Activity之间传递数据,如果中间还隔着另一个Activity,比如A -> B->C,要想在A和C之间用startActivityForResult和setResult的话,就要在B启动C时加上这个参数。也就是A正常的startActivityForResult启动B,B以FLAG_ACTIVITY_FORWARD_RESULT方式启动C,在C中setResult,这样当从C退回B,再退回到A,即C和B都finish后,A的onActivityResult会收到C中setResult传的值。
9.FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY
这个是从最近任务列表中启动Activity时由系统设置的,第三方应用不会用到这个标志,系统的SystemUI在最近任务列表中才会设这个标志。
10.FLAG_ACTIVITY_NO_ANIMATION
要启动Activity将不执行入场动画。
11.FLAG_ACTIVITY_TASK_ON_HOME
以这个flag启动的Activity所在的task将会位于Home所在的task之上,也就是说在这个Activity中按back键会回到home,而不是启动它的那个Activity。例如,A -> B,B的taskAffinity与A不同,A启动B时同时加上了FLAG_ACTIVITY_TASK_ON_HOME和FLAG_ACTIVITY_NEW_TASK这两个标志,那么A和B位于不同的task中,如果仅是以newtask方式启动B,那么即使B和A不在一个task中,那么在B中按back键还是会退到A的,但加上了FLAG_ACTIVITY_TASK_ON_HOME后,按back键就退回到home了,此时A已经被移动到了后台。
- 嵌入式企鹅圈原创团队由阿里、魅族、nvidia、龙芯、炬力、拓尔思等资深工程师组成。百分百原创,每周两篇,分享嵌入式、Linux、物联网、GPU、Android、自动驾驶等技术。欢迎扫码关注微信公众号:嵌入式企鹅圈,实时推送原创文章!
Android Activity使用拾遗的更多相关文章
- Android:Activity+Fragment及它们之间的数据交换.
Android:Activity+Fragment及它们之间的数据交换 关于Fragment与Fragment.Activity通信的四种方式 比较好一点的Activity+Fragment及它们之间 ...
- Android Activity launchMode研究
Android Activity launchMode研究 Activity的Launch mode一共有四种: standard, singleTop, singleTask, singleInst ...
- android Activity类中的finish()、onDestory()和System.exit(0) 三者的区别
android Activity类中的finish().onDestory()和System.exit(0) 三者的区别 Activity.finish() Call this when your a ...
- Android Activity的生命周期简单总结
Android Activity的生命周期简单总结 这里的内容参考官方的文档,这篇文章的目的不是去总结Activity是如何启动,如何创造,以及暂停和销毁的,而是从实际开发中分析在Activity各个 ...
- Android Activity返回键控制的两种方式
Android Activity返回键监听的两种方式 1.覆写Activity的OnBackPressed方法 官方解释: Called when the activity has detected ...
- Android Activity和Fragment的转场动画
Android Activity和Fragment的转场动画 Activity转场动画 Activity的转场动画是通过overridePendingTransition(int enterAnim, ...
- android Activity生命周期(设备旋转、数据恢复等)与启动模式
1.Activity生命周期 接下来将介绍 Android Activity(四大组件之一) 的生命周期, 包含运行.暂停和停止三种状态,onCreate.onStart.onResume.o ...
- Android Activity的加载模式和onActivityResult方法之间的冲突
前言 今天在调试程序时,发现在某一Activity上点击返回键会调用该Activity的onActivityResult()方法.我一开始用log,后来用断点跟踪调试半天,还是百思不得其解.因为之前其 ...
- Android Activity的onSaveInstanceState() 和 onRestoreInstanceState()方法:
Android Activity的onSaveInstanceState() 和 onRestoreInstanceState()方法: 1. 基本作用: Activity的 onSaveInstan ...
随机推荐
- 编写高质量JS代码的68个有效方法(十二)
No.56.避免不必要的状态 Tips: 尽可能地使用无状态的API 如果API是有状态的,标示出每个操作与哪些状态有关联 无状态的API简洁,更容易学习和使用,也不需要考虑其他的状态.如: 'tes ...
- Office Web Apps Server 概述
Office Web Apps Server 是新的 Office 服务器产品,它提供 Word.PowerPoint.Excel 和 OneNote 的基于浏览器的版本.单个 Office Web ...
- 我也想聊聊 OAuth 2.0 —— Access Token
这是一篇待在草稿箱半年之久的文章 连我自己都不知道我的草稿箱有多少未发布的文章了.这应该是我在上一家公司未解散之前写的,记得当时是要做一个开发者中心,很不幸. 今天,打开草稿箱有种莫名的伤感,看到这个 ...
- C语言中的经典例题用javascript怎么解?(一)
C语言中的经典例题用javascript怎么解?(一) 一.1+2+3+……+100=? <script type="text/javascript"> ...
- 在做excel导出时如何将excel直接写在输出流中
之前做excel导出时,我都是先将文件写在服务器上,然后再下载下来,后来发现原来可以直接将文件写在输出流里边. 下面是一个小demo: package com.huaqin.fcstrp.util; ...
- Qt Style Sheet实践(一):按钮及关联菜单
导读 正如web前端开发中CSS(Cascade Style Sheet)的作用一样,Qt开发中也可以使用修改版的QSS将逻辑业务和用户界面进行隔离.这样,美工设计人员和逻辑实现者可以各司其职而不受干 ...
- Jcrop简单实用
今天有一个项目的功能需求 “在上传照片的时候能进行裁剪”,网上找了下,发现有Jcrop这款插件,自己试了下,感觉很不错,蛮好用的.又能增加用户体验,测试了兼容性也很好,所以在这里分享下 首先,可以到官 ...
- .net中清理内存,清理占用内存方式方法
#region 内存回收 [DllImport("kernel32.dll", EntryPoint = "SetProcessWorkingSetSize") ...
- 重新想象 Windows 8 Store Apps (67) - 后台任务: 推送通知
[源码下载] 重新想象 Windows 8 Store Apps (67) - 后台任务: 推送通知 作者:webabcd 介绍重新想象 Windows 8 Store Apps 之 后台任务 推送通 ...
- 与众不同 windows phone (38) - 8.0 关联启动: 使用外部程序打开一个文件或URI, 关联指定的文件类型或协议
[源码下载] 与众不同 windows phone (38) - 8.0 关联启动: 使用外部程序打开一个文件或URI, 关联指定的文件类型或协议 作者:webabcd 介绍与众不同 windows ...