阅读 714

Android面试之Activity补漏

Activity生命周期详解

从一个问题开始:一个Activity开启另外一个Activity,生命周期是怎么走的呢?到了金三银四就开始慌了,一趴基础发现漏洞真的多哎~

一 Activity的四种状态:

Activity的生命周期中存在四种基本的状态:活动状态(Active/Runing),暂停状态(Paused),停止状态(Stopped),销毁状态(Killed)。每个状态下Activity都会拥有某些能力和失去某些能力。

  • 活动状态(Active/Runing)

    一个新的Activity入栈之后,当处于Activity的栈顶,此时它处于可见并且能与用户交互的激活状态,叫做活动状态或者运行状态。

    期间触发的生命周期有: onCreate() -> onStart() -> onResume()。

  • 暂停状态(Paused)

    当Activity是去焦点,一个新的非全屏的Activity或者一个透明的Activity被放置在栈顶。注意:在Activity之上显示Dialog或者PoupWindow的时候,该Activity并不会变成暂停状态。一个处于暂停状态下的Activity只有再通极度匮乏的时候才会被回收掉。

    运行状态到暂停状态触发的生命周期:onResume() -> onPause()。

    从暂停状态恢复到运行状态触发的生命周期:onPause() -> onResume()。

  • 停止状态(Stopped)

    一个Activity被另外一个Activity完全覆盖掉,用户不可见或者退至后台,叫做停止状态。它仍然保持这所有状态跟成员信息,不能与用户交互。当系统内存需要的时候Stopped状态的Activity会被强制回收掉。

    从暂停到停止状态触发的生命周期:onPause() -> onStop()。

    从停止状态到运行状态触发的生命周期:onStop() -> onRestart() -> onStart() -> onResume()。不会走onCreate()。

  • 销毁状态(Killed)

    如果一个Activity再Paused或者Stopped状态,系统可以将Activity从内存中删除,删除的方式有两种:一种是要求Activity结束,一种直接结束掉它的进程。当有需要的时候就得重新创建Activity了。

    触发的生命周期:onDestroy(),直接结束进程的话是不会走onDestroy()的。

上面是Activity在整个生命周期中展示的四种状态。程序员可以手动创建一个Activity,但不能手动的销毁一个Activity。也就是说当调用activity.finish()方法或者按下物理返回键去关掉一个Activity的时候,只是通知了AntivityManager该Activity可以被回收了,随后ActivityManage将采取一系列的回收措施,这是开发者无法干预的。

二 完整的生命周期:

Activity完整的生命周期 :

oncreate()->onstart()->onResume()->onRestart()->onPouse()->onStop()->onDestory()。

Activity在创建到销毁的过程中会走的完整的生命周期,但是并一定每次创建跟销毁都会完整的走一遍。

图是百度百科的

  • oncreate()

    Activity创建的时候第一个走的生命周期。这个生命周期中可以做一些初始化的工作:调用setContentView()去加载UI试图,可以用findViewById跟布局里面的组件进行交互,调用managedQuery(),使用Bundle恢复数据等等方法。系统表示在该方法内应该调用setContentView()和进行findViewById的操作,当然别的生命周期也是可以调用setContentView()和进行findViewById()操作的。大多情况下页面的数据是只需要初始化一次,那么也就必须在onCreate()方法中去初始化,这也就是为啥我们老是在onCreate()方法中去加载我们需要的组件。

    特点: 不可见,不可交互,可初始化数据。

    注意: onCreate()生命周期中直接执行onFinish()方法的时候,Activity将直接被调用onDestroy()方法不会走其他的生命周期。Activity在调用过该方法之后才会调用onStart方法,顺序执行,所以不要在该方法中做一些耗时的工作,影响界面的启动速度。

  • onStart()

    在onCreate()方法之后调用或者onRestart()之后。源码并没有对此方法做过多的解释,只是说有两个地方会执行到该方法:一次是创建的时候,一次是暂停状态到活动状态的时候。这个方法开发中勇的不多,适合开启在Activity活跃状态下才要执行的任务:开始计时,接口轮询,启动广播,开启后台任务等。该方法不适合大量的数据初始化,因为它会执行多次。

    特点: 可见,不可交互,如果在onCreate()方法中完成数据的初始化这时就可以直接操作数据了。

    注意: 整个Activity生命周期中可别执行多次,切记一定要正确的使用该声明周期。

  • onResume()

    再onStart(),onRestoreInstanceState(),onRestart(),onPause()方法之后都会执行onResume()。源码注释说这里建议开启动画,或者打开一些独享设备(照相机)等的操作。该方法会在Activity的整个生命周期中频繁的调用,写在里面的逻辑要非常的慎重。常见的功能:当页面可见的时候刷新页面的数据,这个虽然会浪费资源但是有的时候确实很有用的。一般为了控制某些代码在该生命周期里面只执行一次,可以添加一个标记为去控制一下,也是一个不错的选择,毕竟当用户可见的时候这个方法就会被执行一次...

    特点: 可见,可交互,Activity位于的活动栈顶部。

    注意: 该方法会频繁的调用,慎重节约资源。

  • onPause()

    当Activity是去焦点后会被调用,页面被透明的活着半透明的Activiy部分遮挡。该方法调用可能是Activity要被销毁,也可能是页面进入后台。被调用的频率不算很多,适合保存一些持久化数据,比如EditText的展示数据恢复,停止一些动画和一些消耗cpu的任务,或者关闭独占访问的资源等(如:相机)等。该方法尝尝伴随着onStop()执行但也有情况直接调用onResume()方法。开发中都没怎么用到过该方法...

    特点: 可见,不可交互,可以被系统回收。

    注意: 该方法常再Activity处于停止状态下调用,当启动另一个Activity的时候,新启动的Activity必须等到该Activity的onPause()方法执行才会执行自己的onCreate()…等方法。所以不要在该方法里面做耗时的操作以免影响启动新Activity的效率。另外就算是Activity被系统强制的回收也一定会走这个方法,可以不走onDestroy()。

  • onStop()

    当Activity不可见的时候调用。此时Activity处于停止状态,当页面被完全遮挡,按下Home建页面进入后台,Activity销毁等。该方法适合停止一些消耗资源的操作:结束倒计时,接口数据轮训,取消注册的广播,关闭后台的服务等。但是千万不要再该方法中释放一些运行状态下要用到的一些数据。之前做过在onStop的时候将一个引用置为NULL来回收资源,就是因为看到了文章说建议在这个声明周期内回收资源,结果可想而知...

    该方法之后会调用onRestart() -> onStart() -> onResume()。或者调用onDestroy()。

    特点: 不可见,不可交互,可以被系统回收。

    注意: 释放Activity持有的资源要慎重,有网络轮询尽量关掉轮询,切断倒计时或者一些单个网络请求等。当Activity被强制回收内存的时候Android版本是3.0之后该方法也是一定会走的,可以不走onDestroy()。

  • onDestroy()

    在Activity的整个生命周期中只会执行一次,也就是Activity将要被销毁的时候,通常是调用了finish()方法或者系统内存不足强制销毁。在这里一般要进行持有资源的全部释放工作,将集合清空,引用置为null,销毁一些单例,取消网络请求,以及清空Handler数据等等,保证不会出现内存泄漏的情况。可以调用Activity.isFinish去判断该Activity是否已经销毁。不要尝试再该方法中去保存一些数据,这只是系统的警告,我们还是会再该方法里面去保存一些SP数据的…另外:在某些情况下,系统会简单地终止活动的宿主进程,而不调用其中的此方法(或任何其他方法),因此不应将其用于执行进程结束后要保留重要数据的操作。

    特定: 可以放心的回收资源。

    注意: 在回收资源的时候也要进行一些判空,以免发生意外。尽量不要再该方法里面去保存一下重要的数据。界面被系统回收的时候该方法可能不会被调用。

三 常见的生命周期的问题

1.当前Activity启动另外一个Activity,启动之后关掉新Activity的时候两个生命周期的变化:

ActivityA 启动 Activity B :

ActivityA : onPause() -> ActivityB :onCreate() -> ActivityB:onStart() -> ActivityB :onResume() -> ActivityA : onStop()。

这也就是打开一个新的Activity一定要等当前的Activity的onPause()方法走完之后才会去创建新的Activity。

2.屏幕旋转:

Activity :onpause() -> onStop() -> onCreate() -> onStart() -> onResume()。

当屏幕旋转的时候Activity会销毁创建,这一点一定要记得,如果Activity发生泄漏的话旋转次数多了就会导致内存占用越多最终导致OOM。

另外屏幕旋转将会导致布局拉伸或者压缩,严重影响UI界面美观性,除非你已经做了适配。建议直接将界面设置成不可旋转的吧。

3.按home键:

Activity进入后台 : onPause() -> onStop() 。回到前台:onRestart() -> onStart() -> onResume()。

有可能应用会被系统杀死进程。

4.系统回收:

首先每个应用最少有一个进程,我们的Activity都是运行在进程中的,当应用退到后台时,系统可能因为内存不足而杀掉优先级低的进程,那么再该进程中的Activity都会被杀死,这种情况是不会走Activity的生命周期的,只有杀掉单个Activity的时候才会走Activity的onDestroy()方法。

5.调用finish方法:

调用finish()方法的时候需要区分在那个生命周期内执行的该方法,这里是执行并不是在那个生命周期内写了finishi()的代码。

onCreate()生命周期内直接执行了finish()方法: onCreate() -> onDestroy()。

onStart()生命周期内直接执行了finish()方法: onCreate() -> onStart() -> onStop() -> onDestroy()。

onResume()生命周期内直接执行了finish()方法:onCreate() -> onStart() -> onResume() -> onPause()

-> onStop() -> onDestroy()。

注意点击事件是观察者模式,当执行的时候Activity一定onResume了。

6.物理返回键onKeyDown方法:

Activity : onpause() -> onStop() -> onDestroy()。

7.onSaveInstanceState()方法:

google工程师们对onSaveInstanceState如此设计就是让其完成对一些临时的、非永久数据存储并进行恢复。什么样的数据属于临时数据呢?举个例子,比如EditText中输入的内容,CheckBox是否勾选,ScrollView的滑动位置,目前视频的播放位置等等。 由于onSaveInstanceState()方法方法不一定会被调用(如:主动点击back按键时), 因此不适合在该方法中保存持久化数据,例如向数据库中插入记录等。保存持久化数据的操作应该放在onPause()中。 onSaveInstanceState()方法只适合保存瞬态数据, 比如UI控件的状态,,成员变量的值等。当Activity被系统回收的时候是一定会走这个方法的,所以可以再该方法的Bundle里面保存一些数据用来重新恢复。

8.Dialog,PopupWindow或者DialogActivity:

当Activity之上显示出Dialog或者PopupWindow的时候是不会走任何的生命周期的,Toast也是一样的。当出现了Dialog风格的Activity的时候会走 onPause() -> onSaveInstanceState()。消失后会走onResume()。

9.息屏时再打开:

Activity : onPause() -> onStop() -> onRestart() -> onStart() -> onResume()。

10.再Activity的生命周期内直接调startActivity(Intent)方法:

AActivity再onPause()生命周期前调用启动BActivity :

AActivity : onCreate() -> AActivity:onStart -> AActivity : onResume -> AActivity : onPause -> BActivity : onCreate() -> BActivity : onStart() -> BActivity : onResume().

也就是打开一个新的Activity一定要等到当前的Activity的onPasuse()生命周期走过。这一点其实很有用的,比如当我们想要在界面一开始的时候做一些操作,然后直接跳到别的界面,在onCreate()里面写了跳转逻辑,之后又写了一大堆的逻辑代码,最后反而影响了新界面的打开速度。最好是加个Return,让后面的逻辑代码不执行。

11.启动一个再前台的且启动模式为singleTop的Activity:

Activity : onPause() -> onNewIntent() -> onResume()。

12.再当前Activity界面进入设置界面更改了一些已有的设置,或者Activity发生异常奔溃重建:

Activity : onPause() -> onStop() -> onDestroy() -> onCreate() -> onStart() (会执行这个方法onRestoreInstance() )-> onResume()。

欢迎点击哦

我的GitHub里面有好多适合学习的框架,都是按照最流行的框架来的~

关注下面的标签,发现更多相似文章
评论