0
点赞
收藏
分享

微信扫一扫

温故而知新:重新认识Activity的生命周期,大厂面试题汇总

hwwjian 2022-01-24 阅读 87
  • 子类必须在onCreate中调用 super 方法,也就是super.onCreate, 否则会抛出异常。(尽量保证super方法在子类onCreate方法的第一行)

  • 如果onCreate方法的参数onSaveInstanceState不为空,那么它是Activity最近被系统杀死时保存了你在onSaveInstanceState方法中设置的值,你可以用它来恢复数据。

其他注意事项是你不能在此方法中执行任何耗时的代码,在所有的Activity的生命周期方法中也是如此。

2. onContentChanged

说明:

onContentChanged方法其实来自于Window的Window.Callback接口中的回调方法,Activity实现了该接口,该方法实际上相当于一个hook方法,每当Window的setContentView方法被调用时它就会被调用。

在onCreate方法中调用的setContentView方法,实际上是会调用Window的setContentView方法,在Activity的源码当中它的实际调用者是PhoneWindow对象,PhoneWindow是Window抽象类的子类,在PhoneWindow的源码中,setContentView方法调用了onContentChanged方法。

也就是说Activity的内容布局发生变化时,就会回调此方法,因此我们可以选择在此方法中进行view的一些初始化操作,比如findViewById()操作,可以放在此方法中进行。不过此方法在实际开发中并不常用,除非你的布局在Activity创建以后会重新设置,此方法或许有用。

3. onStart

说明:

这个方法会在Activity实例被创建的时候,以及经过onStop之后重新返回该Activity时会被调用。来看源码的注释说明:

没有啥特别的,就是除了onCreate会调用它之外,也会在onRestart方法之后调用它(此时肯定是被其他ac遮挡状态)。 经过onRestart方法之后再调用onStart后,窗口将会对用户可见,这也就告诉我们如果想要用户更快的看到界面,就不要在onCreate和onStart方法中做过多无关UI的操作。另外不要忘记在子类的onStart方法中调用super.onStart方法(并尽量保证在第一行),否则同样会抛异常。

4. onRestoreInstanceState

说明:

这个方法比较有意思,主要是用来恢复数据的,在一般情况下它不会被调用,只有当这个Activity是被系统杀死并且需要再次展现该Activity的时候会被调用。

该方法会在onStart方法之后,onPostCreate方法之前被调用,它有一个参数savedInstanceState,这是一个Bundle对象,它是在onSaveInstanceState方法中保存数据的对象参数。

当你需要恢复View的状态时你可以选择在onSaveInstanceState方法中为该参数设置值,这样当Activity被系统销毁重建时就可以在onRestoreInstanceState方法的参数中获得该参数来重新恢复你的布局状态。

值得注意的是,在onCreate方法中也有一个savedInstanceState,它跟onRestoreInstanceState方法里的参数区别是,在onCreate方法中的这个参数是可以为空的(首次创建),而对于onRestoreInstanceState方法,只要它被调用,这个参数就一定不为空。

另外实测发现,该方法确实是 “当且仅当Activity被系统杀死,再由系统恢复” 时,才会被调用的,也就是说假如你主动调用了finish方法去干掉它,或者别人调用了finish方法干掉了它,或者是用户主动干掉了它,或者由于异常挂掉了,都不要指望在它重新创建的时候会走onRestoreInstanceState方法,这时重建Activity的时候都不会调用此方法的。经过我自己的手机上的测试,在发生屏幕旋转的时候Activity重建会调用onRestoreInstanceState方法, 因为这种情况系统也会先杀死Activity然后再重新创建。

5. onPostCreate

说明:

此方法会在onStart和onRestoreInstanceState之后调用,当然如果onRestoreInstanceState没有被调用,那么onStart之后会直接调用它。只有当Activity首次创建的时候才会调用它,当过onStop再次回到Activity时并不会执行它。来看它的源码注释:

官方注释说这个方法通常没必要重写,设计意图是为了给系统类使用的,实际中此方法看起来也确实没多大卵用,你可以选择性的使用。此方法携带savedInstanceState参数,同样可以做恢复View操作。重写的话子类同样必须要调用super方法。

6. onStateNotSaved

说明:

这个方法看起来也没有什么卵用,而且它的调用时机不是严格按照顺序确定的,在一开始的完整流程图中,关于这个方法其实是缺少了一种情况的,当Activity第一次创建的时候,它会在onPostCreate之后被调用,而在Activity经过onStop再返回的时候它的顺序又不是这样的,此时会在onRestart方法之前调用它,但是当我手机锁屏再打开之后它又是在onStart之后调用的。

但不管怎样onStateNotSaved都会保证总是在onResume之前,以及在onNewIntent和onActivityResult之前被调用,这可能是该方法唯一有用的点了吧,可以允许你在onResume或onActivityResult之前的某个时机做一些事情。看了下该方法是在API 23 Android 6.0被加入的。

7. onResume

说明:

这个方法应该很常用了,此方法会在onStart方法之后执行,这是唯一确定的执行顺序,如果是首次创建会执行它,当然当Activity经历onPause或onStop之后也会执行到此方法。如果首次创建时有这几个方法onRestoreInstanceState、onPostCreate、onStateNotSaved,那么onStart会在他们之后执行。

官方注释说明明确指出,不能以此方法作为判断标志来确定当前activity是都是对用户可见的,因为可能有其他的系统弹窗在该activity前面,比如系统软键盘(我想官方这里的意思可能是不一定完全对用户可见,但是经过onResume之后setContentView设置的内容就会显示出来)。同样,子类必须调用super方法,否则会报异常。(尽量保证super在第一行)

虽然官方建议onResume不能作为用户可见的依赖方法,但实际当中基本上我们会在此方法中恢复一些之前停止的状态,如恢复之前在onPause中停止的动画、视频播放、Camera预览等,因为只要onResume被调用了说明用户之前的activity回到前台(有可能不是完全可见,只有一部分可见,但用户肯定是能看到它的,至少是部分),从体验角度来讲是需要这样处理的。

此外,不能在onResume方法中做额外的耗时任务,如数据保存数据库,I/O读写等,这将导致Activity的卡顿,或者用户重新回来的时候卡顿,影响交互体验。

8. onPostResume

说明:

此方法跟onPostCreate方法类似,会紧跟在onResume方法之后被调用。

同样,从官方的注释说明来看它目前并没有什么卵用。。

9. onAttachedToWindow

说明:

该方法是Window中Wind
ow.Callback接口中的方法,该方法会在window被添加的WindowManager上时被调用。从调用顺序上看,它会在onPostResume方法之后被调用,但是只有Activity首次创建才会调用。

官方注释让看View#onAttachedToWindow()方法,但是我看了下View的这个方法中并没有找到调用Window.Callback的onAttachedToWindow方法,于是后来到DectorView类中终于找到了该方法的回调,我们知道DectorView是最顶层的View,当我们设置给PhoneWindow对象的contentView最终都会被加到DectorView上,当然如果你的Activity没有调用setContentView的话,也是会有默认的DectorView对象的。所以,实际上是DectorView被添加到PhoneWindow时会调用此方法。因此onAttachedToWindow在Activity创建后一定被执行的,并且从该方法开始View才真正被绘制在窗口之上,也是我们最终看到的东西。所以严格意义来讲,经过该方法之后Activity才处于可以与用户进行交互的状态。这也是为什么在阿里的android开发手册当中推荐你在onAttachedToWindow方法之后再去创建显示弹窗。

10. onPause

说明:

此方法也是高频使用的方法,通常在Activity不在前台(被其他Activity的页面完全遮挡,或者部分可见)时被调用。

官方注释说明中提到,当另一个Activity B需要被创建来到Activity A的前台时,只有当Activity A的onPause方法执行完毕后,才会执行Activity B的创建生命周期方法。所以不应该在该方法中做任何耗时任务。点击查看:Activity启动另一个Activity并返回的完整生命周期

onPause方法被调用时,我们应该释放或者停止任何消耗CPU资源的行为,以便下一个Activity能得到快速的切换显示,比如结束或者暂停正在执行的动画、正在播放的视频、Camera预览、正在使用的系统服务(如GPS或其他传感器)等等。如有必要,需要在onPause方法中对任何用户正在编辑的信息进行持久化的保存,以便用户再次回来时能恢复之前的状态。

对系统而言,如果你的应用不是在前台,也就是经过onPause之后的(当然是onPause之后的那个Activity不属于你的应用的情况),会变成一个后台进程,而后台进程在内存不足时会被系统杀死。因此onPause方法是我们保存全局持久化数据的一个重要方法。虽然在onResume之后会调用onSaveInstanceState方法,在onSaveInstanceState方法中也可以来保存数据,但是该方法的时机较晚,主要用来保存一些UI状态的数据。

注意,当调用finish方法或被系统杀死的时候,onPause是不会被调用的。另外子类一定要调用super方法,否则会报异常。(并尽量保证在第一行)还有就是如果被自己Activity show出来的弹窗遮挡部分的话,onPause也是不会被调用的,必须是被其他Activity show出来的弹窗才能满足条件。

11. onSaveInstanceState

说明:

此方法会在Activity被销毁时调用,可以在该方法中进行UI状态的保存,并在onCreate或者onRestoreInstanceState方法中进行恢复。

一般情况下它会在onPause方法之后被调用,但是不能指望一定是在onPause方法之后被调用,最简单的情况比如打开一个Activity,然后按back键关闭它,这时系统就不会调用该方法,或者直接调用finish方法也不会调用该方法。当系统内存不足时可能会直接调用该方法,而不会调用其他任何生命周期方法。总之该方法跟生命周期的依赖不是固定的。

目前能确定调用该方法的场景有:按下home键、锁屏、跳转到其他Activity、横竖屏切换。能确定的一点是只要该方法被调用到,那么一定是在onStop之前,跟onPause方法的先后顺序不确定。

实际上即便你不实现该方法,该方法的父类默认实现页会将视图树中拥有id的每个控件的UI状态以及获得视图焦点的id进行保存,并在onRestoreInstanceState方法中来为你恢复每个实例的UI状态。但是如果你有额外的被UI控件持有的信息需要保存,你可能需要重写此方法。

此外,我们应该只在该方法中进行view状态的保存,而不应该依赖该方法做额外的持久化数据保存如数据库保存,上传服务器等等。

12. onStop

说明:

此方法当Activity对用户不可见时被调用,可以在该方法中进行数据持久化保存。

类似onPause方法,此方法中也可以进行资源的释放,因为经过onStop之后该Activity也不在前台了,有可能是按了Home键或者其他Activity来到了前台。假如是按了Home键或其他app来到前台,那么该Activity所处进程变成后台进程有可能被系统杀死,所以需要释放那些系统共享资源如GPS、Camera,或者暂停动画、视频播放等销毁CPU的资源。同时时我们可以在onPause方法保存用户数据,以做现场恢复用。

在onStop方法之后,要么是经历onDestroy方法销毁Avtivity,要么是会在稍后重新返回Activity执行onRestart方法。

在子类中必须调用super方法,否则会抛出异常。(尽量保证在第一行)

13. onRestart

说明:

此方法是当前Activity被其他Activity完全遮挡再返回时调用,也就是经过onStop之后,此方法之后会紧接着调用onStart方法。

官方注释提到如果你使用原生的Cursor对象(而不是通过managedQuery方法),可以在该方法中恢复Cursor请求(因为有可能你在onStop中停止了)Cursor请求。但是我看官方的Cursor#requery()Cursor#deactivate()方法都已经弃用,该方法会导致UI线程的ANR。

同样,如果子类想要覆写此方法的话,要调用super方法,否则抛异常。(并尽量放在第一行)

14. onDestroy

说明:

此方法是Activity被销毁的时候调用,一般是调用了finish方法, 也有可能是系统销毁。

ly implemented to

举报

相关推荐

0 条评论