路漫漫其修远兮,吾将上下而求索。---屈原《离骚》
可能很多人会感觉Activity很简单,但是经历了半年的android开发,我发现我对Activity的的理解还是比较浅显的,其实Activity并没有我们想象的那么简单今天花了一个下午学习了Activity的生命周期,为以后忘记后迅速回顾,做准备。
一、首先看下官网给出activity的生命周期图
我们可以从图中分析它的执行过程:
1.启动Activity:系统会首先调用onCreate方法,然后调用onStart方法,最后调用onResume()方法。此时Activity进入运行状态
2.当前Activity被其他Activity覆盖或处于锁屏状态:系统会调用onPause方法,然后调用onStop方法,此时Activity处于停滞状态。
3.当前Activity由覆盖状态回到前台或解锁屏:系统会调用onRestart方法,然后调用onStart方法,最后调用onResume方法,再次进入运行状态。
4.当前Activity跳转到新的Activity界面或Home键回到主屏,退到后台:系统会先调用onPause方法,然后调用onStop方法进入停滞状态
5.用户后退回到此Activity:系统会先调用onRestart()方法,然后调用onStart方法,最后调用onResume方法,再次进入运行状态
6.当前Activity处于被覆盖状态或者后台不可见状态,即第二和第四步,系统内存不足,杀死当前Activity,而后用户退回当前Activity:再次调用onCreate方法、onStart方法、onResume方法,进入运行状态。
7.用户退出当前Activity:系统会调用onPause方法,然后调用onStop方法最后调用onDestroy方法,结束当前Activity
以上的Activity方法的生命周期是很简单的,但是任何简单的东西,只有我们通过实例验证才能理解的更加透彻,记忆更加深刻,
二、实例分析
实例代码:
package com.example.activitypractice; import android.app.Activity; import android.content.Intent; import android.content.res.Configuration; import android.os.Bundle; import android.util.Log; import android.view.View; import android.view.View.OnClickListener; import android.widget.Button; public class MainActivity extends Activity { private static final String TAG = "MainActivity"; private Button btn_jump; private String saveData= "存放的数据" ; //Activity创建时调用 @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout. activity_main); btn_jump=(Button) findViewById(R.id. btn_jump); btn_jump.setOnClickListener( new OnClickListener() { public void onClick(View v) { Intent intent= new Intent(MainActivity.this,JumpToActivity.class ); startActivity(intent); } }); Log. i(TAG,"执行了onCreate方法" ); } //Activity创建或者从后台重新回到前台时被调用 @Override protected void onStart() { super.onStart(); Log. i(TAG,"执行了onStart方法" ); } //Activity从后台重新回到前台时被调用 @Override protected void onRestart() { super.onRestart(); Log. i(TAG,"执行了onRestart方法" ); } //Activity创建或者从被覆盖、后台重新回到前台时被调用 @Override protected void onResume() { super.onResume(); Log. i(TAG,"执行了onResume方法" ); } //Activity被覆盖到下面或者锁屏时被调用 @Override protected void onPause() { super.onPause(); Log. i(TAG,"执行了onPause方法" ); } //退出当前Activity或者跳转到新Activity时被调用 @Override protected void onStop() { super.onStop(); Log. i(TAG,"执行了onStop方法" ); } //退出当前Activity时被调用,调用之后Activity就结束了 @Override protected void onDestroy() { super.onDestroy(); Log. i(TAG,"执行了onDestroy方法" ); } //Activity窗口获得或失去焦点时被调用,在onResume之后或onPause之后 /* @Override public void onWindowFocusChanged(boolean hasFocus) { super.onWindowFocusChanged(hasFocus); Log.i(TAG, "onWindowFocusChanged called."); } */ /** * Activity被系统杀死时被调用. * 例如:屏幕方向改变时,Activity被销毁再重建;当前Activity处于后台,系统资源紧张将其杀死. * 另外,当跳转到其他Activity或者按Home键回到主屏时该方法也会被调用,系统是为了保存当前View组件的状态. * 在onPause之前被调用. */ @Override protected void onSaveInstanceState(Bundle outState) { outState.putString( "key", saveData); Log. i(TAG, "onSaveInstanceState called.put saveData: " + saveData ); super.onSaveInstanceState(outState); } /** * Activity被系统杀死后再重建时被调用. * 例如:屏幕方向改变时,Activity被销毁再重建;当前Activity处于后台,系统资源紧张将其杀死,用户又启动该Activity. * 这两种情况下onRestoreInstanceState都会被调用,在onStart之后. */ @Override protected void onRestoreInstanceState(Bundle savedInstanceState) { String getData = savedInstanceState.getString( "key"); Log. i(TAG, "onRestoreInstacedState called.getData: "+getData); super.onRestoreInstanceState(savedInstanceState); } }
在上面的例子中我们可以看到还有三个不是特别常见的方法,onWindowFocusChanged、onSaveInstanceState、onRestoreInstanceState方法这三个方法我们用的比较少下面也来说说它们的用法:
(1)onWindowFocusChanaged方法
在Activity窗口获得或失去焦点时调用,例如创建时首次展示在用户面前、当Activity被其它Activity所覆盖、Activity退到后台、用户退出当前Activity,这几种条件都会调用onWindowFocusChanaged,并且当Activity被创建时是在onResume之后被调用,当Activity被覆盖或者退到后台或当前Activity退出时它是在onPause之后被调用的,如下图Activity启动之后被其它的activity覆盖(点击我们的跳转按钮)打印的日志
这个方法在很多场合下还是很有用的,例如程序启动时想要获取组件的尺寸大小,在onCreate中是无法取到的因为Window对象还没有创建完,这时候我们就需要在onWindwosFocusChanaged里获取,这也是我们常用的方法。
(2)onSaveInstanceState:
1.在Activity被覆盖或者退到后台之后,系统资源不足,将其杀死,此方法会被调用;
2.在用户改变屏幕方向时此方法会被调用;
3.在当前Activity跳转到其他Activity或者按Home键回到主屏,自身退到后台时,此方法会被调用。
第一种情况我们无法保证什么时候发生,系统根据资源的紧张程度去调度;第二种是屏幕翻转方向时,系统先销毁当前Activity,然后再重建一个新的,调用此方法时,我们可以保存一些临时数据,例如:当竖屏时加载一个进度条,切换到横屏时如果不保存当前加载到多少横屏时会重0开始,保存后就可以继续加载,第三种情况系统调用此方法是为了保存当前窗口各个View组件的状态。onSaveInstanceState的调用顺序是在onPause之后,如下图是在跳转到其它的Activity所执行的方法
我们从图中可以看出onSaveInstanceState方法是在onPause方法中执行的
(3)onRestoreInstanceState
1.在Activity被覆盖或是退居后台之后,系统资源不足将其杀死,然后又回到了此Activity,此方法会被调用
2.在用户改变屏幕方向时,重建的过程中,此方法会被调用。我们可以重写此方法,以便恢复一些临时数据。onRestoreInstanceState的调用顺序是在onStart方法之后。
之后我们来结合上面的例子来一 一看看Activity的生命周期在各种的情况下的变化
1.启动Activity:
启动Activity:系统会首先调用onCreate方法,然后调用onStart方法,最后调用onResume()方法。此时Activity进入运行状态
2.在1跳转到其他的Activity,或按Home键
系统会先调用onPause方法,然后调用 onSaveInstanceState方法,然后调用onStop方法进入停滞状态
3.从后台回到前台
系统会先调用onRestart方法,然后调用onStart方法,然后调用onResume方法
4.修改在AndroidMainfest.xml中的配置,将android:theme属性设置为@android:style/Theme.Dialog,然后再点击跳转按钮,然后JumpToActivity覆盖到LifeCycleActivity之上了,
此时调用的方法为:onPause和onSaveInstanceState,我们注意到,此时MainActivity的onPause方法被调用,并没有执行onStop方法,因为此时的MainActivity没有退居到后台只是被覆盖或被锁屏;onSaveInstanceState会在onPause之后被调用
5.在4的基础上按回退键MainActivity从被覆盖回到前面
此时执行onResume方法
6.退出
系统调用onPause、onStop、onDestroy方法。
不知道大家有没有发现在上面的所有的日志中并没有执行onRestoreInstanceState方法,为什么没有执行它呢没有满足它执行的条件,从上面onRestoreInstanceState执行的条件我们发现第一种是不可预测的,但是第二种(即改变屏幕方向)的话我们可以模拟的
三、Activity屏幕方向的知识
我们可以为一个Activity指定一个特定的方向,指定之后即使转动屏幕方向,显示方向也不会跟着转动
1.指定为竖屏:在AndroidManifest.xml文件中对指定的Activity设置android:screenOrientation:="portrait",
或者在onCreate方法中指定代码为:
setRequestOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);就指定为了竖屏
2.指定为横屏:在AndroidManifest.xml文件中对指定的Activity设置android:screenOrientation:="landscape",
或者在onCreate方法中指定代码为:
setRequestOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);就指定为了竖屏
在开发应用的过程中,为应用中的Activity设置特定的方向是经常用到的方法,可以为我们省去很多麻烦,但是我为了让onRestoreInstanceState方法执行采用的是不固定屏幕的显示方向我们对上面的代码稍作修改加上onConfigurationChanged方法
现在源码如下:
package com.example.activitypractice; import android.app.Activity; import android.content.Intent; import android.content.res.Configuration; import android.os.Bundle; import android.util.Log; import android.view.View; import android.view.View.OnClickListener; import android.widget.Button; public class MainActivity extends Activity { private static final String TAG = "MainActivity"; private Button btn_jump; private String saveData= "存放的数据" ; //Activity创建时调用 @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout. activity_main); btn_jump=(Button) findViewById(R.id. btn_jump); btn_jump.setOnClickListener( new OnClickListener() { public void onClick(View v) { Intent intent= new Intent(MainActivity.this,JumpToActivity.class ); startActivity(intent); } }); Log. i(TAG,"执行了onCreate方法" ); } //Activity创建或者从后台重新回到前台时被调用 @Override protected void onStart() { super.onStart(); Log. i(TAG,"执行了onStart方法" ); } //Activity从后台重新回到前台时被调用 @Override protected void onRestart() { super.onRestart(); Log. i(TAG,"执行了onRestart方法" ); } //Activity创建或者从被覆盖、后台重新回到前台时被调用 @Override protected void onResume() { super.onResume(); Log. i(TAG,"执行了onResume方法" ); } //Activity被覆盖到下面或者锁屏时被调用 @Override protected void onPause() { super.onPause(); Log. i(TAG,"执行了onPause方法" ); } //退出当前Activity或者跳转到新Activity时被调用 @Override protected void onStop() { super.onStop(); Log. i(TAG,"执行了onStop方法" ); } //退出当前Activity时被调用,调用之后Activity就结束了 @Override protected void onDestroy() { super.onDestroy(); Log. i(TAG,"执行了onDestroy方法" ); } /** * Activity被系统杀死时被调用. * 例如:屏幕方向改变时,Activity被销毁再重建;当前Activity处于后台,系统资源紧张将其杀死. * 另外,当跳转到其他Activity或者按Home键回到主屏时该方法也会被调用,系统是为了保存当前View组件的状态. * 在onPause之前被调用. */ @Override protected void onSaveInstanceState(Bundle outState) { outState.putString( "key", saveData); Log. i(TAG, "onSaveInstanceState called.put saveData: " + saveData ); super.onSaveInstanceState(outState); } /** * Activity被系统杀死后再重建时被调用. * 例如:屏幕方向改变时,Activity被销毁再重建;当前Activity处于后台,系统资源紧张将其杀死,用户又启动该Activity. * 这两种情况下onRestoreInstanceState都会被调用,在onStart之后. */ @Override protected void onRestoreInstanceState(Bundle savedInstanceState) { String getData = savedInstanceState.getString( "key"); Log. i(TAG, "onRestoreInstacedState called.getData: "+getData); super.onRestoreInstanceState(savedInstanceState); } //当指定了android:configChanges="orientation"后,方向改变时onConfigurationChanged被调用,并且activity不再销毁重建 @Override public void onConfigurationChanged(Configuration newConfig) { super.onConfigurationChanged(newConfig); switch (newConfig. orientation) { case Configuration. ORIENTATION_PORTRAIT://竖屏 Log. i(TAG,"竖屏" ); setContentView(R.layout. portrait); break; case Configuration. ORIENTATION_LANDSCAPE://横屏 Log. i(TAG,"横屏" ); setContentView(R.layout. landscap); default: break; } } }
需要注意的是我们必须在手机上设置(注意:要在设置中设置自动旋转屏幕我用的三星的测试机是在设定-->我的设备-->显示
在"显示"里有"自动旋转屏幕"选项)自动旋转屏幕才可以
然后当我们旋转屏幕时,我们会看到Activity首先会销毁然后重建,系统会调用onSaveInstanceState方法并在Bundle对象中保存了一个临时的数据,当Activity销毁后再重建时调用onRestoreInstancedState方法我们从中可以把保存的数据取出来日志如下:
但是Activity销毁后再重建,这有时候并不是我们想要的,那么我们应该怎样避免这种情况呢?这是我们应该在清单文件中对应的Activity中配置android:configChanges="orientation"然后我们再旋转屏幕
每次在旋转的时候都调用了onConfigurationChanged方法,并且Activity没有了销毁重建的过程
在上面的配置过程中我们需要注意几点:
1.如果在Activity中配置了android:screenOrientation属性,则会使android:configChanges="orientation"失效。
2.在配置android:configChanges时需要注意:如果是Android 4.0,则是"orientation|keyboardHidden|screenSize",如果是
4.0之前的版本android:configChanges="orientation|keyboardHidden"
关于android:configChanges配置时需注意的事项见此链接