Android-Activity横竖屏切换时的生命周期

Android-Activity横竖屏切换时的生命周期

相信大家对活动的生命周期十分了解了,它的7个生命周期方法onCreate(),onStart(),onResume(),等在什么时候调用都很熟悉。那么,当一个活动运行时锁屏,返回主界面,旋转屏幕时方法会怎么调用,数据是如何保存的,我分享一下我所学的。

新的方法

onSaveInstanceState():当activity变得容易被系统回收时调用
onRestoreInstanceState():被系统回收的activity重新创建时调用
onConfigurationChanged():当系统的配置信息发生改变时,系统会调用此方法

  • onSaveInstanceState

onSaveInstanceState()在onStop()方法后执行
(注:根据官方文档,在Android API26以下,onSaveInstanceState()优先于onStop()方法执行,API26以后会先执行onStop()再执行onSaveInstanceState())

首先给大家带来三个新方法的学习,onSaveInstanState()我们已经有过接触,在《第一行代码》P63,2.4.5 活动被回收了怎么办 这一节中提到,为了避免活动被回收时数据无法及时保存的问题,我们可以使用onSaveInstanceState(Bundle outState)方法的outState参数保存临时数据,并在onCreate()方法中取出

@Override
    protected void onSaveInstanceState(@NonNull Bundle outState) {
        super.onSaveInstanceState(outState);
        String tempData = "Something you just typed";
        outState.putString("data_key", tempData);
    }

@Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        if(savedInstanceState != null){
        //注意要做非空判断
        	String tempData = savedInstanceState.getString("data_ley);
        	Log.d(TAG, tempData);
        }
	}

另外,onSaveInstanceState()方法要注意的是,它只有在activity变得容易被系统销毁前会调用,而用户主动销毁,如按返回键退出程序是不会调用的。
什么是“容易”,有一下几种情况:

  1. 按HOME键返回主屏幕
  2. 按菜单键切换程序
  3. 锁屏时
  4. 启动新活动时
  5. 屏幕方向切换
    总而言之,onSaveInstanceState()的调用遵循一个原则,当系统存在未经你许可销毁活动的可能时,则onSaveInstanceState()会被系统调用。
  • onRestoreInstanceState()

onRestoreInstanceState()在onStart()方法后执行

onRestoreInstanceState()onSaveInstanceState()相辅相成,与从名字来看,这个方法就是用来回复数据的。这个方法会在activity确实被系统回收,并且要重新创建activity时调用。
与在onCreate()方法我们手动回复数据不同的是,onRestoreInstanceState()会在重新创建已经被系统回收的activity时自动调用,并且我们也不需要在进行非空判断,因为调用了此方法就一定会有Bundl对象。

  • onConfigurationChanged()

因为活动的创建十分耗费资源,而横竖屏切换系统又必定销毁再重新创建,有什么方法可以跳过这些步骤呢?我们可以使用onConfigurationChanged()方法。
首先我们需要再Manifest文件中为activity加上configChanges属性

<activity android:name=".ActivityTwo"
          android:configChanges="orientation|keyboardHidden|screenSize">

</activity>

configChanges属性所声明的内容就意味着activity可以处理的配置改变,即当这些内容发生变化时,activity不会重新启动,而是调用onConfigurationChanged()方法

调用顺序

代码

public class MainActivity extends AppCompatActivity {
    private static final String TAG = "MainActivity";
    String s = "Activity1";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        Log.d(TAG, "onCreate: " + s);

        Button startActivity = findViewById(R.id.start_activity);
        startActivity.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent intent = new Intent(MainActivity.this, ActivityTwo.class);
                startActivity(intent);
            }
        });

        Button alert1 = findViewById(R.id.alert1);
        alert1.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent intent = new Intent(MainActivity.this, ActivityThree.class);
                startActivity(intent);
            }
        });

        Button startService = findViewById(R.id.start_service);
        startService.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent intent = new Intent(MainActivity.this, MyService.class);
                startService(intent);
            }
        });

        Button stopService = findViewById(R.id.stop_service);
        stopService.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent intent = new Intent(MainActivity.this, MyService.class);
                stopService(intent);
            }
        });
    }

    @Override
    protected void onStart() {
        super.onStart();
        Log.d(TAG, "onStart: " + s);
    }

    @Override
    protected void onResume() {
        super.onResume();
        Log.d(TAG, "onResume: " + s);
    }

    @Override
    protected void onPause() {
        super.onPause();
        Log.d(TAG, "onPause: " + s);
    }

    @Override
    protected void onStop() {
        super.onStop();
        Log.d(TAG, "onStop: " + s);
    }

    @Override
    protected void onRestart() {
        super.onRestart();
        Log.d(TAG, "onRestart: " + s);
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        Log.d(TAG, "onDestroy: " + s);
    }

    @Override
    protected void onSaveInstanceState(@NonNull Bundle outState) {
        super.onSaveInstanceState(outState);
        Log.d(TAG, "onSaveInstanceState: " + s);
    }

    @Override
    protected void onRestoreInstanceState(@NonNull Bundle savedInstanceState) {
        super.onRestoreInstanceState(savedInstanceState);
        Log.d(TAG, "onRestoreInstanceState: " + s);
    }

    @Override
    public void onConfigurationChanged(@NonNull Configuration newConfig) {
        super.onConfigurationChanged(newConfig);
        Log.d(TAG, "onConfigurationChanged: " + s);
    }
}
  • 锁屏

D/MainActivity: onPause: Activity1
D/MainActivity: onStop: Activity1
D/MainActivity: onSaveInstanceState: Activity1

  • 按下HOME键

D/MainActivity: onPause: Activity1
D/MainActivity: onStop: Activity1
D/MainActivity: onSaveInstanceState: Activity1

  • 按下菜单键

D/MainActivity: onPause: Activity1
D/MainActivity: onStop: Activity1
D/MainActivity: onSaveInstanceState: Activity1

这三种情况可以看到,活动进行到onStop()再调用onSaveInstanceState()保存数据就结束了

-屏幕旋转时

D/MainActivity: onPause: Activity1
D/MainActivity: onStop: Activity1
D/MainActivity: onSaveInstanceState: Activity1
D/MainActivity:onDestroy: Activity1
D/MainActivity: onCreate: Activity1
D/MainActivity: onStart: Activity1
D/MainActivity: onRestoreInstanceState: Activity1
D/MainActivity: onResume: Activity1

这里我们终于见到了onRestoreInstanceState()方法,因为此时旧活动确实被系统回收了,系统又帮我们重新创建了活动

  • 带configChanges属性的活动的横竖屏切换

D/ActivityTwo: onConfigurationChanged: Activity2

可以看到,当我们设置好了configChanges属性后,切换屏幕只会执行onConfigurationChanged()方法

  • 应用分屏

没有configChanges属性
D/MainActivity: onPause: Activity1
D/MainActivity: onStop: Activity1
D/MainActivity: onSaveInstanceState: Activity1
D/MainActivity: onDestroy: Activity1
D/MainActivity: onCreate: Activity1
D/MainActivity: onStart: Activity1
D/MainActivity: onRestoreInstanceState: Activity1
D/MainActivity: onResume: Activity1
D/MainActivity: onPause: Activity1

有configChanges属性
D/ActivityTwo: onConfigurationChanged: Activity2
D/ActivityTwo: onPause: Activity2

总结:应用分屏总是会执行onPause()方法,不同的是,没有configChanges属性会先销毁再新建,有configChanges属性先执行onConfigurationChanged()方法再执行onPause()方法。

  • 启动新活动及退出

启动新活动
D/MainActivity: onPause: Activity1
D/ActivityTwo: onCreate: Activity2
D/ActivityTwo: onStart: Activity2
D/ActivityTwo: onResume: Activity2
D/MainActivity: onStop: Activity1
D/MainActivity: onSaveInstanceState: Activity1

退出活动
D/ActivityTwo: onPause: Activity2
D/MainActivity: onRestart: Activity1
D/MainActivity: onStart: Activity1
D/MainActivity: onResume: Activity1
D/ActivityTwo: onStop: Activity2
D/ActivityTwo: onDestroy: Activity2

这个有了很大的变化,在启动新活动时,先执行活动1的onPause()方法,然后开始创建活动2,当活动2准备好后,也就是onResume()状态才会接着执行活动1的onStop(),onSaveInstanceState()方法。退出时也一样,先执行活动2的onPause()方法再回复活动1,当活动1完全恢复时才调用活动2的onStop(),onDestroy()方法。

数据保存

一般来说,我们可以在生命周期的onPause(),或者在onSaveInstanceState()方法中保存数据,他们有什么区别,我要怎么使用呢?

  • 为什么要在onPause()中保存数据,而不是在onStop()中?

以上面启动新活动为例,我们可以看到,在启动新活动时,我们先执行了活动1的onPause()方法才创建活动2,因此我们能保证onPause()一定被执行,onStop()方法并不保证一定能执行。同时,因为onPause()方法结束才会创建下一个活动,我们不能在onPause()有耗时操作,否则会影响下一个活动入栈。

  • 他们分别可以保存什么数据

onSaveInstanceState()用来保存一些临时数据,同时,他的默认实现会自动保存活动的某些数据,比如EditText会自动保存和恢复输入的数据。
onPause()方法可以进行一些数据持久化操作,将数据保存在数据库中。但是,因为数据库操作是耗时操作,数据量过多会ANR异常,我们只能保存少量数据,对于大量数据,我们就需要开启新线程来保存了

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值