Activity知识点详解
一、什么是Activity
官方解释:
The Activity class is a crucial component of an Android app, and the way activities are launched and put together is a fundamental part of the platform’s application model. Unlike programming paradigms in which apps are launched with amain()method, the Android system initiates code in an Activity instance by invoking specific callback methods that correspond to specific stages of its lifecycle.
Activity是Android应用的重要组成部分,它的启动和组合方式是Android应用程序模型的一个基本部分。与使用 main ()方法启动应用程序的编程范例不同,Android 系统通过调用与其生命周期的特定阶段相对应的特定回调方法来启动 Activity 实例中的代码。
我们在日常的开发中接触最多的可能就是Activity了,对于Activity我的理解是它作为Android四大组件之一,主要是给我们提供界面的展示和用户交互。。这里要说下Android的四大组件,Activity、Service、Brocast、ContentProvider功能各不相同但是称它们为四大组件主要是它们四个都是Android应用的入口。我们都知道Java是采用main ()方法启动应用程序的,但是Android并没有采用这种方式,Android设计了四个组件以这些组件为入口来启动一个Android应用。
二、生命周期
生命周期作为Activity老生常谈的知识点是我们必须要熟练掌握的。这里要分两种情况去理解掌握:正常情况下的生命周期和异常情况下的生命周期。
正常情况下的生命周期
这可以说是Activity最基本的知识点了在此就不展开了,贴张图
再次补充一个关于生命周期的问题就是处于哪些生命周期时是可以被杀死的。
onCreate、onStart()、onRestart()、onResume()当Activity处于这些生命周期时是不可被kill的。onPause()在Honeycomb(3.X版本)之前是可以被kill的,而从Honeycomb开始系统在Activity回调onStop()
之前是不会杀死Activity的,因为这样可以确保在异常情况下onsaveinstancestate被调用,保存状态。
(Android P开始onsaveinstancestate在onStop()之后被调用)
异常情况下的生命周期
我们主要注意以下两种情况下的生命周期:
系统配置发生变化
比如常见的如屏幕方向发生变化,配置发生变化是会导致Activity销毁重建的,如果我们想保持之前的Activity不被销毁那么我们可以在manifest中设置对应的配置信息 ,之后当其变化时会触发onConfigurationChanged回调此时是不会销毁重建的。但是要注意的是触发回调时当前组件(Activity)必须还在运行 如果组件被暂停 那么是不会触发回调的 。
内存紧张导致Activity被杀死
因为Android总体资源有限当内存紧张时系统会根据一定的优先级杀死一些Activity。这里的优先级依次是:前台Activity>可见Activity>后台Activity>空进程。
除此之外我们还要了解onsaveinstancestate/onrestoreinstancestate回调。
onsaveinstancestate是Activity因为异常被系统kill时用来保存当前Activity的有关状态和数据的,我们也可以在该回调中保存我们想要保存的数据以防止Activity因为异常被杀死而丢失数据。之后系统会在合适的时机重建该Activity此时就会触发onrestoreinstancestate回调,在该回调里我们可以拿到之前保存的状态和数据进行恢复(在oncreate中也可以拿到保存的数据不过需要进行判空,所以还是推荐在onrestoreinstancestate进行恢复)。
最后关于这两个函数的回调时机,系统版本不同会有一些差异:
1、 api < 11,onSaveInstance在onPause之前执行
2、11 <= api < 28,onSaveInstance在onPause之后,onStop之前执行
3、api >= 28,onSaveInstance在onStop之后执行
三、启动方式
分类一
显示启动
指明ComponentName有明确的启动目标
隐式启动
未指明ComponentName,通过匹配intentfilter找到可以启动的目标
分类二
不带返回值
通过startActivity
带返回值
startActivityForResult启动并在onActivityResult中接收返回的结果。
四、任务栈
Task是用户在执行某项任务时与之交互的Activity的集合。按照每个Activity打开的顺序排列在一个堆栈(先进后出)。一般来说处在栈顶的Activity是正在前台的Activity。
总结Activity和Task的默认行为:
- 当Activitya 启动Activity b 时,Activity a 停止,但系统保持其状态(如滚动位置和输入到表单中的文本)。 如果用户按下Back键回来那么a 恢复其状态,b被弹出Task并被销毁。
- 当用户通过按下Home button当前Activity被停止并且它的任务进入后台。 系统保留任务中每个Activity的状态。 如果用户稍后通过选择启动该Task的启动图标恢复该任务,则该Task将到达前台并恢复堆栈顶部的Activity。
- Activity可以被多次实例化,同时可以从其他Task中实例化
一般而言我们不需要干预Task的默认行为,但是我们也可以通过以下方法去干预:
taskAffinity
Affinity表示Activity希望属于哪个Task。 默认情况下,来自同一个应用程序的所有Activity彼此都有相同的Affinity。可以设置Taskaffinity 属性来自定义Affinity。task自身的affinity决定于根Activity的affinity值也就是说同一个task中的所有Activity具有相同的affinity。
affinity在什么场合应用呢?
1.根据affinity重新为Activity选择宿主task(与allowTaskReparenting属性配合工作);
2.启动一个Activity过程中Intent使用了FLAG_ACTIVITY_NEW_TASK标记,根据affinity查找或创建一个新的具有对应affinity的task
Affinity还有两点要注意:
1、根activity的taskAffinity可以决定task的“名字”,activity在启动时和re-parent时需要根据taskAffinity来确定该activity会出现在哪个task
2、优先级是activity中指定的taskAffinity>application中指定的taskAffinity>默认的包名
launchMode
Android提供了四种启动模式:
- standard
默认模式 该模式下每次启动activity都会创建新的activity实例。特殊情况,如果在Service或Application中启动一个Activity,其并没有所谓的任务栈,可以使用标记位Flag来解决。解决办法:为待启动的Activity指定FLAG_ACTIVITY_NEW_TASK标记位,创建一个新栈。 - singleTop
启动一个activity如果该activity实例已经已在栈顶则复用并回调onnewintent。应用场景 推送跳转activity - singleTask
启动一个activity时会先找自己所属的Task,如果该Task已经存在那么查看Task中是否有该activity实例 有则复用并回调onnewintent
如果所属的Task还未创建那么就先创建Task然后再创建Activity实例并入栈 所以说singleTask 启动模式的activity 是全局单例的。应用场景 app主页 -
singleInstance
可以看做是singleTask的加强版,改启动模式下每次都会启动一个新的Task并将activity实例放到Task 并且Task中只有这一个activity实例。应用场景 呼叫来电。activity attributes或者intent flags
android:allowTaskReparenting
这个属性用来标记一个Activity实例在当前应用退居后台后,是否能从启动它的那个task移动到有共同affinity的task,“true”表示可以移动,“false”表示它必须呆在当前应用的task中,默认值为false 重新宿主的操作发生在应用退后台再次重启过程中android:alwaysRetainTaskState
如果用户长时间离开Task,系统将清除除根Activity以外的所有Activity。 当用户再次返回Task时,只恢复根Activity。但是设置该属性为true后就不会发生清除,即使在很长一段时间之后,任务仍然保留其堆栈中的所有活动。android:clearTaskOnLaunch
在Task的根Activity中,只要用户离开Task并返回到该Task,堆栈就会被清除到根Activity。用户总是返回到Task的初始状态,即使离开Task只有一会儿。android: finishOnTaskLaunch
它作用于一个单一的Activity,而不是一个完整的Task。 它会导致任何Activity消失,包括根Activity。用户离开,然后返回到Task,则该Task不再存在。FLAG_ACTIVITY_NEW_TASK
其效果与指定Activity为singleTask模式一致。系统会寻找或创建一个新的task来放置目标Activity,寻找时依据目标Activity的taskAffinity属性进行匹配,如果找到一个task的taskAffinity与之相同,就将目标Activity压入此task中,如果查找无果,则创建一个新的task,并将该task的taskAffinity设置为目标Activity的taskActivity,将目标Activity放置于此taskFLAG_ACTIVITY_SINGLE_TOP
其效果与指定Activity为singleTop模式一致。FLAG_ACTIVITY_CLEAR_TOP
具有此标记位的Activity,当它启动时,在同一个任务栈中所有位于它上面的Activity都要出栈。如果和singleTask模式一起出现,若被启动的Activity已经存在栈中,则清除其之上的Activity,并调用该Activity的onNewIntent方法。如果被启动的Activity采用standard模式,那么该Activity连同之上的所有Activity出栈,然后创建新的Activity实例并压入栈中。如果和FLAG_ACTIVITY_NEW_TASK 一起使用时,则是一种在另一个Task中定位现有Activity并将其放置在能够响应该意图的位置的方法。FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET
如果一个Intent中包含此属性,则它转向的那个Activity以及在那个Activity其上的所有Activity都会在task重置时被清除出task
最后说明下activity启动时如何选择task:
先判断target activity能否在新task中启动
singleTask/singleInstance的activity本身具有在新task中启动的能力,standard/singleTop的activity要想拥有在新task中启动的能力,需要在设置Intent.FLAG_ACTIVITY_NEW_TASK判断target activity所在task
找一个taskAffinity的task去启动,找不到就新建一个(这里会忽略了singleInstance独占的task)根据TargetActivity的启动模式判断会如何启动
五、相关问题
onWindowFocusChanged
在Activity窗口获得或失去焦点时被调用,
1、创建时首次呈现在用户面前;
2、当前Activity被其他Activity覆盖;
3、当前Activity转到其他Activity或按Home键回到主屏,自身退居后台;
4、用户退出当前Activity。
以上几种情况都会调用onWindowFocusChanged,并且当Activity被创建时是在onResume之后被调用,当Activity被覆盖或者退居后台或者当前Activity退出时,它是在onPause之后被调用
这个方法在某种场合下还是很有用的,例如程序启动时想要获取视特定视图组件的尺寸大小,在onCreate中可能无法取到,因为窗口Window对象还没创建完成,这个时候我们就需要在onWindowFocusChanged里获取
其他应用问题:
- activity间传递数据
- 知晓当前activity
- 关闭所有activity
- 双击退出app
-
保存activity状态
面试常见知识点
Activity A跳转到Activity B 两者经历怎样的生命周期
未配置configchanges情况下屏幕发生旋转时 当前Activity的生命周期是怎样变化的