Activity你该懂的

本文不适合入门新手,适合进阶者阅读。

0. 提问

  • onStart和onResume有什么区别?onPause和onStop有什么区别?打开一个新Activity时的回调顺序?
  • 4种启动模式的含义?
  • 任务栈的作用?Activity一定会放入其taskAffinity属性所声明的栈中吗?

一. 生命周期

1. 顺序

Activity Lifecycle

2. 详细作用

  • onCreate:生命周期内只调用1次,用于初始化界面、必要对象创建、基础逻辑、恢复数据、注册广播等
  • onStart:界面由完全不可见(不包括被透明界面遮挡)变为可见时调用,利用这个特性处理一些业务逻辑
  • onResume:界面可点击交互,不被顶层其他任何Activity遮挡;开始执行界面交互操作
  • onPause:界面不可点击交互,被其他Activity遮挡,部分可见;此时应当停止交互相关等耗资源的操作,如动画、相机等
  • onStop:界面完全不可见;保存重要数据,而不在onDestroy中执行,因为Activity在后台时进程被杀,则不调用
  • onDestroy:生命周期内只调用1次,界面完全销毁,用于执行资源释放、反注册广播等
  • onRestart:界面由stopped状态下被再次打开时调用

Tips:注册、反注册应当在成对的生命周期回调方法里执行

3. onStart和onResume?

onStart和onResume都是可见,区分在于onResume可点击交互,用户可以操作界面。

4. onPause和onStop?

  • 当从Activity A打开一个透明属性的Activity B时,A只会调用onPause方法,而onStop不会调用。此时,A处于部分可见状态,但不可交互。同理,此时按返回键关闭B返回A,只会调用A的onResume方法。
  • 从A打开B,若B不带透明属性:方法调用顺序如下:A.onPause → B.onCreate → B.onStart(B开始可见)→ B.onResume → A.onStop。所以两个方法还是有所区分侧重的,两个方法都不当做耗时操作,特别是onPause方法,会影响界面B的打开,所以稍微重点的计算操作方到onStop中,耗时的当然是异步处理。

5. 异常状态下的生命周期

1. 系统配置改变

如屏幕旋转、键盘、语言等等,会触发Activity重新创建。若想要这些改变时,不触发Activity重启,可以通过在AndroidManifest里设置activity的configChanges属性。常用的有locale(语言区域)、orientation(屏幕方向)、keyboardHidden(键盘无障碍功能)、screenSize(当前可用屏幕尺寸发生了变化,旋转屏幕尺寸会触发)。具体参照官网API指南

2. 系统资源不足

Activity优先级从高到低,分3种:
Ⅰ. 前台:可交互
Ⅱ. 可见非前台:比如打开了一个对话框或者透明Activity
Ⅲ. 后台:跳转其他Activity
内存不足时,从低到高进行销毁。

二. 状态保存与恢复

当Activity跳转到其他Activity,或者按Home键后,在后台由于资源不足被系统回收,再次打开时若想恢复原有的数据,则需要通过Bundle进行数据存储与恢复。

  • 保存状态:在onStop方法之前,系统会调用onSaveInstanceState方法,在此处存储状态。
  • 恢复状态:在onCreate方法里进行恢复,要先对参数savedInstanceState进行判空。也可以在onRestoreInstanceState方法里进行恢复,该方法在onStart之后调用,并且只有数据需要恢复时系统才会调用,所以此处savedInstanceState无需判空。

三. LaunchMode-启动模式

1. 设置方法

  1. AndroidMenifest配置:无法设置FLAG_ACTIVITY_CLEAR_TOP标识
  2. 代码中设置intent.addFlags():若与第一种同时存在,则以本方式为准。无法设置singleInstance模式

2. Activity任务栈

  • 用于组合存放Activity
  • 采用“后进先出”的栈结构
  • 栈的拼接:从栈A启动栈B后,按返回键,则先将栈B回退到空之后,再进入栈A。可见图示
    栈的拼接

    栈拼接后,不代表两个栈都合并了,只是返回栈拼接而已。如上图,处于第二步时,若按Home键返回桌面,再按多任务键打开绿色的任务栈,这时候两个任务栈不再拼接,按返回键后,退出绿色的栈后返回桌面。同理,若多任务键切换到蓝色的栈,栈的顶部也不会有绿色的栈的内容。

Home键回桌面打开应用、多任务键切换任务栈,都是直接打开目标任务栈,之前的栈的拼接都会失效。

  • 查看信息命令: adb shell dumpsys activity

3. LaunchMode的4种类型

  1. standard:标准模式:每次启动一个Activity都会创建一个新的实例,并加入到当前任务栈的顶部

  2. singleTop:栈顶复用模式:若打开的Activity位于即将放入的栈的顶部,则复用,不会创建新的实例。按照onPause → onNewIntent → onResume的顺序触发,可以onNewIntent内处理业务。

  3. singleTask:栈内复用模式:Activity A在栈S1,若A打开B(singleTask)

  • B目标栈为S2,S2不存在:则创建S2,并将B加入到栈中。standard和singleTop不具备该特性。
  • B目标栈为S1(或S2),S1(或S2)存在,栈内无B:创建B放入栈顶。
  • B目标栈为S1(或S2),S1(或S2)存在,栈内有B:复用B,清空B之上的Activity,回调onNewIntent方法。
  1. singleInstance:单实例模式:单独位于一个任务栈中,栈中不会有其他Activity,单例,你懂的,还是onNewIntent。

4. 标识Flags

  • FLAG_ACTIVITY_NEW_TASK:效果不等同于"singleTask"!!!(《Android开发艺术探索》此书对于这点有误)

验证方式:Manifest中配置为singleTask的Activity,通过一个application的context来启动一个声明为singleTask的Activity来进行测试,会报错。因为在解析目标Activity属性之前,系统对context进行检测,导致报错,位于源码中的ContextImpl.startActivity方法中。

正确理解如下(通过源码理解测试):

  • 打开的Activity的目标栈如果不存在,则创建栈,并且把Activity放到栈中。

  • 打开的Activity的目标栈如果存在,则再分两种情况:

    • Activity未打开过:创建Activity放入栈顶;
    • Activity已经打开过(无论是否被销毁):
      • 若Activity不在栈顶,只会将该栈移动到前台,不会创建新的Activity。(比如A、B同个目标栈,先打开A,A打开B,此时若B打开A,则是没有反应的,不会跳转到A);
      • 若Activity在栈顶,且是使用Standard模式,则会创建新的Activity实例加到栈顶。
  • FLAG_ACTIVITY_SINGLE_TOP:效果如"singleTop"

  • FLAG_ACTIVITY_CLEAR_TOP:singleTask自带该效果。

特别组合:被启动的Activity使用standard模式,则会将它以及它以上的Activity都出栈,创建新的Activity放入栈中。

  • FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS:不出现在多任务列表中。

5. 应该进入哪个任务栈?(难点)

  1. taskAffinity:官方翻译为亲和关系,而非栈名,表示更倾向于进入哪个栈。所以不是设置了该属性的Activity,就是在属于这个名的栈中
  2. taskAffinity不设置时,则默认为包名;设置为空,则为当前Activity的包名路径
  3. 当A启动一个声明为standard、singleTop的B时,且不带FLAG_ACTIVITY_NEW_TASK,则只会加入到A所在的栈顶,不会加入B所配置taskAffinity所声明的栈顶。
  4. 不严谨的概括:只有singleTask、singleInstance或者带FLAG_ACTIVITY_NEW_TASK等带创建栈能力的方式启动,才会让taskAffinity生效。
  5. allowTaskReparenting这个属性,也会让taskAffinity生效。比如栈S1中的A启动设置了taskAffinity的B,无论B使用什么启动模式,B都会被放入其taskAffinity所声明的栈。

四. 文章引用

本文是在学习了以下文章后,进行案例测试后的总结归纳,强烈推荐阅读以下书籍、博客。LaunchMode这部分知识特别需要代码测验,才能理清几个关键细节。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,242评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,769评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,484评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,133评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,007评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,080评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,496评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,190评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,464评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,549评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,330评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,205评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,567评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,889评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,160评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,475评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,650评论 2 335

推荐阅读更多精彩内容