Android Activity生命周期

470 阅读7分钟

Android生命周期

Android的生命周期:onCreate() -> onStart() -> onResume() -> onPause() -> onStop() -> onDestroy() 如下图所示:

  1. 1.当activity启动时系统会先调用onCreate(),然后调用onStart(),最后调用**onResume()**方法,activity进入运行状态。
  2. 当activity被别的activity 覆盖在其上时:系统会掉用onPause(),然后当覆盖在其上的activity会调用**onCreate() -> onStart() -> onResume()后,第一个activity会调用onStop()**方法使activity暂停。
  3. 当覆盖在其上的第二个activity关闭返回此activity时,系统会先调用第二个activity的**onPause()方法然后再调用第一个activity的onRestart() -> onStart() -> onResume()方法,进入运行状态,此时第二个activity才调用onStop() -> onDestroy()**方法关闭。
  4. 用户退出当前activity:系统先调用onPause(),然后调用onSotp(),最后调用**onDestroy()**方法,结束当前activity。

如下日志打印 第一个activity MainActivity 打开 SingleTopActivity 在返回到 MainActivity

     MainActivity :onPause 方法-------------------------
     SingleTopActivity :onCreate 方法-------------------------
     SingleTopActivity :onStart 方法-------------------------
     SingleTopActivity :onResume 方法-------------------------
     MainActivity :onSaveInstanceState 方法--------------------
     MainActivity :onStop 方法-------------------------
     SingleTopActivity :onPause 方法-------------------------
     MainActivity :onRestart 方法-------------------------
     MainActivity :onStart 方法-------------------------
     MainActivity :onResume 方法-------------------------
     SingleTopActivity :onStop 方法-------------------------
     SingleTopActivity :onDestroy 方法-------------------------
  • onRestart():表示activity正在重新启动,一般情况下是当前activity从不可见重新变成可见状态时,**onRestart()**就会被调用,这种情况一般是用户行为导致的,如从其他页面返回当前页面时,或者用户按home键切换到桌面在重新打开app。

  • onStart()和onStop():onStart()表示activity可见了,但是还没有获取焦点,无法进行交互。onStop()是和onStart()对应的当activity从可见转不可见是调用。

  • onResume()和onPause():onResume()表示activity已经获取焦点了,可以进行交互了,onPause()是和onResume()方法对应的表示当前activity失去了焦点,此时可以做一些存储数据和停止动画等工作,但是不能太好时,不是会影响到新的activity的显示,因为只有onPause()执行完了,新的activity才会进入 onCreate() 等方法。

  • onDestroy():onDestroy()表示activity正在销毁,一般我们是在这进行资源的释放,以避免内存的泄漏。

注意:

- 如果覆盖在其上的activity的风格是dialog风格的化,此activity是不会进入**onSotp()**方法,回到此activity时也**不会调用onRestart()和onStart()方法** 会直接调用**onResume()**方法。

- 如果activity中弹出dialog对话框的时候,**activity是不会调用onPause()方法**;

- 只有旧的activity onPause()方法执行完后,新的activity才启动
- 在所以情况下,系统在调用了onPause()和onStop()之后都会调用onDestroy(),只有一个例外:当你从onCreate()方法类调用了finish()时,在这种情况下,系统会立刻调用onDestroy(),而不调用任何其他生命周期方法。日志如下:
 MainActivity :onPause 方法-------------------------
 DialogActivity :onCreate 方法-------------------------
 MainActivity :onResume 方法-------------------------
 DialogActivity :onDestroy 方法-------------------------

异常情况下的生命周期:比如系统资源配置发生改变以及系统内存不足时,activity就可能被杀死。

  • 情况1:资源相关配置方式改变导致activity被杀死并重新创建。 比如当前activity处于竖屏,旋转屏幕,这时由于activity的系统配置改为了横屏状态,在默认情况下,activity就会被销毁并且重新创建,日志打印如下:
 MainActivity :onCreate 方法-------------------------
 MainActivity :onCreate:MainActivity  TaskId:130  hasCode:151566767
 MainActivity :onStart 方法-------------------------
 MainActivity :onResume 方法-------------------------
 MainActivity :onPause 方法-------------------------
 MainActivity :onSaveInstanceState 方法-------------------------
 MainActivity :onStop 方法-------------------------
 MainActivity :onDestroy 方法-------------------------
 MainActivity :onCreate 方法-------------------------
 MainActivity :onCreate:MainActivity  TaskId:130  hasCode:233659052
 MainActivity :onStart 方法-------------------------
 MainActivity :onRestoreInstanceState 方法-------------------------
 MainActivity :onResume 方法-------------------------
 MainActivity :onPause 方法-------------------------
 MainActivity :onSaveInstanceState 方法-------------------------
 MainActivity :onStop 方法-------------------------
 MainActivity :onDestroy 方法-------------------------
 MainActivity :onCreate 方法-------------------------
 MainActivity :onCreate:MainActivity  TaskId:130  hasCode:262962597
 MainActivity:TaskAffinity:com.hugo.reviewbasic
 MainActivity :onStart 方法-------------------------
 MainActivity :onRestoreInstanceState 方法-------------------------
 MainActivity :onResume 方法-------------------------

在上面这日志中 我们进入MainActivity -> onCreate() -> onStart () -> onResume() 这个时候MainActivity已经在栈顶并获得焦点了,然后我们旋转手机屏幕,

这时调用了 onPause() -> onSaveInstanceState() -> onStop() - onDestroy() 方法把当前MainActivity 销毁了,然后紧接着又重新创建了一个MainActivity -> onCreate() -> onStart() -> onRestoreInstanceState() -> onResume()

这是MainActivity已经重新创建并且是横屏显示的,这是我们又旋转手机屏幕重新竖屏显示 ,这是调用了 onPause() -> onSaveInstanceState() -> onStop() - onDestroy() 方法把当前横屏MainActivity 销毁了,并重新创建了竖屏的MainActivity -> onCreate() -> onStart() -> onRestoreInstanceState() -> onResume()

在这上面的流程我们可以看到 在第一次进入MainActivity 时是每有调用onRestoreInstanceState() 方法的而是在重新创建时才调用了该方法,这个方法是用来做什么的呢?这个方法就是用来在activity被销毁并重新创建时用来恢复我们保存的数据用的,那我们的数据在哪保存的呢,可以看到日志里每次在销毁前都有调用 onSaveInstanceState() 方法,这个方法就是用来保存数据用的。

在onSaveInstanceState()方法中系统会传入Bundle对象用来存储数据,在重新创建时onRestoreInstanceState()方法系统会传入在onSaveInstanceState()方法是存储了数据的Bundle对象,在onRestoreInstanceState()方法里可以在传入的Bundle对象中获取存储的数据进行页面恢复。

根据日志可以看出 onSaveInstanceState() 总是在 onStop()之前调用,而onRestoreInstanceState() 总是在onStart() 之后调用,而且onRestoreInstanceState()在activity第一次创建时是不会调用的。

  • 情况2:在资源不足的情况下导致低优先级的activity被杀死。 这种情况下和前面第一种情况1的数据存储和恢复是完全一致的,activity按照优先级从高到低可以分为以下三种:

    1. 前台activity:正在和用户交互的activity,优先级最高。 2.可见但是非前台activity:就是能看见,但是没有获取到焦点不能和用户进行直接交互。 3.后台activity:已经被暂停的activity,比如执行了onStop()方法,优先级最低。

注意: 必须始终调用 onSaveInstanceState()和onRestoreInstanceState() 的超类实现因为这两个方法默认实现了保存有关activity视图层次的状态信息和恢复视图层次结构状态,列如EditText小部件的文本或ListView的滚动位置。而且所有的View都有onSaveInstanceState()和onRestoreInstanceState()这两个方法。


自行处理配置变更: 我们可以在声明Activity将自行处理配置变更,这样就可以阻止系统重启activity了。 声明时在AndroidManifest.xml文件中编辑相应的""元素,设置以包含的 android:configChanges 属性(最常用的值包括“orientation”和“keyboardHidden”,分别用于避免因屏幕方向和可用键盘改变而导致的重启)。我们可以在该属性中声明多个匹配值,方法是用“ | ”字符分隔这些配置值。 如下配置:

<activity android:name=".singletop.OtherTopActiivty" 
android:configChanges="orientation|screenSize"
android:launchMode="singleTop"/>

现在,当其中一个配置发生改变是OtherTopActiivty不会重启,但是OtherTopActiivty的onConfigurationChanged()方法会被调用,系统会 传入Configuration对象指定新的设备配置。我们可以通过读Configuration中的字段,来确定新配置,进行相应的UI更改。 以下是在onConfigurationChanged()实现检查当前设备的方向:

override fun onConfigurationChanged(newConfig: Configuration?) {   
super.onConfigurationChanged(newConfig)  
LogUtil.i(TAG,"$ActivityName :onConfigurationChanged 方法-------------------------"if(newConfig?.orientation == Configuration.ORIENTATION_LANDSCAPE){     
LogUtil.i(TAG,"$ActivityName :onConfigurationChanged 横屏")  
Toast.makeText(this,"横屏",Toast.LENGTH_SHORT).show()  
}else if(newConfig?.orientation == Configuration.ORIENTATION_PORTRAIT){    
LogUtil.i(TAG,"$ActivityName :onConfigurationChanged 竖屏")   
Toast.makeText(this,"竖屏",Toast.LENGTH_SHORT).show() 
}
}


注意:

  • 自行处理配置变更可能导致备用资源的使用更为困难,因为系统不会自动应用这些资源。所以只有在我们必须避免activity因配置改变而重启这种情况下,才考虑采用自行处理配置变更这种方法,而且对于大多数应用并不建议使用此方法。
    
  • 在Android3.0(API 级别13)开始,设备在纵向和横向之间切换时,“屏幕尺寸”也会发生改变,因此在开发针对API级别13或更高版本的应用时,若要避免由于设备方向的改变而导致运行时重启,则除了“orientation”值外,还必须添加“screenSize“值。也就是必须声明android:configChanges="orientation|screenSize"。
    
  • 在声明有Activity处理配置变更时,我们有责任要为其提供备用资源的所有元素。如声明了activity处理方向变更,有些图像是应该横向和纵向之间切换,则必须在 onConfigurationChanged()方法中将每个资源重新分配给每个元素。
    

这个例子代码在这里