Activity的生命周期和启动模式

来源:互联网 发布:维斯布鲁克数据库 编辑:程序博客网 时间:2024/06/14 04:09

本文为Android开发艺术探索一书的第一章总结,文中所记内容都是我觉得有必要或者之前没注意过的问题,并没有面面俱到。另外关于文中一些感觉不太对的内容,我也记在了问题一栏。

1 笔记

1.1 关于Activity的正常生命周期

Activity的生命周期在正常情况下有onCreate,onStart,onResume,onPause,onStop,onDestroy六个回调。其中onCreate初始化数据,onStart时Activity已经显示出来了,但是还不在前台,而onResume时出现在前台,可以与用户交互。onPause表示即将离开前台,由于onPause之后新Activity的onCreate到onResume会被调用,所以只可以做一些轻量级的回收工作(如停止动画,存储数据),否则页面切换会出现卡顿现象。onPause之后如果Activity变得不可见则会执行onStop(此处有问题1),可以进行稍微重量级的回收工作。最后会执行onDestroy,执行回收工作和资源释放。

1.2 Activity的配置发生变化

当系统发生配置变化时(如屏幕方向orientation,语言locale,键盘是否可见keyboardHidden等),Activity会进行销毁并重建,但是会在正常的生命周期中的onPause前后(可能前也可能后),onStop之前插入onSaveInstanceState以保存当前Activity的状态,并在onStart之后插入onRestoreInstanceState恢复存储的状态数据(具体可以保存和恢复的数据见各个View的重写方法)。如果不想重建Activity,可以通过在manifest中设置Activity的configChanges=“orientation|locale|keyboardHidden|screenSize”来解决。关于什么时候会调用onSaveInstanceState有问题,见问题2

1.3 Activity的启动模式

(1)SingleTask:可以用来限制Activity只存在于一个栈中并且该Activity只能存在一个实例。如果实例已经存在,则不会onCreate和onStart等,而是直接调用onNewIntent。
(2)SingleInstance:标注的Activity只存在于一个栈,且栈中无其他Activity。
(3)SingleTop:当栈顶已经存在该Activity时,只会调用onNewIntent。当快速点击按钮或者listview跳转页面(比如从一览到详细画面)时,可能会生成两个新Activity,我用这个flag进行限定,不知道大家是怎么做的?

1.4 Activity的Flags

(1)New_Task:有问题见问题4。用NEW_TASK启动一个Activity(LaunchMode为Multiple或者SingleTop)时,如果被启动的Activity的Affinity与当前Activity的Affinity不同,则会为新Activity创建一个新栈。如果Affinity相同,则在当前栈顶追加新的Activity。但是如果已经存在由该Activity作为root启动的栈的话,则会直接将该栈移到前台。
(2)Single_Top:参照LaunchMode的SingleTop
(3)Clear_Top:如果当前栈中已经存在该Activity,则会首先清除该Activity以上的Activity,接下来的行为有两种:一是如果LaunchMode为Multipel且flag没有Single_Top,则当前Activity被finish然后重建。其他情况,当前Activity被调用OnNewIntent。
(4)Exclude_From_Recents:文中说是不会出现在历史Activity中,不知道和No_History是不是一样,见问题5

1.5 IntentFilter匹配规则

IntentFilter中包含Action,Category和Data三种内容。无论是进行queryIntentActivities或者startActivity,都需要匹配这三者的内容,但是每一项的匹配原则有所不同
(1)Action:Intent中一般都存在一个Action,匹配的条件是该Action和IntentFilter中Action(可能有多个Action)的任意一个相同即可。
(2)Category:Intent中如果存在Category,则每一个Category都必须在Filter中找到对应项,否则匹配失败。如果Intent中不存在Category则也算作匹配成功。但是有一点需要注意,startActivity和startActivityForResult会自动在Intent中添加Category_Default,所以如果你想要自己的Activity能被检索并迁移到,需要在Filter中加上Default这个Category。
(3)Data:Data中包含两项内容:MimeType和URI,URI的格式是这样的:
scheme://host:port/[path/pathPattern/pathPrefix]
例:http://172.168.1.101:8080/filelist
MimeType是指媒体类型,如image/jpeg,video/mpeg,message/rfc822等字符串。文中此处过于简略,关于Data匹配的详细说明见此
https://stuff.mit.edu/afs/sipb/project/android/docs/guide/components/intents-filters.html
简单概括一下:
(1)Intent没有URI和Type,只能匹配同样都没有的IntentFilter
(2)Intent只有URI且Type不能从URI推测出来,只能匹配只含有URI的IntentFilter
(3)Intent只有Type,只能匹配只含有Type的IntentFilter
(4)Intent中两者都有(或者只有URI但是Type可以推测也算),则只能与同时含有Type和URI的IntentFilter匹配成功。但是要注意,如果IntentFilter中只含有Type,此时Filter中的URI默认支持Content:和file:这两种URI,所以Intent中的URI只要是其中之一则匹配成功。


2 问题

2.1 从A画面迁移到B画面(式样透明),A画面会由于仍然可见不会调用onStop?
经过验证,如果B画面透明的话,A画面确实不会调用onStop,只会调用onPause。也证实了onStart和onStop用于可见性的变化,onResume和onPause用于用户交互的变化(是否位于前台)。


2.2 p13最上一段说:onSaveInstanceState只有在Activity被销毁且有机会重新显示的情况下才会被调用(也就是比如说旋转屏幕)。但是我有看过在正常启动新Activity时,当前Activity也会调用onSaveInstanceState以确保如果之后被系统强制关闭,再次启动时能恢复状态的说法,经过测试也确实如此。


(3)p20最上的一段:
应用A启动应用B的ActivityC(allowTaskReparenting=true),再按Home回到桌面,然后按B的图标启动B,但是显示的是ActivityC,我要确定一下B的主Activity有没有被启动。
经过确认,确实当B启动时,ActivityC会从A的栈移动到B的栈顶,root为应用B的主Activity


(4)p27关于New_Task和Single_Task的效果相同这点
文中已经提到了New_Task的效果,和作者所述并不相同。况且如果和Single_Task的效果相同,那么在启动一个作为root存在的Activity时,应该会将该Activity以上的Activity全都出栈才是,而非直接将该栈移到前台。


(5)Intent的Flag中的Exclude_From_Recents的具体作用和表现?
在Manifest中为应用的主Activity添加该属性后,当应用被切换到后台时,无法通过“最近使用过的应用”窗口返回前台(因为找不到你的应用),只能通过应用图标,其他没有什么变化。

0 0