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 ...
随机推荐
- Core Animation 学习
core animation 是在UIKit层之下的一个图形库,用于在iOS 和 OS X 实现动画. Core Animation管理App内容 core animation不是一个完整的绘图系统, ...
- excel导入记录
use DangJianSELECT vale1, value2 into Table2 from Table1 select COUNT(*) from tmpdangyuan where 手机号 ...
- Linux的一些命令
程序 # rpm -qa # 查看所有安装的软件包 系统 # uname -a # 查看内核/操作系统/CPU信息 # head -n 1 / ...
- iOS-NSDate
一.概念解释 1.什么是NSTimeZone? NSTimeZone:时区是一个地理名字,是为了克服各个地区或者国家之间在时间上的混乱设定的. 1).GMT:0:00格林威治标准时间:UTC +00: ...
- [python]python元类
这两天在看Django框架,里面的filter实现原理搞不明白,最后发现跟python的元类有关系. 原文:http://stackoverflow.com/questions/100003/what ...
- android高级---->AsyncTask的源码分析
在Android中实现异步任务机制有两种方式,Handler和AsyncTask,它在子线程更新UI的例子可以参见我的博客(android基础---->子线程更新UI).今天我们通过一个小的案例 ...
- sitemesh学习笔记(2)
之前我也是通过网上一些资料来学习sitemesh的,后来发现那些资料都比较老了,现在最近的已经是sitemesh3了而我之前看的是sitemesh2.3,今天重新去看了一些sitemesh3的资料,发 ...
- jQuery $.extend() 和 $.fn.extend() 用法
http://blog.csdn.net/xuemoyao/article/details/19021659
- csharp: Data binding in WPF DataGrid control
<Window x:Class="WpfProjectDemo.MainWindow" xmlns="http://schemas.microsoft.com/wi ...
- ERROR 2002 (HY000): Can’t connect to local MySQL server through socket ‘/var mysql 启动不了
ERROR 2002 (HY000): Can’t connect to local MySQL server through socket ‘/var mysql 启动不了 ps -A | gr ...