在正常情况下生命周期如下:
onCreate:表示生命周期在被创建,这是第一个生命周期,在这里可以做一些初始化的操作,比如:setContentView加载布局。 但是不能在这个方法中获取子控件的大小。
onRestart:表示activity被重新启动
onStart:表示activity正在被启动,activity可见,但是不能交互,
onResume:表示activity可见,可以进行人机交互,于onStart的区别在于,onStart还在后台,而onResume在前台。
onPause:失去焦点,失去交互。
onStop : 不可见状态,退回到后台
onDestory :销毁activity,这里可以做一些回收工作,资源释放
生命周期图
1. 第一次启动,调用过程: onCreate - > onStart -> onResume.
2.当打开新的Activity或者切换到桌面的时候:onPause -> onStop , 有一种特殊的情况是:当用户设置了透明的主题,那么当前Activity不会走onStop方法。
3. 当用户再次回到原Activity时,回调如下:onRestart -> onStart ->onResume
4. 当用户按下back键,回调: onPause -> onStop ->onDestory
这里提出两个疑问:
1. onStart、onResume、onStop、onPause从描述上看是差不多的,对我们来说有什么本质的区别呢?
onStart和onStop是从是否可见这个角度来讲的,onResume和onPause 是从与用户是否可以交互这个角度讲的。
2. 当前的Activity 为A,当打开Actiivty B,那么是B的onResume和A的onPause那个先执行呢?
从源码中可以看出,当一个新的Activity要启动时,位于栈顶顶Activity需要先onPause后,新的Activity才能启动。
一般我们不要在onPause中作耗时的操作,以便新的Activity能快速的启动。
异常情况下的生命周期
1. 当资源等系统配置内存不足杀死了Activity然后又重新创建。
当手机从横屏切换到竖屏的时候,当前的Activity会销毁然后重新创建,当然我们也可以阻止横竖屏切换销毁Activity。
当系统配置改变后,Activity重新创建,它所走的生命周期方法是:
当系统以外被杀死后,正常的生命周期方法都会调用,onPause、onStop、onDestory会被调用,还会调用onSaveInstanceState方法保存当前的状态,它调用的时机是在onStop之前。当被重新创建的时候,会调用onRestoreInstanceState方法,将参数保存到Bundle中传递, 在onCreate方法中这个Bundle对象,如果是正常启动这里的Bundle的值是null。如果在onCreate方法中获取参数值,需要进行判空处理,而在onRestoreInstanceState方法中不需要,因为一旦调用这个方法,Bundle中就一定有值。
源码中每一个View都有这两个方法,onSaveInstanceState和onRestoreInstanceState方法。首先Activity以为终止,会调用onSaveInstanceState方法去保存数据。然后Activity会委托Window去保存数据,Window会委托它的顶级容器去保存数据,一般是ViewGroup,或者DecorView,最后顶级容器通知它的子元素去保存数据。这就是一个典型的委托思想,它与java虚拟机加载class字节码文件的委托加载机制的思想是一样的。源码中可以看到,view保存了一些状态和内容。
不想让Activity在屏幕旋转的时候重新创建,可以在清单文件中设置configChanges属性添加orientation这个值:
android:configChanges="orientation|screenSize"
启动模式
Activity launchMode有四种启动模式:standard、singleTop、singleTask、singleInstance。
1. standard标准模式,这是系统默认的模式,每次启动activity都会创建的一个新的activity。谁启动了这个Actiivty,那么这个activity就会在启动它的那个任务栈中。比如Activity A启动了Activity B,那么这个B就会进入到A所在到任务栈中。
但是当我们使用ApplicationContext启动standard模式的activity就会报错,因为非Activity类型的context并没有所谓的任务栈,只有Activity 才有任务栈。解决办法就是在为启动的Activity指定任务栈:
FLAG_ACTIVITY_NEW_TASK
这样就创建了一个新的任务栈,这个时候启动的Activity实际上是以singleTask模式启动的。
singleTop:栈顶复用模式。在这个模式下,如果新的Activity已经位于栈顶,那么就不会再创建新的Activity。同时会调用它的onNewIntent方法。这里的onCreate方法和onStart方法不会被调用。如果新的Activity实例存在但是不位于栈顶,那么会创建一个新的Activity实例。
singleTask:栈内复用模式,这是一个相当于单例模式,只要Activity实例存在,那么多次启动Activity都不会重新创建Activity。同时它也会调用onNewIntent()方法。它会将启动的activity栈上边的其他Activity实例全部出栈 ,将这个activity实例放到栈顶。
singleInstance:单实例模式,它单独启用一个任务栈。这个任务栈中只有这一个实例。
singleTask中什么是需要的任务栈呢?
这要从一个参数说起:TaskAffity ,这个参数标记了activity所需要的任务栈名字。默认情况下,所有的任务栈的名字是应用包名。指定新的任务栈不能和包名一样。
给Activity指定启动模式有两种方式:
第一种是在ActivityMenifest中设置
android:launceMode="singleTast"
第二种是:在Intent中设置标志位。
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
区别在于第二种方式的优先级比第一种高,当两种方式都存在,以第二种方式为准。
IntentFilter匹配
Actiivity启动分为显示启动和隐式启动。隐式启动需要设置匹配规则,这个匹配组建就是IntentFilter ,它有三个可以提供过滤的,action、data、category。一个Intent必须完全匹配过滤规则才能隐式启动Activity。一个Activity可以包含多个intent-filter,一个Intent只要能匹配任何一组intent-filter就可以启动Activity。
action规则:action是一个字符串,一个过滤规则中可以有多个action,只要一个可以匹配就行。它区分大小写,一个过滤规则中必须包含action,否则无法匹配。
category规则:过滤规则中可以不设置category,它与action 不同,action是必须设置的,而category可以不设置,如果设置了,那么必须匹配上,否则报错。
data规则:data由两部分组成,mimeType和URI 。mineType指媒体类型,比如:image/jpeg、audio/mpeg4-generic和video/*等。
URI结构为:
<scheme>://<host>:<port>/[<path>|<pathPrefix>|<pathPattern>]
scheme:表示URI的模式:有http/file/content 等,如果没有设置scheme,那么整个uri无效。
host:主机名。
port:当指定scheme和host后,这个端口才有效。
path等三个都是指定路径。
如果要为intent指定完整的data,必须调用setDataAndType方法,不能先调用setData,然后再调用setType。因为这两个方法会彼此清除对方的值。