谨以文章记录学习历程,如有错误还请指明。
Activity生命周期
首先放上Google Develop Guides中的Activity完整的生命周期示意图:
回调初步解读
onCreate()
:创建活动时调用。onStart()
:当活动进入可见状态时调用,使得活动可见但不可与用户交互。onResume()
:活动进入前台时调用,可与用户交互。onPause()
:活动不持有用户焦点但依然可见时调用。活动仍可见,但停止与用户交互,比如弹窗,锁屏等onStop()
:活动不可见时调用onDestroy()
:活动退出,被销毁时调用onRestart()
:活动由不可见重新返回前台时调用。依次调用onRestart()
->onStart()
->onResume()
回调方法中进行的操作
onCreate()
:在这个方法中,执行基本的应用程序启动逻辑,这种逻辑应该只在活动的整个生命周期中发生一次。如将数据绑定到ListView
,声明范围变量等。同时该方法接收一个savedInstanceState
参数,是用来恢复之前保存过状态的Bundle
对象。后面我们会介绍。onStart()
:该方法中初始化维护UI的组件,如注册一个监听UI变化的广播。onResume()
:在这个方法中,应该初始化在onPause()
中释放的组件,如初始化camera
,同时执行活动每次进入前台时候都需要的初始化操作,如开始动画与初始化哪些只有在获取用户焦点时才需要得到组件,如上下文菜单。onPause()
:释放系统资源,例如广播接收器、处理传感器(如GPS
)或任何可能影响电池寿命的资源。onStop()
:释放几乎所有不需要的资源,如上述onStart()
中创建的广播,同时在此方法中执行耗时的释放资源的操作,如保存数据,网络调用,数据库事务等。同时很重要的一点,需要在此方法中释放可能导致内存泄漏的资源,因为系统因为内存紧张而杀死活动进程时,不会调用最后的onDestroy()
方法。onDestroy()
:释放在onCreate()
中初始化的活动所能使用的全局资源。
在任何一个生命周期回调方法中调用
finish()
方法时,系统会直接调用onDestroy()
方法,而跳过这之前的所有回调过程。
-
onRestart()
:由于onStart()
的存在,这个方法好像没什么使用场景。
为什么在
onStop()
中释放耗时资源而不是在onPause()
中?
原因:在两个Activity A,B中,当从A中startActivity()
或startActivityForResult()
启动B时,分别以如下的顺序调用生命周期的回调方法:
- Activity A的
onPause()
- Activity B的
onCreate()
,onStart()
,onResume()
依次执行,此时Activity B进入前台并获得用户焦点- 如果Activity A不再显示在屏幕上,则调用其
onStop()
方法。A的
onStop()
方法和B的onCreate()
等一系列方法并非顺序执行,而是有重叠。因此当onPause()
方法中进行耗时操作时,会严重影响活动之间的跳转速度。
不同场景下回调方法的调用顺序
启动Activity
onCreate()
(创建)--->onStart()
(可见,不可交互) --->onResume()
(前台,可交互)currentActivity被otherActivity覆盖一部分,或锁屏
onPause()
(失去用户焦点,但仍可见)currentActivity由上述部分不可见状态回到前台或解锁屏幕
onResume()
(前台,持有用户焦点)currentActivity转到otherActivity界面,或按Home退回主界面,自身进入后台
onPause()
(失去用户焦点,但仍可见)--->onStop()
(不可见)由上述后台状态再次打开该活动
onRestart()
(过渡状态,不清楚到底有什么用。。。) --->onStart()
(可见,不可交互) --->onResume()
(前台,持有用户焦点)currentActivity部分可见或后台不可见时,系统内存不足时
杀死当前Activity,此时生命周期不会发生回调上述被杀死的活动再次启动
onCreate()
(重新创建) --->onStart()
(可见,不可交互) --->onResume()
(前台,持有用户焦点)用户退出currentActivity
onPause()
(失去用户焦点,但仍可见) --->onStop()
(不可见) --->onDestroy()
多窗口下,ActivityA获得焦点时,点击ActivityB
对于ActivityA:onPause()
(失去用户焦点,但仍可见)
对于ActivityB:onResume()
(前台,持有用户焦点)
Fragment的生命周期
同样,还是先放上Google Develop Guides中的Fragment完整的生命周期示意图:
回调解析
Activity中同名方法不在赘述
onAttach()
Fragment和Activity建立关联时调用(获得activity的传递的值,如二者依靠回调通信时,获得activity的引用(将其转型为callback回调接口))onCreateView()
为Fragment创建视图(加载布局)时调用(给当前的fragment绘制UI布局,可以使用线程更新UI)onActivityCreated()
当Activity中的onCreate()
方法执行完后调用(表示activity执行oncreate()
方法完成了的时候会调用此方法)onDestroyView()
Fragment中的布局被移除时调用onDetach()
Fragment和Activity解除关联的时候调用
不同场景下回调方法的调用顺序
创建一个fragment的时候
创建过程:onAttach()
--->onCreate()
--->onCreateView()
--->onActivityCreated()
显示到前台:onStart()
--->onResume()
fragment进入后台
onPause()
--->onStop()
fragment被销毁
onPause()
--->onStop()
--->onDestroyView()
--->onDestroy()
--->onDetach()
锁屏
onPause()
--->onStop()
解锁
onStart()
--->onResume()
打开其他fragment(原始fragment被替换,或完全不可见)
onPause()
--->onStop()
--->onDestroyView()
上述条件下back回原始fragment
onCreateView()
--->onActivityCreated()
->onStart()
--->onResume()
Home回到桌面
onPause()
--->onStop()
上述回到原始fragment
onStart()
--->onResume()
退出应用
onPause()
--->onStop()
--->onDestroyView()
--->onDestroy()
--->onDetach()
二者生命周期的联系
老规矩,还是放上Google Develop Guides中的对比图
由于Android内部机制(原理尚不知,未深入源码做研究),fragment总是依附于activity而存在,不过需要注意的是activity的生命周期由系统控制,而fragment则是由宿主activity控制,因此在activity进入到某一状态如created,系统会调用activity的
onCreate()
,此时宿主activity会调用fragment的onAttach()
...onActivityCreated()
一系列方法,使得fragment快速跟上宿主,与宿主activity保持一致状态。
关于Activity状态保存与恢复
在上述生命周期中,我们有时会需要保存activity的状态,比如我们正在某一文本框EditText中输入文本时,此时退出应用之后再次打开时,我们会发现文本框的内容消失了。消失了。。消失了。。。
这种情况下,用户体验显然不会好。因此Google引入了保存UI状态这一概念。
保存状态
复写onSaveInstanceState()
,传入一个带有状态信息的Bundle
对象,代码如下:
static final String STATE_SCORE = "playerScore";
static final String STATE_LEVEL = "playerLevel";
// ...
@Override
public void onSaveInstanceState(Bundle savedInstanceState) {
// Save the user's current game state
savedInstanceState.putInt(STATE_SCORE, mCurrentScore);
savedInstanceState.putInt(STATE_LEVEL, mCurrentLevel);
// Always call the superclass so it can save the view hierarchy state
super.onSaveInstanceState(savedInstanceState);
}
保存状态的时机
Activity容易被销毁的时候调用:
- 按下
Home
键:Activity进入了后台 - 锁屏:Activity进入后台
- 启动其他Activity:Activity进入后台
- 横竖屏切换:销毁并重建Activity实例
上述场景下,多数为当系统内存不足时,可能销毁后台低优先级的Activity。
注意事项
在用户主动销毁Activity时不会保存状态:
back
键- 调用
finish()
方法方法调用时机:
- Android P之前:介于
onStop()
之前,但不确定在onPause()
之前还是之后。- Android P中:在
onStop()
后调用设有id的组件会自动保存组件的状态
恢复状态
我们有两种方式恢复状态:
- 在
onCreate()
方法恢复
需要注意的是,在尝试读取该对象时,需要判断其是否为空,空时则会创建该活动的新实例,而非恢复之前被销毁活动实例:
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); // Always call the superclass first
// Check whether we're recreating a previously destroyed instance
if (savedInstanceState != null) {
// Restore value of members from saved state
mCurrentScore = savedInstanceState.getInt(STATE_SCORE);
mCurrentLevel = savedInstanceState.getInt(STATE_LEVEL);
} else {
// Probably initialize members with default values for a new instance
}
// ...
}
- 重写
onRestoreInstanceState()
方法恢复
只有在有待恢复的状态时,系统才调用onRestoreInstanceState()
,所以不需要检查savedInstanceState
是否为空:
public void onRestoreInstanceState(Bundle savedInstanceState) {
// Always call the superclass so it can restore the view hierarchy
super.onRestoreInstanceState(savedInstanceState);
// Restore state members from saved instance
mCurrentScore = savedInstanceState.getInt(STATE_SCORE);
mCurrentLevel = savedInstanceState.getInt(STATE_LEVEL);
}
调用时机
- 销毁了之后重建的时候调用, 如果内存充足, 系统没有销毁这个 Activity, 就不需要调用
- 横竖屏切换时调用
总结
- 本文尽可能详细的对Activity和Fragment的生命周期,以及Activity的状态保存与恢复作出了解析
- 笔者水平有限,如有错漏,欢迎指正。
- 接下来我也会将所学的知识分享出来,有兴趣可以继续关注whd_Alive的Android开发笔记
欢迎关注whd_Alive的简书
- 不定期分享Android开发相关的技术干货,期待与你的交流,共勉。