深刻理解Activity的生命周期和onSaveInstanceState()

Activity类中定义了7个回调方法,覆盖了活动声明周期的每一个环节。

在这里插入图片描述
不要小看这张图,你总是说你看的多了,你真的了解吗?

onCreate()

你应该在这个方法中完成活动的初始化操作,比如加载布局,绑定时间等。

onStart()

这个方法在活动由不可见变为可见的时候调用。
此时的活动一定位于返回栈的栈顶,并且处于运行状态。

onResume()

这个方法在活动准备好和用户进行交互的时候调用,此时的活动一定位于返回栈的栈顶,并且处于运行状态

onPause()

这个方法在系统准备去启动或者恢复另一个活动的时候调用,我们通常会在这个方法中将一些消耗CPU的资源释放掉,以及保存一些关键数据,但这个方法的执行速度一定要快,不然会影响到新的栈顶活动的使用。

onStop()

这个方法在活动完全不可见的时候调用。它和onPause()方法的主要区别在于,如果启动的新活动是一个对话框式的活动,那么onPause()方法会得到执行,而onStop()方法并不会执行。

onDestroy()

这个方法在活动被销毁之前调用,之后活动的状态将变为销毁状态。

onRestart()

这个方法在活动由停止状态变为运行状态之前调用,也就是活动被重新启动了。
以上7个方法除了onRestart()方法,其他都是两两相对的,从而又可以将活动分为3种生存期。

onCreate和onStart之间有什么区别?

(1)可见与不可见的区别。前者不可见,后者可见。
(2)执行次数的区别。onCreate方法只在Activity创建时执行一次,而onStart方法在Activity的切换以及按Home键返回桌面再切回应用的过程中被多次调用。因此Bundle数据的恢复在onStart中进行比onCreate中执行更合适。
(3)onCreate能做的事onStart其实都能做,但是onstart能做的事onCreate却未必适合做。如前文所说的,setContentView和资源初始化在两者都能做,然而想动画的初始化在onStart中做比较好。

onStart方法和onResume方法有什么区别?

(1)是否在前台。onStart方法中Activity可见但不在前台,不可交互,而在onResume中在前台。
(2)职责不同,onStart方法中主要还是进行初始化工作,而onResume方法,根据官方的建议,可以做开启动画和独占设备的操作。

onPause方法和onStop方法有什么区别?

(1)是否可见。onPause时Activity可见,onStop时Activity不可见,但Activity对象还在内存中。
(2)在系统内存不足的时候可能不会执行onStop方法,因此程序状态的保存、独占设备和动画的关闭、以及一些数据的保存最好在onPause中进行,但要注意不能太耗时。

onStop方法和onDestroy方法有什么区别?

onStop阶段Activity还没有被销毁,对象还在内存中,此时可以通过切换Activity再次回到该Activity,而onDestroy阶段Acivity被销毁

完整生存期。

活动在onCreate()方法和onDestroy()方法之间所经历的,就是完整生存期。

可见生存期。

活动在onStart()方法和onStop()方法之间所经历的,就是可见生存期。

前台生存期

活动在onResume()方法和onPause()方法之间所经历的就是前台生存期。
在前台生存期内,活动总是处于运动状态,此时的活动是可以和用户进行交互的。我们平时看到和接触最多的也就是这个状态下的活动。

onSaveInstanceState()和onRestoreInstanceState()

回调方法。这个方法可以保证在活动被回收之前一定会被调用。
因此我们可以通过这个方法来解决活动被回收时临时数据得不到保存的问题。

在系统内存不足时,系统可能回收Activity,如果没有保护措施的话,在很多信息输入的界面,重新打开可能全部丢失,用户体验非常不好。
这个时候可以使用onSaveInstanceState(Bundle outState)来解决问题,这个方法可以保证被回收前一定会调用,然后再oncreate中返回savedInstanceState 取出数据即可。

注意
1、如果是用户自动按下返回键,或程序调用finish()退出程序,是不会触发onSaveInstanceState()和onRestoreInstanceState()的。
2、每次用户旋转屏幕时,您的Activity将被破坏并重新创建。当屏幕改变方向时,系统会破坏并重新创建前台Activity,因为屏幕配置已更改,您的Activity可能需要加载替代资源(例如布局)。即会执行onSaveInstanceState()和onRestoreInstanceState()的。

public class StartActivity extends AppCompatActivity {
    
    
    private static final String TAG = "StartActivity";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
    
    
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Log.d(TAG, "onCreate: ");
        if (null != savedInstanceState) {
    
    
            String key1 = savedInstanceState.getString("key1");
            String key2 = savedInstanceState.getString("key2");
            Log.d(TAG, "onCreate: key1=" + key1+ ";key2 =" + key2 );
        }
    }

    @Override
    protected void onSaveInstanceState(Bundle outState) {
    
    
        Log.d(TAG, "onSaveInstanceState: ");
        outState.putString("key1", "113");
        super.onSaveInstanceState(outState);
        outState.putString("key2 ", "113-k2");
    }
}

在onSaveInstanceState方法中,调用 super.onSaveInstanceState(outState);之前和之后都可以生效,不过建议尽量在之前调用。

onCreate()可以选择执行onRestoreInstanceState(),而不是在系统调用onStart()方法之后恢复状态。系统onRestoreInstanceState()只有在存在保存状态的情况下才会恢复,因此您不需要检查是否Bundle为空:

public void onRestoreInstanceState(Bundle savedInstanceState) {
    
    
    // 总是调用超类,以便它可以恢复视图层次超级
    super.onRestoreInstanceState(savedInstanceState);
   
    // 从已保存的实例中恢复状态成员
    mCurrentScore = savedInstanceState.getInt(STATE_SCORE);
    mCurrentLevel = savedInstanceState.getInt(STATE_LEVEL);
}

调用时机

onSaveInstanceState方法会在什么时候被执行,有这么几种情况:

  • 当用户按下HOME键时。
    这是显而易见的,系统不知道你按下HOME后要运行多少其他的程序,自然也不知道activity A是否会被销毁,故系统会调用onSaveInstanceState,让用户有机会保存某些非永久性的数据。以下几种情况的分析都遵循该原则。

  • 长按HOME键,选择运行其他的程序时。

  • 按下电源按键(关闭屏幕显示)时。

  • 从activity A中启动一个新的activity时。

  • 屏幕方向切换时,例如从竖屏切换到横屏时(如果不想重建,那么需在AndroidManifest.xml中对对应的Activity做如下设置:

android:configChanges="orientation|screenSize"

orientation选项指在屏幕方向发生改变,screenSize选项指屏幕尺寸发生改变,由于旋转屏幕时屏幕尺寸会发生变化,所以必须设置screenSize选项。activity不被重建,系统也就不会调用onSaveInstanceonRestoreInstance方法,而会调用onConfigChanged方法。
需要说明的是,configChanges属性是Android 3.2(API 13)中新加入的,所以当编译选项的minSdkVersion和targetSdkVersion均小于13时,则无需设置screenSize。)

猜你喜欢

转载自blog.csdn.net/i_nclude/article/details/74936446