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放置于此task

  • FLAG_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:

  1. 先判断target activity能否在新task中启动
    singleTask/singleInstance的activity本身具有在新task中启动的能力,standard/singleTop的activity要想拥有在新task中启动的能力,需要在设置Intent.FLAG_ACTIVITY_NEW_TASK

  2. 判断target activity所在task
    找一个taskAffinity的task去启动,找不到就新建一个(这里会忽略了singleInstance独占的task)

  3. 根据TargetActivity的启动模式判断会如何启动

五、相关问题

onWindowFocusChanged

在Activity窗口获得或失去焦点时被调用,
1、创建时首次呈现在用户面前;
2、当前Activity被其他Activity覆盖;
3、当前Activity转到其他Activity或按Home键回到主屏,自身退居后台;
4、用户退出当前Activity。

以上几种情况都会调用onWindowFocusChanged,并且当Activity被创建时是在onResume之后被调用,当Activity被覆盖或者退居后台或者当前Activity退出时,它是在onPause之后被调用
这个方法在某种场合下还是很有用的,例如程序启动时想要获取视特定视图组件的尺寸大小,在onCreate中可能无法取到,因为窗口Window对象还没创建完成,这个时候我们就需要在onWindowFocusChanged里获取

其他应用问题:

  1. activity间传递数据
  2. 知晓当前activity
  3. 关闭所有activity
  4. 双击退出app
  5. 保存activity状态

    面试常见知识点

    Activity A跳转到Activity B 两者经历怎样的生命周期
    未配置configchanges情况下屏幕发生旋转时 当前Activity的生命周期是怎样变化的

Activity知识点详解的更多相关文章

  1. Android application 和 activity 标签详解

    extends:http://blog.csdn.net/self_study/article/details/54020909 Application 标签 android:allowTaskRep ...

  2. Android组件系列----Activity组件详解

    [声明] 欢迎转载,但请保留文章原始出处→_→ 生命壹号:http://www.cnblogs.com/smyhvae/ 文章来源:http://www.cnblogs.com/smyhvae/p/3 ...

  3. python爬虫知识点详解

    python爬虫知识点总结(一)库的安装 python爬虫知识点总结(二)爬虫的基本原理 python爬虫知识点总结(三)urllib库详解 python爬虫知识点总结(四)Requests库的基本使 ...

  4. 「JVM」知识点详解一:JVM运行原理详解

    前言 JVM 一直都是面试的必考点,大家都知道,但是要把它搞清楚又好像不是特别容易.JVM 的知识点太散,不系统,今天带大家详细的了解一下jvm的运行原理. 正文 1 什么是JVM? JVM是Java ...

  5. OpenStack知识点详解

    一:云计算     一.起源 1. 云计算这个概念首次在2006年8月的搜索引擎会议上提出,成为了继互联网.计算机后信息时代的又一种革新(互联网第三次革命). 2. 云计算的核心是将资源协调在一起,使 ...

  6. Activity 使用详解

    极力推荐文章:欢迎收藏 Android 干货分享 阅读五分钟,每日十点,和您一起终身学习,这里是程序员Android 本篇文章主要介绍 Android 开发中的部分知识点,通过阅读本篇文章,您将收获以 ...

  7. Android基础之Activity launchMode详解

    本文来自http://blog.csdn.net/liuxian13183/ ,引用必须注明出处! Activity的lauchmode,是基础的属性,但也是App优化必须掌握的知识,它约束了Acti ...

  8. Android之路-------Activity的详解

    前言 由于接近放假,公司在赶项目所以前段LP比较忙,没什么时间总结和写博客,只是准备睡觉的时候看看书,每天看的不算多,大概10多页左右吧,不过每天坚持如此的话那也是一个庞大的数字. 今天LP的任务完成 ...

  9. ant+eclipse知识点详解及使用案例

    ant的优点和地位就不再阐述,下面直接上知识点: 在java中使用xml文件开发,有以下基本语法 (1)project:每个ant程序有且只有一个此标签,而且是类似于html的总标签,有name,de ...

随机推荐

  1. [问题解决]Got permission denied while trying to connect to the Docker daemon socket at unix:///var/run/docker.sock

    写了一个脚本读取docker日志,发生报错:Got permission denied while trying to connect to the Docker daemon socket at u ...

  2. 通Shell获取Tomcat进程号并杀死进程

    #!/bin/bash echo "begin get tomcat8 pid" tomcat8_id=$( | grep -v grep | awk '{print $2}') ...

  3. 【ztree】获取根节点

    var node = treeObj.getNodesByFilter(function (node) { return node.level == 0 }, true);

  4. JS系列:三元运算符与循环

     三元运算符 语法: 条件?成立做的事情:不成立做的事情:<=>相当于简单的if/else判断(简化写法) var num = 12; if(num>10){ num ++; }el ...

  5. SQL Server MERGE(合并)语句

    如何使用SQL Server MERGE语句基于与另一个表匹配的值来更新表中的数据.  SQL Server MERGE语句 假设有两个表,分别称为源表和目标表,并且需要根据与源表匹配的值来更新目标表 ...

  6. Linux用户查询、新增&删除

    1.查询用户tail -1 /etc/passwd 2.新增用户&用户组groupadd testgroup #组的添加useradd testuser #创建用户testuserpasswd ...

  7. 修改kvm宿主机主机名后

    修改了宿主机的主机名后, libvirtd错误日志如下 virNetSocketReadWire: : End of file while reading data: Input/output err ...

  8. PHP设计模式 - 中介者模式

    中介者模式用于开发一个对象,这个对象能够在类似对象相互之间不直接相互的情况下传送或者调解对这些对象的集合的修改. 一般处理具有类似属性,需要保持同步的非耦合对象时,最佳的做法就是中介者模式.PHP中不 ...

  9. Shell的展开

    Shell的展开 2018-5-30   Writen By Stephen.Yu  一.路径名展开 shell执行echo命令前,在命令行上自动展开任何符合条件的字符,例如这里,* 被展开成当前的路 ...

  10. *** WARNING L16: UNCALLED SEGMENT, IGNORED FOR OVERLAY PROCESS

    Warning提示的原因是 一些未使用的函数被编译进入芯片,浪费了RAM/ROM. 解决的方法: 1.将不用的函数注释: 2.在未使用函数的首尾加条件编译 #ifdef 函数名 和 #endif ,不 ...