研究这个问题的初衷在于项目中碰到了一个问题:横屏的时候灭屏再亮屏,亮屏的时候用户可以清晰的看到先启动竖屏(过程1)再切换到横屏的过程,由于灭屏的时候onSaveInstanceState()保存的时横屏时的状态信息,因此过程1竖屏会使用到横屏的状态参数而且这一过程用户是可见的,因此会导致一些意想不到的Bug的出现。
探究使用的实例中我用了屏幕的横竖屏和宽这两个配置信息来说明生命周期中此时系统所知道的屏幕的客观状态,注意这个客观状态与我们在onSaveInstanceState()中要保存的“状态信息”是不一样的,客观状态由硬件和系统决定,在那一时刻一定是这样的状态,“状态信息”是程序员想要保存的信息,这个由程序员自己控制。
横竖屏切换一般会由onConfigurationChanged()这个系统函数来响应,但响应这个函数需要在Manifest中为Activity配置如下信息(Android3.2及更高版本的配置方法)
<activity
...
android:configChanges="orientation|screenSize"
... >
本篇先探究没有进行这种配置时Activity的生命状态,从结果中可以看到此时的横竖屏切换时一个完全杀死Activity再重启Activity的过程,同时横屏的灭屏亮屏都先做了一次切换到竖屏的过程。
源码如下:
package com.vivo.configurationtest; import android.app.Activity; import android.content.res.Configuration; import android.os.Bundle; import android.util.Log; public class MainActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { Log.d("vi", "---onCreate()--" + "orientation = " + orientation() + "width = " + width()); super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); } @Override protected void onSaveInstanceState(Bundle outState) { // TODO Auto-generated method stub Log.d("vi", "---onSaveInstanceState()--" + "orientation = " + orientation() + "width = " + width()); super.onSaveInstanceState(outState); } @Override protected void onStart() { // TODO Auto-generated method stub Log.d("vi", "---onStart()--" + "orientation = " + orientation() + "width = " + width()); super.onStart(); } @Override protected void onResume() { // TODO Auto-generated method stub Log.d("vi", "---onResume()--" + "orientation = " + orientation() + "width = " + width()); super.onResume(); } @Override protected void onPause() { // TODO Auto-generated method stub Log.d("vi", "---onPause()--" + "orientation = " + orientation() + "width = " + width()); super.onPause(); } @Override public void onConfigurationChanged(Configuration newConfig) { // TODO Auto-generated method stub Log.d("vi", "---onConfigurationChanged()--" + "width = " + width()); super.onConfigurationChanged(newConfig); } @Override protected void onStop() { // TODO Auto-generated method stub Log.d("vi", "---onStop()--" + "orientation = " + orientation() + "width = " + width()); super.onStop(); } @Override protected void onRestart() { // TODO Auto-generated method stub Log.d("vi", "---onRestart()--" + "orientation = " + orientation() + "width = " + width()); super.onRestart(); } @Override protected void onDestroy() { // TODO Auto-generated method stub Log.d("vi", "---onDestroy()--" + "orientation = " + orientation() + "width = " + width()); super.onDestroy(); } private String orientation() { int ori = this.getResources().getConfiguration().orientation; if (ori == Configuration.ORIENTATION_PORTRAIT) { return "ORIENTATION_PORTRAIT--"; } else if (ori == Configuration.ORIENTATION_LANDSCAPE) { return "ORIENTATION_LANDSCAPE--"; } return "-------"; } private int width() { int screenWidth = getWindowManager().getDefaultDisplay().getWidth(); return screenWidth; } }
//以下为没有在manifest中配置configuration
//竖屏从创建到切换到横屏C:\Users\Administrator>adb logcat -s vi
--------- beginning of /dev/log/main
--------- beginning of /dev/log/system
D/vi (16610): ---onCreate()--orientation = ORIENTATION_PORTRAIT--width = 480
D/vi (16610): ---onStart()--orientation = ORIENTATION_PORTRAIT--width = 480
D/vi (16610): ---onResume()--orientation = ORIENTATION_PORTRAIT--width = 480
D/vi (16610): ---onPause()--orientation = ORIENTATION_LANDSCAPE--width = 854 //onPause()时已经获取到切换之后的屏幕的配置信息
D/vi (16610): ---onSaveInstanceState()--orientation = ORIENTATION_LANDSCAPE--width = 854
D/vi (16610): ---onStop()--orientation = ORIENTATION_LANDSCAPE--width = 854
D/vi (16610): ---onDestroy()--orientation = ORIENTATION_LANDSCAPE--width = 854 //屏幕切换是一个完全的杀死activity然后重启activity的过程
D/vi (16610): ---onCreate()--orientation = ORIENTATION_LANDSCAPE--width =854
D/vi (16610): ---onStart()--orientation = ORIENTATION_LANDSCAPE--width = 854
D/vi (16610): ---onResume()--orientation = ORIENTATION_LANDSCAPE--width =854
//从横屏切换到竖屏
C:\Users\Administrator>adb logcat -s vi
--------- beginning of /dev/log/main
--------- beginning of /dev/log/system
D/vi (16610): ---onPause()--orientation = ORIENTATION_PORTRAIT--width = 480
D/vi (16610): ---onSaveInstanceState()--orientation = ORIENTATION_PORTRAIT--width = 480
D/vi (16610): ---onStop()--orientation = ORIENTATION_PORTRAIT--width = 480
D/vi (16610): ---onDestroy()--orientation = ORIENTATION_PORTRAIT--width =480
D/vi (16610): ---onCreate()--orientation = ORIENTATION_PORTRAIT--width = 480
D/vi (16610): ---onStart()--orientation = ORIENTATION_PORTRAIT--width = 480
D/vi (16610): ---onResume()--orientation = ORIENTATION_PORTRAIT--width = 480
//竖屏从灭屏到亮屏
C:\Users\Administrator>adb logcat -s vi
--------- beginning of /dev/log/main
--------- beginning of /dev/log/system
D/vi (16610): ---onPause()--orientation = ORIENTATION_PORTRAIT--width = 480 //灭屏从onPause()处开始
D/vi (16610): ---onSaveInstanceState()--orientation = ORIENTATION_PORTRAIT--width = 480 //暂停并保存当前信息,要保存什么样的信息由用户选择
D/vi (16610): ---onStop()--orientation = ORIENTATION_PORTRAIT--width = 480
D/vi (16610): ---onRestart()--orientation = ORIENTATION_PORTRAIT--width =480 //亮屏从onRestart()处开始
D/vi (16610): ---onStart()--orientation = ORIENTATION_PORTRAIT--width = 480
D/vi (16610): ---onResume()--orientation = ORIENTATION_PORTRAIT--width = 480
//横屏的灭屏
C:\Users\Administrator>adb logcat -s vi
--------- beginning of /dev/log/main
--------- beginning of /dev/log/system
D/vi (16610): ---onPause()--orientation = ORIENTATION_PORTRAIT--width = 480
D/vi (16610): ---onSaveInstanceState()--orientation = ORIENTATION_PORTRAIT--width = 480
D/vi (16610): ---onStop()--orientation = ORIENTATION_PORTRAIT--width = 480
D/vi (16610): ---onDestroy()--orientation = ORIENTATION_PORTRAIT--width =480
D/vi (16610): ---onCreate()--orientation = ORIENTATION_PORTRAIT--width = 480
D/vi (16610): ---onStart()--orientation = ORIENTATION_PORTRAIT--width = 480
D/vi (16610): ---onResume()--orientation = ORIENTATION_PORTRAIT--width = 480 //横屏的灭屏相当于先切换到竖屏,再灭屏,这个过程用户没看到
D/vi (16610): ---onPause()--orientation = ORIENTATION_PORTRAIT--width = 480
D/vi (16610): ---onSaveInstanceState()--orientation = ORIENTATION_PORTRAIT--width = 480
D/vi (16610): ---onStop()--orientation = ORIENTATION_PORTRAIT--width = 480
//横屏的亮屏
C:\Users\Administrator>adb logcat -s vi
--------- beginning of /dev/log/main
--------- beginning of /dev/log/system
D/vi (16610): ---onRestart()--orientation = ORIENTATION_PORTRAIT--width =480
D/vi (16610): ---onStart()--orientation = ORIENTATION_PORTRAIT--width = 480
D/vi (16610): ---onResume()--orientation = ORIENTATION_PORTRAIT--width = 480 //横屏的亮屏相当于先亮到竖屏,再切换到横屏,这个过程用户是可以看到的,灭屏的时候系统也做了一次同样的切换到竖屏的动作,屏灭用户没看到而已
D/vi (16610): ---onPause()--orientation = ORIENTATION_LANDSCAPE--width = 854
D/vi (16610): ---onSaveInstanceState()--orientation = ORIENTATION_LANDSCAPE--width = 854
D/vi (16610): ---onStop()--orientation = ORIENTATION_LANDSCAPE--width = 854
D/vi (16610): ---onDestroy()--orientation = ORIENTATION_LANDSCAPE--width = 854
D/vi (16610): ---onCreate()--orientation = ORIENTATION_LANDSCAPE--width =854
D/vi (16610): ---onStart()--orientation = ORIENTATION_LANDSCAPE--width = 854
D/vi (16610): ---onResume()--orientation = ORIENTATION_LANDSCAPE--width =854