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、自动驾驶等技术。欢迎扫码关注微信公众号:嵌入式企鹅圈,实时推送原创文章!

时间: 2024-10-06 13:08:35

Android Activity使用拾遗的相关文章

android——activity与view

1.       activity, view概述 进行android开发,只需具有java语言基础即可.入门的开发并不需要一些高深的java知识,如Swing,网络,线程,数据库等. 刚开始进行android开发,会觉得android的架构设计得很好,接口简单,模块独立.特别是像我这种C++程序员来说,没有了框架自动添加的很多消息映射宏,窗口的启动,过多复杂的类等.如android应用程序的基本构成就采用MVC模式,界面与逻辑开发独立,程序员可以只专注于程序逻辑开发,美工可以专注于界面设计.

Android——Activity中的六个主要函数

Android Activity中的六个主要函数 Android中一个Activity一般都需要实现六个函数: onCreate(), onStart(), onResume(),onPause(),onStop(),onDestroy(). onCreate函数:注册你要用到的变量,比如说service,receiver,这些变量是无论你的Activity是在前台还是在后台都能够被响应到的,然后调用上面那个用来初始化的函数初始化布局信息. onStart函数:注册一些变量.这些变量必须在And

[转]Android Activity和Fragment的转场动画

Android Activity和Fragment的转场动画 Activity转场动画 Activity的转场动画是通过overridePendingTransition(int enterAnim, int exitAnim)实现的. 这个方法是API Level 5 加入的. 这个方法在startActivity(Intent) or finish()之后被调用,指定接下来的这个转场动画. 方法的第一个参数:enterAnim,是新的Activity的进入动画的resource ID: 第二

Android Activity类讲解(一)

--by CY[[email protected]] 1.protected void onCreate(Bundle savedInstanceState) { throw new RuntimeException("Stub!"); } 当创建一个Activity时,系统会自动调用onCreate方法来完成创建工作.该创建工作包括布局,监听器的绑定等. 首先说一下Bundle 这个类,Bundle是一个键值对,跟Map类似,两个Activity之间的通信可以用Bundle类来实现.

Android Activity和Fragment的生命周期图

Android Activity和Fragment的生命周期图,布布扣,bubuko.com

Android Activity启动模式

在Android的联机文档中,有对Activity的简单介绍,现在通过编写代码对Activity的启动模式做一个深入的理解.在配置文件AndroidManifest.xml中,activity元素的android:launchMode属性用来配置对应Activity的启动模式,目前有以下四种启动模式:1.standard2.singleTop3.singleTask4.singleInstance如果不对Activity设置启动模式,默认就是standard模式 一.standard 请看以下代

我的Android进阶之旅------>Android Activity的singleTask加载模式和onActivityResult方法之间的冲突

今天调试一个bug的时候,情景如下: 一个Activity A,需要用startActivityForResult方法开启Activity B.Activity B的launch mode被设置为singleTask,那么在Activity B开启之后的瞬间(未等B返回任何result),Activity A中的onActivityResult方法就会被调用,并且收到一个RESULT_CANCEL的request code. 然后在ActivityB中做了一些逻辑之后,在Activity B通过

[转]Android:Activity+Fragment及它们之间的数据交换(一)

2014-05-18         来源:Android:Activity+Fragment及它们之间的数据交换(一)   简介: 为什么要用Fragment?使用Fragment可以在一个Activity中实现不同的界面.Fragment与 Fragment之间的动画切换,远比Activity与Activity之间的动画切换变化方式多.很多时候,我们通过使用一个Activity,切换 多个Fragment.本次博客,主要列举一下Fragment与它的Activity之间进行数据交换的方式.

【Android4高级编程笔记】深入探讨Android Activity

创建Activity 要创建一个新的Activity,需要对Activity类进行扩展,在新类定义用户界面并实现新的功能. 视图是用来显示数据和提高用户交互的Ui控件.Android提供了多个布局类,称为ViewGroup,它可以包含多个视图来帮助布局UI.Fragment用来封装UI的各个部分,从而能够方便地创建动态界面. Activity需要在Manifest中对其进行注册.在Manifest的application节点内添加新的activity标签:activity标签包含像标签.图标.必