一、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使用拾遗的更多相关文章

  1. Android:Activity+Fragment及它们之间的数据交换.

    Android:Activity+Fragment及它们之间的数据交换 关于Fragment与Fragment.Activity通信的四种方式 比较好一点的Activity+Fragment及它们之间 ...

  2. Android Activity launchMode研究

    Android Activity launchMode研究 Activity的Launch mode一共有四种: standard, singleTop, singleTask, singleInst ...

  3. android Activity类中的finish()、onDestory()和System.exit(0) 三者的区别

    android Activity类中的finish().onDestory()和System.exit(0) 三者的区别 Activity.finish() Call this when your a ...

  4. Android Activity的生命周期简单总结

    Android Activity的生命周期简单总结 这里的内容参考官方的文档,这篇文章的目的不是去总结Activity是如何启动,如何创造,以及暂停和销毁的,而是从实际开发中分析在Activity各个 ...

  5. Android Activity返回键控制的两种方式

    Android Activity返回键监听的两种方式 1.覆写Activity的OnBackPressed方法 官方解释: Called when the activity has detected ...

  6. Android Activity和Fragment的转场动画

    Android Activity和Fragment的转场动画 Activity转场动画 Activity的转场动画是通过overridePendingTransition(int enterAnim, ...

  7. android Activity生命周期(设备旋转、数据恢复等)与启动模式

    1.Activity生命周期     接下来将介绍 Android Activity(四大组件之一) 的生命周期, 包含运行.暂停和停止三种状态,onCreate.onStart.onResume.o ...

  8. Android Activity的加载模式和onActivityResult方法之间的冲突

    前言 今天在调试程序时,发现在某一Activity上点击返回键会调用该Activity的onActivityResult()方法.我一开始用log,后来用断点跟踪调试半天,还是百思不得其解.因为之前其 ...

  9. Android Activity的onSaveInstanceState() 和 onRestoreInstanceState()方法:

    Android Activity的onSaveInstanceState() 和 onRestoreInstanceState()方法: 1. 基本作用: Activity的 onSaveInstan ...

随机推荐

  1. 利用 word2vec 训练的字向量进行中文分词

    最近针对之前发表的一篇博文<Deep Learning 在中文分词和词性标注任务中的应用>中的算法做了一个实现,感觉效果还不错.本文主要是将我在程序实现过程中的一些数学细节整理出来,借此优 ...

  2. 创意欣赏:20幅字体排版(Typography)素描

    通常我们都只关注最终的作品,但其实幕后还有很多的过程,其中一个是素描.素描用来表达最初思想观念的原型.有时客户需要一个独特的品牌新LOGO或字体,这时先绘制在纸上是比较方便的,之后扫描到 Photos ...

  3. Android学习笔记之图片轮播...

    PS:一个bug又折腾了一个下午....哎... 学习内容: 1.Android利用ViewPager和PagerAdapter实现图片轮播... 2.使用反射机制获取Android的资源信息... ...

  4. 如何彻底的卸载和删除Windows service

    最近遇到很头疼的问题,安装到服务器的Windows Service卸载的时候出错了,结果在服务列表中就一直驻留,并且系统进程一直在运行,怎么都杀不掉. 最后终于找到办法了: 1.常规做法,批处理命令卸 ...

  5. IntelliTrace简介

    解决无法复现bug所使用的策略是在遇到bug时捕获尽可能多的信息,在使用IntelliTrace进行调试时可以充分利用这些信息.最令人称道的一个功能在于bug本身可以自动修复. 打开IntelliTr ...

  6. R语言简单聚类分析

    #以R基础包自带的鸢尾花(Iris)数据进行聚类分析iris data <- iris[,:] #系统聚类法(层次聚类法) distance <- dist(data) #计算距离 iri ...

  7. Math APP 2.0

    首先,我们把这个软件理解成一个投入市场的.帮助小朋友进行算术运算练习的APP. 从质量保证的角度,有哪些需要改进的BUG? 从用户的角度(把自己当成小学生或真的请小学生帮忙),需要在哪些方面进行改进? ...

  8. [CLR via C#]13. 接口

    一.类和接口继承 在Microsoft.Net Framwork中,有一个名为System.Object的类,它定义了4个公共实例方法:ToString, Equals, GetHashCode和Ge ...

  9. oracle中文显示为问号

    在用PL/sql查询时,中文显示为问号.经查证,发现问题为oracle字符集不支持中文导致的.修改oracle字符集,改为支持中文即可. 方法: 第一步:修改注册表. 开始-运行-输入regedit- ...

  10. 详细讲解PHP中缓存技术的应用

    PHP,一门最近几年兴起的web设计脚本语言,由于它的强大和可伸缩性,近几年来得到长足的发展,php相比传统的asp网站,在速度上有绝对的优势,想mssql转6万条数据php如需要40秒,asp不下2 ...