(主要参考《Android艺术探索》第一章及其它相关章节)
一、生命周期图 && 一些特殊情况
onCreate()
onStart() onRestart()
onResume()
onPause()
onStop()
onDestroy()
可参考剪藏:Android总结篇系列:Activity生命周期 - Windstep - 博客园
Android activity的生命周期 - hpoi的专栏 - CSDN博客
##特殊情况与补充:
1.当Activity A跳转到透明主题的另一个Activity时,A不会调用onStop(),对应的,回来时也不会调用onRestart()和onStart()。(可以理解为透明主题Activity遮挡对当前Activity的影响,等同Toast、Dialog等的遮挡,毕竟当前Activity并没有完全不可见。)
2.点击back键回退时,生命周期流程为onPause()->onStop()->onDestroy()
3.Actvity A 跳转 Activity B时的生命周期执行流程:
A->onPause()
B->onCreate()
B->onStart()
B->onResume()
A->onStop()
也就是说,前一个Activity的onPause()执行完后,后一个Activity才开始执行生命周期流程,所以为了保证切换速度,onPause()中不能执行耗时的重量级操作。
4.Activity 用户主动关闭后重新打开 && Activity非用户主动关闭而是被系统回收后重新打开,两种情况下执行的生命周期方法相同(都是从onCreate()开始),但执行的具体过程有差别。
在后一种情况,会额外执行一些流程:
4.1关闭时:onSaveInstanceState([Bundle])->onStop()->onDestroy()
其中onSaveInstanceState()与onPause()没有时序上的必然关系。
4.2再次开启时:onCreate([Bundle])->onStart()->onRestoreInstanceState([Bundle])
在前面的onSaveInstanceState()中会把Activity的相关信息保存在一个Bundle对象中,并在重新打开时作为参数传递给onCreate()和onRestoreInstanceState()方法。
4.2.1 正常关闭Activity并重新打开时,onCreate([Bundle])中传入的Bundle对象是空的,非正常关闭重新打开,传入的Bundle才是非空的。正常关闭后重启Activity时,是不会触发onRestoreInstanceState()方法的。
4.3系统通过onSaveInstance()和onRestoreInstance()机制,在重新启动Activity时,会自动地做一些恢复操作操作,包括自动恢复相应的View展示与数据,具体恢复情况跟具体的View种类有关。
因为在onSaveInstanceState()中系统默认执行的操作是,从Window开始,逐级委托下一层View来保存自己的数据。在重新创建Activity时,会逐级恢复各个View的展示。各个View具体的数据保存与恢复操作是自己做的,因此具体恢复成什么样要看View自己的特性和实现逻辑。
4.4触发系统回收分两种情况,一种是“系统配置发生变化”,另一种是内存不足。
4.4.1“系统配置发生变化”情况触发回收时,默认情况下,系统会销毁该Activity并重新创建,自动恢复相应的View展示与数据。
4.4.1.1 可通过配置AndroidManifest中Activity的android:configChanges属性,来设置“当系统某个配置变化时,不销毁该Activity”。常见的属性配置包括:屏幕方向、系统语言、软键盘的弹出隐藏变化 等。
4.4.2内存不足回收Activity时会按照优先级来回收,先回收优先级低的。
优先级顺序如下:前台Activity > onPause()被遮挡的Activity(可见但非前台) > onStop()位于后台的Activity。
另外,不含四大组件的进程也优先被系统回收。
4.5onRestart()触发时机:当Activity执行onStop()之后,但未被销毁,再次回到该Activity页面时,触发onRestart()->onStart()回调。例如点击Home键退到后台再次回到页面时,或者一个任务栈中点击back键弹出顶部的Activity,再次回到下面的Activity页面时。
至于主动跳转到SingleTop、SiingleTask、SingleInstance模式的Activity,应该是触发onNewIntent()->onStart()。
二、Activity任务栈&四种启动模式
任何Activity都被放在某一个任务栈中,这些任务栈由Android系统来管理(todo:查阅任务栈管理机制相关内容)。Android通过任务栈来管理Activity的启动关闭次序。
默认情况下,每次点击back键,此刻的前台任务栈会弹出一个Activity,当一个任务栈为空时,就会被系统回收。
由于不同任务间的Activity可以互相跳转,其回退弹出顺序并非弹空一个栈再弹另一个栈,具体Activity的弹出顺序由“回退列表”来决定。(todo:查阅回退列表的相关内容)
任务栈相关:
一般一个应用启动时,会开启一个对应的任务栈,默认与当前包名相同;但跟Activity的具体设置相关,同一个应用Activity也可以被放入多个不同的任务栈,不同应用的Activity也可以放入同一个任务栈。
个人理解:根据桌面(启动器页面)在与其它任务栈Activity的切换过程,它表现地很像一个单例模式的Activity页面。
用户最初是从桌面(启动器页面)开始,点击启动某个应用,启动了其对应任务栈,然后各种启动、关闭、切换操作,实质上对应的是各种任务栈以及其中Activity的创建、销毁和切换。
点击Home键时,切换到桌面,当前应用页面对应的Activity进入后台,并未被销毁。
Android 任务栈 - 简书
(2条消息)android 任务栈的管理_哲的专栏-CSDN博客_android 栈管理机制
Android任务栈的完全解析_qq_31860607的博客-CSDN博客_android 任务栈
##.四种启动模式的大致特性如下:
1.标准模式(Standard): 每次都重新创建一个实例,放到目标任务栈的栈顶;
2.单顶模式(SingleTop):若目标任务栈的栈顶已经是该Activity的实例A,则直接跳转到A,不再创建新的实例。跳转到A时,会触发onNewIntent()回调方法。
即,目标任务栈的顶部只会有一个当前Activity的实例。
3.单栈模式(SingleTask):若目标任务栈中已存在该Activity的实例A,则直接跳转到A,此过程中任务栈中A上面的Activity都会出栈,最后A位于栈顶。同样,会触发A的onNewIntent()回调方法。
即,目标任务栈中只会有一个当前Activity的实例。
4.单例模式(SingleInstance):若系统中已经存在该Activity的实例A,则直接跳转到A,触发其onNewIntent()方法;否则创建该Activity的实例B,放到一个单独的新任务栈中,并且跳转到实例B。
即,整个系统中只会有一个当前Activity的实例,它位于一个单独的任务栈中。
##.额外补充说明:
1.Activity的目标任务栈:
一个Activity的目标任务栈默认情况与包名相同。如果要自定义,只有在SingleTask模式下自定义才有效,由属性android:taskAffinity来设置,如果设置了android:taskAffinity,则设置的值不能等于当前包名。
todo:了解一下allowTaskReparenting属性。
注:应用包名由AnroidManifest.xml文件中package属性来设定,例如:
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.xxxx.xxxx"
……..>
……….
……….
</manifest>
2.通过Java代码和AndroidManfest.xml都可以设置一个Activity启动时的启动模式。若二者同时存在,则在执行中第二种方式的优先级更高。
但注意,java代码模式无法设置SingleInstance模式,xml方式无法设置出FLAG_ACTIVITY_CLEAR_TOP标记位对等的效果。
xml中设置方法:android:launchMode=“xxx"
Java中设置方法:Intent.setFlags(xxx|xxx);
3.在理解上,个人的理解:
启动模式,故名思议,用什么样的方式去启动目标Activity。
这个方式既可以由Intent来说明(Java代码中设置Intent属性),也可以由目标Activity来说明(AndroidManifest.xml中)。
最终的执行过程,与选择的启动参数有关,也与当前任务栈当前具体情况有关。
以下为个人根据相关资料并实际运行测试后的一些相关理解:
3.1xml静态设置的参数,与Activity绑定,表示每次都以什么方式启动;而java代码中设置Intent标记位参数只跟“本次启动操作”绑定。
从这个方面也就可以理解:为何xml可以设置任意启动模式,而java方式无法设置SingleInstance模式,也无法完全等价地设置SingleTask模式。因为xml方式的优先级高,无论设置成任何模式,每次启动都是自洽的。 而java方式同一个Activity的不同实例启动时,所用的启动模式有可能不同,使用SingleInstance、SingleTask模式启动时可能与其它模式启动时产生冲突。
3.2SingleTop模式只是去检测栈顶是否有相应示例,并做相应操作。
3.3java代码中设置FLAG_ACTIVITY_NEW_TASK,作用并不等同xml中设置android:lanchMode=singleTask,实际运行的时候发现单独设置该标记位,什么特殊作用都没发生。
当设置FLAG_ACTIVITY_CLEAR_TOP | FLAG_ACTIVITY_SINGLE_TOP时,作用才类似xml中设置singleTask。不过这种方式不能保证一个栈中只有一个目标示例,它只是在栈中找到最上面的那个实例,并把上面的其它Activity实例都弹出。
在xml中设置android:lanchMode=singleTask, 才能保证栈中单实例,因为这样每次启动该Activity时,都是以singleTask方式启动的。
3.4SingleInstance模式只能在xml指定,也就是说要么不设定这种模式,要么就每次都是这种模式启动。无法通过java代码来动态设置每次的启动模式。
3.5当启动Activity时,若创建了新的A实例,则触发onCreate()->onStart()流程;若未创建新的A实例,而是SingleTop、SingleTask、SingleInstance等模式,则触发onNewIntent()->onStart()流程。
Flag设置参考剪藏:
Android 之Activity启动模式(二)之 Intent的Flag属性 | skywang
Intent.addFlags() 启动Activity的20种flags全解析
剪藏我打赌你一定没搞明白的Activity启动模式 - Android - 掘金中对Android中这部分设计动机的讲解还不错。
4.可以用adb shell dumpsys activity activities命令,来查看一个调试中的Android手机中的当前任务栈信息。参考剪藏:adb shell dumpsys 命令用法
##Activity的标记位(Flags)
启动Activity时,在Intent中可添加的标记位种类很多,具体可以参考上面的几个剪藏。
常用标记位:
1.FLAG_ACTIVITY_SINGLE_TOP:指定为SingleTop模式,该标记位的效果与单顶模式相同。
2.FALG_ACTIVITY_NEW_TASK:指定为SingleTask模式(很多文章都指出,实际上单独设置该flag时,并不会有什么作用)
3.FLAG_ACTIVITY_CLEAR_TOP:
若任务栈中尚无Activity A的实例,不会有特别处理,只是放到顶部;
若任务栈中已存在Activity A的实例,当A不位于栈顶时,弹出A所属任务栈中A之上的所有Activity,触发onNewIntent();
当A位于栈顶时,分两种情况:若以默认方式启动A,则弹出A,创建一个新的实例放入栈顶,所以会触发onCreate();若附加FLAG_ACTIVITY_SINGLE_TOP标记位来启动A(可理解为以单顶模式启动A),则A不弹出,触发onNewIntent()方法。
另外,SingleTask的Activity实例,默认是带有FLAG_ACTIVITY_CLEAR_TOP标记位的。
4.FLAG_ACTIVITY_EXCLUDE_FROM_RECENT:带有该标记位的Activity,不会显示在历史记录列表中(就是点击底部菜单键弹出的那一堆选择列表)。
三、Activity的启动和关闭、信息传递
1.可通过Activity.finish()来手动关闭指定Activity。
2.启动方式有两种:
2.1一种在各种上下文环境都可使用,可通过Context.startActivity(Intent)来启动指定Activity;
2.2另一种在两个Activity之间可使用,并且前面的Activity可接收到后面Activity关闭时返回的信息:
2.2.1A通过Activity.startActivityForResult(请求码,Intent)方式来启动一个Activity B;
2.2.2Activity B执行setResult(结果码,Intent) ,然后finish()关闭自己;
2.2.3则A在回调方法onActivityResult(请求码,结果码,Intent)中可获取对应的回调,并提取B封装在Intent中的数据。
注:若B未设置结果码或B运行中崩溃,则A中回调方法中结果码为#RESULT_CANCELED,值为-1。
参考剪藏:startActivityForResult使用场景 - 简书
Android的startActivityForResult()与onActivityResult()与setResult()参数分析
onActivityResult()的用法_weixin_41008021的博客-CSDN博客_onactivityresult
四、Activity在AndroidManifest.xml中常见设置参数
常见设置参数如下:
<activity
android:name=".module.common.activity.SampleActivity” //名称,应为对应的包名地址
android:screenOrientation="portrait” //Activity的屏幕显示方向:示例为强制竖屏显示
android:launchMode="singleTask” //加载模式:示例为单栈模式
android:exported="true” //是否允许其它APP调起该Activity
android:theme="@style/CommonAppTheme” //设置主题类型,参考笔记:Android Activity界面显示相关总结
//窗口软键盘加载模式:示例参数为:
该Activity总是调整屏幕的大小以便留出软键盘的空间 | 用户选择activity时,软键盘总是被隐藏
android:windowSoftInputMode="adjustResize|stateHidden”>
//设置捕获哪些手机状态的变化,状态变化时会触发onConfigurationChanged()回调,
示例的设置效果为:当前尺寸|键盘显示隐藏|屏幕方向|屏幕布局设置
默认情况下,系统状态变化时会销毁Activity再自动重新创建实例,如果不想自动销毁和重建,可以把这个状态添加到这里。
这样当该系统状态改变时,不会销毁重建Activity,而是会触发当前Activity的onConfigurationChanged()回调方法。
android:configChanges="screenSize|keyboardHidden|orientation|screenLayout"
android:excludeFromRecents="true" //是否允许显示在手机历史使用记录列表中
(就是点击手机底部导航条菜单键,弹出的那个历史应用列表)
android:taskAffinity=“per.sample.task” //如果设置该参数,则会在指定的任务栈中启动。
默认不用设置,运行在包名对应的任务栈中。
android:process="help_process" //如果设置该参数,则会运行在指定的进程中。
默认不用设置,运行在包名对应的进程中。
<intent-filter> //IntentFilter设置,详情参考笔记IntentFilter匹配规则 & Scheme调用
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<data android:scheme="abesfesee" />
</intent-filter>
</activity>
各参数的详细介绍参考剪藏:
全面解析:AndroidManifest.xml文件中activity标签常用属性 - 简书
AndroidManifest.xml文件--Activity标签详解 - 简书
五、界面显示相关
参考笔记:Android Activity界面显示相关总结
六.Activity中常见的回调方法归纳:
##.生命周期相关:
onCreate()
onStart()
onResume()
onPause()
onStop()
onDestroy()
onRestart()
onIntent()
##.状态信息保存与读取(用于被系统回收再次重新打开时恢复数据)
onSaveInstanceState() //存储
onRestoreInstanceState() //读取
onCreate(Bundle) //直接在onCreate()中读取亦可
##.跳转与关闭
方式1:
Context.startActivity(Intent) //跳转,Intent可以是显式的,也可以是隐式的
finish() //关闭当前Activity
方式2:关闭时可回传数据
启动方:startActivityForResult(请求码,Intent) //跳转
onActivityResult(请求码,结果码,Intent) //接收结果回调
关闭方:setResult(结果码,Intent) //设置结果数据
finish() //关闭当前Activity
##.界面相关
setContentView() //设置Activity的界面主布局
getSupportActionBar() //获取ActionBar。需要Activity支持ActionBar,例如AppCompatActivity。
##.其它
//系统状态发生变化时的回调,具体监听哪些状态,需要监听的状态可在AndroidManifest.xml中注册Activity时设置
onConfigurationChanged(Configuration newConfig)
onBackPressed() //点击返回键时的回调
#.其它一些相关总结笔记和要点:
Android Activity的四种加载模式
Android Activity间的两种跳转方式、自我关闭方法、关闭后的结果处理
Android横竖屏切换时,状态和信息的维护
(声明:部分图片获取自网络,这里只是用于学习分享,侵删!)