Activity横竖屏切换生命周期

 Activity横竖屏切换生命周期

/**
* onCreate : 创建activity时调用。设置在该方法中,还以Bundle中可以提出用于创建该 Activity 所需的信息
* onStart : activity变为在屏幕上对用户可见时,即获得焦点时,会调用
* onResume : activity开始与用户交互时调用(无论是启动还是重新启动一个活动,该方法总是被调用的)
* onPause : activity被暂停或收回cpu和其他资源时调用,该方法用于保存活动状态的
* onStop : activity被停止并转为不可见阶段及后续的生命周期事件时,即失去焦点时调用
* onDestroy : activity被完全从系统内存中移除时调用,该方法被调用可能是因为有人直接调用 finish()方法 或者系统决定停止该活动以释放资源
*
* onSaveInstanceState : 不是生命周期方法,只有在由系统销毁一个Activity时,会被调用
* onRestoreInstanceState : 不是生命周期方法,只有在activity被系统回收,重新创建activity的情况下才会被调用
* onConfigurationChanged : 不是生命周期方法,当系统的配置信息发生改变时,系统会调用此方法
*
*/

一、屏幕横竖屏切换的代码

竖屏

setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);

横屏

setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);

获得当前屏幕状态

getResources().getConfiguration().orientation

此状态可为:Configuration.ORIENTATION_PORTRAITConfiguration.ORIENTATION_LANDSCAPE

二、横竖屏切换Activity生命周期回调

横竖屏属性可以在AndroidManifest.xml中设置,也可以在MainActivity.java中进行设置(上面已经提及)。

本节主要讲解在AndroidManifest.xml中的设置

<activity android:name=".MainActivity"
    android:configChanges="orientation|keyboardHidden|screenSize"
    android:screenOrientation="portrait">
</activity>

(一)configChanges属性

设置configChanges这个值可以避免Activity生命周期被回到。该部分具体的参数:

  • orientation:屏幕在纵向和横向间旋转
  • keyboardHidden:键盘显示或隐藏
  • screenSize:屏幕大小改变
  • fontScale:用户变更了首选字母大小
  • locale:用户选择了不同的语言设定
  • keyboard:键盘类型变更,如手机从九宫格键盘变为全键盘
  • touchscreen或navigation:键盘或导航方向变换,一般不会发生这种情况。

前面三个是常用的,后面属性很少使用

如果要activity中的生命周期不回调,就要设置:

android:configChanges="orientation|keyboardHidden|screenSize"

缺少其中任一一个都会Activity生命周期回调,即如下情况:

不发生回调是如下情况:

在这附上对应的代码:

MainActivity.java

public class MainActivity extends AppCompatActivity {
    private String TAG = "MainActivity";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Log.i(TAG, "onCreate");

        Button bt = (Button)findViewById(R.id.bt_skip_other_activity);
        bt.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if(getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT)
                    setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
                else
                    setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
            }
        });
    }

    @Override
    public void onConfigurationChanged(@NonNull Configuration newConfig) {
        super.onConfigurationChanged(newConfig);
        Log.i(TAG, "onConfigurationChanged");
        initChange();
    }

    private void initChange(){
        if(getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT)
            Log.i(TAG, "屏幕改变,当前为竖屏");
        else
            Log.i(TAG, "屏幕改变,当前为横屏");
    }

    @Override
    protected void onRestart() {
        super.onRestart();
        Log.i(TAG, "onRestart");
    }

    @Override
    protected void onStart() {
        super.onStart();
        Log.i(TAG, "onStart");
    }

    @Override
    protected void onStop() {
        super.onStop();
        Log.i(TAG, "onStop");
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        Log.i(TAG, "onDestroy");
    }

    @Override
    protected void onPause() {
        super.onPause();
        Log.i(TAG, "onPause");
    }

    @Override
    protected void onResume() {
        super.onResume();
        Log.i(TAG, "onResume");
    }

    @Override
    protected void onSaveInstanceState(@NonNull Bundle outState) {
        super.onSaveInstanceState(outState);
        Log.i(TAG, "onSaveInstanceState");
    }

    @Override
    protected void onRestoreInstanceState(@NonNull Bundle savedInstanceState) {
        super.onRestoreInstanceState(savedInstanceState);
        Log.i(TAG, "onRestoreInstanceState");
    }
}

onSaveInstanceState() 和 onRestoreInstanceState() 方法

现在我们再回过头来看这两个方法。

1. 基本作用:

  首先要声明的是:Activity的 onSaveInstanceState() 和 onRestoreInstanceState() 并不是生命周期方法,它们不同于 onCreate()、onPause()等生命周期方法,并不一定会被触发。当应用遇到意外情况(如:内存不足、按Home键等)由系统销毁一个Activity时,onSaveInstanceState() 会被调用。但当用户主动去销毁一个Activity时,例如在应用中按返回键,onSaveInstanceState() 就不会被调用。此时,用户的行为决定了不需要保存Activity的状态。通常onSaveInstanceState() 只适合用于保存一些临时性的状态,而onPause()适合用于数据的持久化保存。

  比如说,当我们想在切换横竖屏的时候保存视频的播放进度。这时我们就可以在 Activity 中重写 onSaveInstanceState(Bundle outState) 方法。然后调用 outState.putXXX() 来保存数据。然后在 Activity 重新被创建时在 onCreate(Bundle savedInstanceState) 或 onRestoreInstanceState(Bundle savedInstanceState) 中 调用 savedInstanceState.getXXX() 来获取数据。 

  这就是 onSaveInstanceState() 和 onRestoreInstanceState() 两个函数的基本作用和用法了。

2. onSaveInstanceState() 什么时候调用

  先看Application Fundamentals上的一段话:

  Android calls onSaveInstanceState() before the activity becomes vulnerable to being destroyed by the system, but does not bother calling it when the instance is actually being destroyed by a user action (such as pressing the BACK key).

  当activity变得容易被系统销毁前,会回调 onSaveInstanceState() 方法,除非该 activity 是被用户主动销毁的(比如按下BACK键)。

  何为"容易"? 有这么几种情况:

  (1)、当用户按下HOME键时。

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

  (2)、长按HOME键,选择运行其他的程序时。

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

  (4)、从 activity A 中启动一个新的 activity 时。

  (5)、屏幕方向切换时,例如从竖屏切换到横屏时。

  在屏幕切换之前,系统会销毁 activity A,在屏幕切换之后系统又会自动地创建 activity A,所以onSaveInstanceState()一定会被执行,且也一定会执行onRestoreInstanceState()。

  总而言之,onSaveInstanceState()的调用遵循一个重要原则,即当系统存在 “未经你许可” 销毁了我们的 activity 的可能时,则 onSaveInstanceState() 会被系统调用,这是系统的责任,因为它必须要提供一个机会让你保存你的数据。且调用将发生在 onPause() 之前。

3. onRestoreInstanceState()什么时候调用

  onRestoreInstanceState() 被调用的前提是,activity A “确实” 被系统销毁了,且 activity A 被重新创建。当 activity A 未被重新创建时,该方法不会被调用。例如,当正在显示 activity A 的时候,用户按下 HOME 键回到主界面,然后用户紧接着又返回到 activity A,这种情况下 activity A 一般不会因为内存的原因被系统销毁,故 onRestoreInstanceState() 方法不会被执行, 这也证明这两个方法不一定会成对被使用。

  onRestoreInstanceState() 在 onStart() 和 onResume() 之间调用。

4. onSaveInstanceState()方法的默认实现

  如果我们没有覆写 onSaveInstanceState() 方法, 此方法的默认实现会自动保存 activity 中的某些状态数据, 比如 activity 中各种 UI 控件的状态.。android 应用框架中定义的几乎所有 UI 控件都恰当的实现了 onSaveInstanceState() 方法,因此当 activity 被摧毁和重建时, 这些 UI 控件会自动保存和恢复状态数据. 比如 EditText 控件会自动保存和恢复输入的数据,而 CheckBox 控件会自动保存和恢复选中状态.开发者只需要为这些控件指定一个唯一的 ID (通过设置 android:id 属性即可), 剩余的事情就可以自动完成了.如果没有为控件指定 ID, 则这个控件就不会进行自动的数据保存和恢复操作。

  由上所述, 如果我们需要覆写onSaveInstanceState()方法, 一般会在第一行代码中调用该方法的默认实现:super.onSaveInstanceState(outState)。

5. 是否需要重写onSaveInstanceState()方法

  既然该方法的默认实现可以自动的保存UI控件的状态数据, 那什么时候需要覆写该方法呢?

  如果需要保存额外的数据时, 就需要覆写onSaveInstanceState()方法。大家需要注意的是:onSaveInstanceState()方法只适合保存瞬态数据, 比如UI控件的状态, 成员变量的值等,而不应该用来保存持久化数据,如果当用户离开当前 activity 时需要保存数据,应该在 onPause() 中保存(比如将数据保存到数据库或文件中)。且 onPause() 中不适合做耗时的操作。

  由于onSaveInstanceState()方法方法不一定会被调用, 因此不适合在该方法中保存持久化数据, 例如向数据库中插入记录等. 保存持久化数据的操作应该放在onPause()中。若是永久性值,则在onPause()中保存;若大量,则另开线程吧,别阻塞UI线程。

6. 引发activity销毁和重建的其它情况

  除了系统处于内存不足的原因会摧毁 activity 之外, 某些系统设置的改变也会导致 activity 的摧毁和重建. 例如改变屏幕方向(见上), 改变语言设定, 键盘弹出等。


android:configChanges 属性

VALUE                   DESCRIPTION  

"mcc"                   国际移动用户识别码所属国家代号是改变了
"mnc"                   国际移动用户识别码的移动网号码是改变了
"locale"                地址改变了-----用户选择了一个新的语言会显示出来
"touchscreen"           触摸屏是改变了------通常是不会发生的
"keyboard"              键盘发生了改变----例如用户用了外部的键盘
"keyboardHidden"        键盘的可用性发生了改变
"navigation"            导航发生了变化-----通常也不会发生
"screenLayout"          屏幕的显示发生了变化------不同的显示被激活
"fontScale"             字体比例发生了变化----选择了不同的全局字体 
"uiMode"                用户的模式发生了变化
"orientation"           屏幕方向改变了
"screenSize"            屏幕大小改变了
"smallestScreenSize"    屏幕的物理大小改变了,如:连接到一个外部的屏幕上

  以上是 android:configChanges 属性的所有值。当我们希望一种或者多种配置改变时避免重新启动 activity。就可以通过在 AndroidManifest 中设置 android:configChanges 属性来实现。如下所示:

<activity
    android:name=".XXXActivity"
    android:configChanges="XXX|XXX"/>

  我们可以在这里声明 activity 可以处理的任何配置改变,当这些配置改变时不会重新启动activity,而会调用 onConfigurationChanged() 方法。如果改变的配置中包含了你所无法处理的配置(在android:configChanges并未声明),你的 activity 仍然要被重新启动。

  当 Configuration 改变后,ActivityManagerService 将会发送"配置改变"的广播,会要求 ActivityThread 重新启动当前 focus 的 Activity。但当我们为 activity 配置了 configChanges 属性,那么 activity 就不会被销毁再重新创建,而是会回调 onConfigurationChanged 方法。

================== End

原文地址:https://www.cnblogs.com/lsgxeva/p/13414171.html