1.正常情况下的生命周期
1.onCreate: 与onDestory
配对,表示Activity
被创建,这是生命周期的第一个方法。在这方法中可以做一个初始化的工作(比如加载布局资源,初始化activity所需要的数据等),耗时的工作在异步线程上完成。
2.onRestart:表示Activity
正在重新启动一般情况下,在当前Actiivity
从不可见重新变为可见状态时onRestart
就会被调用。这种请求一般都是用户行为所导致的,比如用户按下Home键切换到桌面或者打开了一个新的Activity
(这时当前的Activity会暂停,也就是onPause和onStop被执行),接着用户回到了这个Activity
就会出现这种情况。
3.onStart: 与onStop
配对,表示Activity
正在被启动,并且即将开始。但是这个时候要注意他与onResume
的区别,两者都标识Avtivity
可见,但是onStart
时Activity
还在加载其他内容,正在像我们展示,用户还无法看到,即无法交互。
4.onResume:与onPause
配对,表示Activity
已经创建完成,并可以开始活动了,这个时候用户可以看到界面,并且即将与用户交互 (完成该周期之后便可以响应用户的交互事件了)。
5.onPause:与onResume
配对,表示Activity正在暂停,正常情况下,onStop
接着就会被调用,在特殊情况下,如果这个时候用户快速的再回到当前Activity
,那么onResume
会被调用(极端情况),一般来说,在onPause
这个生命周期状态下可以做一些数据存储,停止动画的工作,但是不能太耗时,,如果是由于启动新的Activity而唤醒的该状态,那会影响到新Activity
的显示,原因是onPause
必须执行完,新的Activity
的onResume
才会执行。
6.onStop:与onStart
配对,表示Activity
即将停止,可以做一些稍微重量级的回收工作,同样也不能太耗时(可以比onPause
稍微好一点)。
7.onDestroy:与onCreate配对,表示Activity即将被销毁,这是Activity生命周期的最后一个回调,我们可以做一些回收工作和最终的资源释放(如Service
、BroadReceiver
、Map
等)。
正常情况下,Activity
的常用生命周期就是上面的7个,下图更加详细的描述的各种生命周期的切换过程:
这里要说的是,从上图我们可以看到一个现象:
onStart
与onStop
、onResume
与onPause
是配对的。两种Activity
回到前台的方式,从onPause
状态回到前台会走到onResume
状态,从onStop
状态回到前台会到onStart
状态,这是从是否可见和是否在前台来说的。从是否可见来说,onStart
和onStop
是配对的;从是否在前台来说,onResume
和onPause
是配对的。
我们来看看正常情况下生命周期的系统日志:
03-23 00:15:52.970 32278-32278/com.example.david.lifecircle E/TAG: onCreate() is invoked!
03-23 00:15:52.971 32278-32278/com.example.david.lifecircle E/TAG: onStart() is invoked!
03-23 00:15:52.971 32278-32278/com.example.david.lifecircle E/TAG: onResume() is invoked!
03-23 00:15:55.858 32278-32278/com.example.david.lifecircle E/TAG: onPause() is invoked!
03-23 00:16:02.573 32278-32278/com.example.david.lifecircle E/TAG: onRestart() is invoked!
03-23 00:16:02.573 32278-32278/com.example.david.lifecircle E/TAG: onStart() is invoked!
03-23 00:16:02.573 32278-32278/com.example.david.lifecircle E/TAG: onResume() is invoked!
2.异常情况下的生命周期
一般正常情况的声明周期就像上面所说的一样,但是因为Android本身内存或者其他的一些情况会使得Activity
不按照正常的生命周期。比如当资源配置发生改变、系统内存不足时,Activity
就会被杀死。下面分析这两种常见的情况。
情况1:资源相关的系统配置发生改变导致Activity
被杀死并重新创建
理解这个问题,我们首先要对系统的资源加载机制有一定了解,不过这里我不分析系统资源加载机制了(因为我也不怎么懂)。简单说明一下,就像是我们把一张图片放在drawable
目录之后,就可以通过Resources
去获取这张图片。同时为了兼容不同的设备,我们还可能需要在其他的一些目录放置不同的图片,比如 drawable-mdpi
、drawable-hdpi
等。这样,当应用程序启动时,系统就会根据当前设备的情况去加载合适的Resource
资源,比如说横屏和竖屏的手机会拿到两张不同的图片(设定了landscape
或portrait
状态下的图片)。
如果说,当前Activity
处于竖屏状态,如果突然旋转屏幕,由于系统配置发生了改变,在默认情况下,Activity
就会被销毁并重新创建(当然我们也可以组织系统重新创建,具体就在Mainfest
中申明android:Configchanges=
属性即可)。
异常情况下的调用流程:
1.调用onSaveInstance
保存当前Activity
状态。注意,它与onPause
方法没有先后之分。
2.调用onStop
方法做后续处理。
3.调用onDestroy
方法销毁当前活动。
4.重新onCreate
该活动。
5.调用onStart
方法之后,再调用onRestoreInstance
方法加载保存的数据。
6.接下来就与正常的一样了,调用onResume
,然后运行。
我们来看一下生命周期异常运行的系统日志:
03-23 00:19:23.480 26457-26457/com.example.david.lifecircle E/TAG: onCreate() is invoked!
03-23 00:19:23.481 26457-26457/com.example.david.lifecircle E/TAG: onStart() is invoked!
03-23 00:19:23.481 26457-26457/com.example.david.lifecircle E/TAG: onResume() is invoked!
03-23 00:19:51.323 26457-26457/com.example.david.lifecircle E/TAG: onPause() is invoked!
03-23 00:19:51.324 26457-26457/com.example.david.lifecircle E/TAG: onSaveInstanceState() is invoked! Save Text = Save Data
03-23 00:19:51.478 26457-26457/com.example.david.lifecircle E/TAG: onCreate() is invoked!
03-23 00:19:51.488 26457-26457/com.example.david.lifecircle E/TAG: onStart() is invoked!
03-23 00:19:51.490 26457-26457/com.example.david.lifecircle E/TAG: onRestoreInstanceState() is invoked! Recover Text = Save Data
03-23 00:19:51.490 26457-26457/com.example.david.lifecircle E/TAG: onResume() is invoked!
情况2:资源内存不足导致低优先级的Activity
被杀死
这种情况不好模拟,但是其数据存储和恢复过程和情况1完全一致,这里简单的描述一下Activity
的优先级情况。Activity
的优先级从高到低可以大致分为一下三种:
(1)前台Activity
——正在和用户交互的Activity,优先级最高。
(2)可见但非前台Activity
——比如Activity
中弹出了一个对话框,导致Activity
可见但无法和用户直接交互。
(3)后台Activity
——已经被暂停或者停止的Activity
,优先级最底。
当系统内存不足的时候,系统就会按照上述优先级从低到高来杀死目标Activity。并在后续通过onSaveInstance
和onRestoreInstance
来存储和恢复数据。
特别提醒的是:如果一个进程中没有四大组件(Activity
、Service
、ContentProvider
、BroadCastReceiver
)。那么这个进程就会很快被杀死,因此一些后台工作不适合脱离四大组件而独立运行在后台中,否则很容易被杀死。一般是将后台工作放入Service中从而保证进程有一定的优先级,这样才不会被系统轻易杀死
三、生命周期的使用
1.常见的生命周期有关问题:
1.onStart
和onResume
、onPause
和onStop
从描述上看来差不多,但是他们为什么会分开呢?有什么不同?
2.两个Activity
A
和B
,从A
中启动B
,那么B
的onResume
与A
的onPause
哪个会先执行呢?
3.onSaveInstance
与onRestoreInstance
是任何情况下都可以使用的嘛?所有的保存数据和恢复的操作都可以在这对方法中执行?
4.如上面所说,如何使得在系统配置放生改变后,Activity
不被重新创建呢?
2.解析
1、 onStart
和onResume
、onPause
和onStop
这两对看起来是差不多,而且很多时候都会同时调用onPause
、onStop
,然后回到onStart
、onResume
。但是在一些比较特殊的情况下就不一样了。我们举两种情况,
第一种:前台弹出了一个Dialog
,那么这个Dialog
的作用只是提醒用户或者让用户输入一个信息等就完毕了,这是一个比较轻量级的任务;
第二种:重新启动另一个Activity
界面,转到另一个模块。这时新启动的Activity
就不是一个临时或者轻量级的任务了。
这两种情况,第一种一般很快就会返回当前Activity
,不会太耗时;第二种可能会很久,在这段时间内系统可能需要启动其他的应用,那么就会产生内存紧张的问题。所以,我认为是要区分这两种情况,才会加入这两对方法。在第一种情况下,可以在onPause
中做一些较轻微的数据存储,因为一般很快就会回到当前Activity
;第二种情况下,适合在onStop
中做一些较重量级的存储。除此之外,我想不到其他的使用了。
2、这个问题可以从源码中得到解答。不过源码太复杂,涉及底层太多(AMS
、Binder
、ActivityStack
、ActivityThread
等)。不过可以直接调用生命周期,输出系统日志来得到解答。从下面的日志我们可以看出,的确是要等到A活动的onPause
方法之后B
才能执行(这里onCreate
没有输出日志):
03-23 01:02:31.339 32382-32382/com.example.david.lifecircle E/MainActivity: onCreate() is invoked!
03-23 01:02:31.341 32382-32382/com.example.david.lifecircle E/MainActivity: onStart() is invoked!
03-23 01:02:31.341 32382-32382/com.example.david.lifecircle E/MainActivity: onResume() is invoked!
03-23 01:04:04.005 32382-32382/com.example.david.lifecircle E/MainActivity: onPause() is invoked!
03-23 01:04:04.047 32382-32382/com.example.david.lifecircle E/SecondActivity: onStart() is invoked!
03-23 01:04:04.047 32382-32382/com.example.david.lifecircle E/SecondActivity: onResume() is invoked!
3、 onSaveInstance
和onRestoreInstance
是只有Activity
异常销毁的时候才会调用的,所以这里一般执行的是Activity
异常销毁时需要保存和恢复的数据;onSaveInstance
和onRestoreInstance
方法还可以判断Activity
是否被重建,但正常情况下是不会调用的。所以正常情况下,还是应该在onPause
和onStop
方法中保存数据。
4、上面提到,我们可以在AndroidMainfest.xml
里,对< activity />增加一个android:configChanges属性,来指定在哪些配置改变的情况下Activity不需要重建。如下所示:
android:configChanges="orientation|screenSize"//界面方向以及大小的改变不需要重建
我们在AndroidMainfest.xml
做如下申明:
MainActivity中的部分代码:
@Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
Log.e("MainActivity","onConfigurationChanged() is invoked!"+newConfig.orientation);
}
@Override
protected void onPause() {
super.onPause();
Log.e("MainActivity","onPause() is invoked!");
}
@Override
protected void onResume() {
super.onResume();
Log.e("MainActivity","onResume() is invoked!");
}
@Override
protected void onStart() {
super.onStart();
Log.e("MainActivity","onStart() is invoked!");
}
@Override
protected void onRestart() {
super.onRestart();
Log.e("MainActivity","onRestart() is invoked!");
}
点击屏幕旋转,然后来看一下系统日志输出:
03-23 01:14:11.357 10361-10361/com.example.david.lifecircle E/MainActivity: onCreate() is invoked!
03-23 01:14:11.359 10361-10361/com.example.david.lifecircle E/MainActivity: onStart() is invoked!
03-23 01:14:11.359 10361-10361/com.example.david.lifecircle E/MainActivity: onResume() is invoked!
03-23 01:14:28.140 10361-10361/com.example.david.lifecircle E/MainActivity: onConfigurationChanged() is invoked!2
03-23 01:14:38.294 10361-10361/com.example.david.lifecircle E/MainActivity: onConfigurationChanged() is invoked!1
03-23 01:14:47.531 10361-10361/com.example.david.lifecircle E/MainActivity: onConfigurationChan
我们发现,屏幕旋转之后,并没有重新调用生命周期,说明活动并没有被重建。configChanges属性还有许多的值,如:mcc\mnc\local\touchscreen\keyboard等等。
最后用一个实际的例子来说明Activity的各个生命周期。假设有一个程序由2个Activity`` A
和B
组成,A
是这个程序的启动界面。当用户启动程序时,Process
和默认的Task分别被创建,接着A被压入到当前的Task
中,依次执行了 onCreate
, onStart
, onResume
事件被呈现给了用户;此时用户选择A
中的某个功能开启界面B
,界面B
被压入当前Task
遮盖住了A
,A
的onPause
事件执行,B
的 onCreate
, onStart
, onResume
事件执行,呈现了界面B
给用户;用户在界面B
操作完成后,使用Back
键回到界面A
,界面B
不再可见,界面B
的onPause
, onStop
, onDestroy
执行,A
的onResume
事件被执行,呈现界面A
给用户。此时突然来电,界面A
的onPause
事件被执行,电话接听界面被呈现给用 户,用户接听完电话后,又按了Home
键回到桌面,打开另一个程序“联系人”,添加了联系人信息又做了一些其他的操作,此时界面A
不再可见,其 onStop
事件被执行,但并没有被销毁。此后用户重新从菜单中点击了我们的程序,由于A
和其所在的进程和Task
并没有被销毁,A
的onRestart
和onStart
事件被执行,接着A
的onResume
事件被执行,A
又被呈现给了用户。用户这次使用完后,按Back
键返回到桌面,A
的 onPause
, onStop
被执行,随后A
的onDestroy
被执行,由于当前Task
中已经没有任何Activity
,A
所在的Process
的重要程度被降到很 低,很快A
所在的Process
被系统结束
常见的例子
情形一、一个单独的Activity
的正常的生命过程是这样的:onCreate
->onStart
->onPause
->onStop
->onDestroy
。例如:运行一个Activit
,进行了一些简单操作(不涉及页面的跳转等),然后按返回键结束。
情形二、有两个Activity
(a和b),一开始显示a,然后由a启动b,然后在由b回到a,这时候a的生命过程应该是怎么样的呢(a被b完全遮盖)?
a经历的过程为onCreate
->onStart
->onResume
->onPause
->onStop
->onRestart
->onStart
->onResume
。这个过程说明了图中,如果Activity
完全被其他界面遮挡时,进入后台,并没有完全销毁,而是停留在onStop
状态,当再次进入a时,onRestart
->onStart
->onResume
,又重新恢复。
情形三、基本情形同二一样,不过此时a被b部分遮盖(比如给b添加个对话框主题 android:theme=”@android:style/Theme.Dialog”)
a经历的过程是:onCreate
->onStart
->onResume
->onPause
->onResum
e
所以当Activity
被部分遮挡时,Activity进入onPause
,并没有进入onStop
,从Activity2
返回后,执行了onResume
情形四、 打开程序,启动a,点击a,启动AlertDialog
,按返回键从AlertDialog返回。
a经历的过程是:onCreate
->onStart
->onResume
当启动和退出Dialog
时,Activity
的状态始终未变,,因为Dialog
实际上时一个View
,它是属于某一个Activity
的,因此如果Dialog
显示在当前Activity
之前时不会影响到Activity
的生命周期的。但是如果是其他Activity
的Dialog
弹出那么就会触发onPause()
方法的执行。
摘自 https://blog.csdn.net/woshimalingyi/article/details/50961380