Activity横竖屏切换的那些事

作者: AxeChen | 来源:发表于2016-09-29 01:16 被阅读1686次

    Activity的生命周期,这是每个Android开发者必须了解的知识。Activity是四大组件之一,而且是使用最频繁的组件。横竖屏切换是每个Android开发者都会遇到的问题。那么横竖屏切换后Activity到底发生了什么呢?

    1、生命周期的变化###

    建一个Activity,重写所有的生命周期方法,然后在这些方法中添加Log。

    public class ActivityA extends Activity {
    
       @Override
       protected void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
         setContentView(R.layout.test_layout);
         Log.i("axe.mg","onCreate()");
       }
    
       @Override
       protected void onRestart() {
         super.onRestart();
         Log.i("axe.mg","onRestart()");
       }
    
       @Override
       protected void onStart() {
         super.onStart();
         Log.i("axe.mg","onStart()");
       }
    
       @Override
       protected void onResume() {
         super.onResume();
         Log.i("axe.mg","onResume()");
       }
    
       @Override
       protected void onPause() {
         super.onPause();
         Log.i("axe.mg","onPause()");
       }
    
       @Override
       protected void onStop() {
         super.onStop();
         Log.i("axe.mg","onStop()");
       }
    
       @Override
       protected void onDestroy() {
         super.onDestroy();
         Log.i("axe.mg","onDestroy()");
       }
    }
    

    正常启动这个Activity。

    09-28 23:16:49.809 24348-24348/com.mg.axe.androiddevelop I/axe.mg: onCreate()
    09-28 23:16:49.809 24348-24348/com.mg.axe.androiddevelop I/axe.mg: onStart()
    09-28 23:16:49.819 24348-24348/com.mg.axe.androiddevelop I/axe.mg: onResume()
    

    通过Log可以看到Activity从创建到展示的的生命周期: onCreate() --->onStart() --->onResume()

    进行横竖屏切换。

    09-28 23:17:42.519 24348-24348/com.mg.axe.androiddevelop I/axe.mg: onPause()
    09-28 23:17:42.519 24348-24348/com.mg.axe.androiddevelop I/axe.mg: onStop()
    09-28 23:17:42.519 24348-24348/com.mg.axe.androiddevelop I/axe.mg: onDestroy()
    
    09-28 23:17:42.719 24348-24348/com.mg.axe.androiddevelop I/axe.mg: onCreate()
    09-28 23:17:42.729 24348-24348/com.mg.axe.androiddevelop I/axe.mg: onStart()
    09-28 23:17:42.729 24348-24348/com.mg.axe.androiddevelop I/axe.mg: onResume()
    

    通过Log将生命周期分为两部分来分析:
    1、Activity销毁: onPause() ---> onStop() ---> onDestroy()
    2、Activity的重新创建展示 :onCreate() ---> onStart() --->onResume()

    结论:当Activity横竖屏切换时.Activity就会重新创建。
    横竖屏切换时Activity会被销毁 , onPause() onStop() onDestory() 会被调用。
    然后Activity又会被重新创建,onCreate() onStart() onResume() 会被调用。

    --

    2、横竖屏切换后的数据恢复###

    已经知道Activity横竖屏切换时Activity会重新创建。那么如何恢复重建前的数据呢?
    Activity中有两个方法用来保存和恢复Activity重建前的数据:

      @Override
      protected void onSaveInstanceState(Bundle outState) {
         super.onSaveInstanceState(outState);
      }
    
      @Override
      protected void onRestoreInstanceState(Bundle savedInstanceState) {
         super.onRestoreInstanceState(savedInstanceState);
      }
    

    onSaveInstanceState:横竖屏切换时,Activity销毁前系统会调用onSaveInstanceState通过保存Bundle参数来保存当前的Activity的数据。这个方法会在onStop前调用。

    onRestoreInstanceState:当Activity被重新创建之后会调用onRestoreInstanceState,并把Activity销毁时 onSaveInstanceState方法所保留的数据作为Bundle参数同时传递给onRestoreInstanceState和onCreate方法。所以我们可以在onRestoreInstanceState和onCreate方法中看到两个一样的参数Bundle savedInstanceState。这个方法会在onStart后调用。

    强调一点:必须是Activity异常情况下被终止(例如:横竖屏切换)才会调用这两个方法。

    通过代码验证:在Activity中重写onSaveInstanceState和onRestoreInstanceState来保存和恢复Activity重建前的数据。

    在onSaveInstanceState保存一个“value_string”的string
    在onRestoreInstanceState获取“value_string”这个值。

    public class ActivityA extends Activity {
    
       @Override
       protected void onSaveInstanceState(Bundle outState) {
         super.onSaveInstanceState(outState);
         outState.putString("key","value_string");
         Log.i("axe.mg","onSaveInstanceState");
       }
    
       @Override
       protected void onRestoreInstanceState(Bundle savedInstanceState) {
         super.onRestoreInstanceState(savedInstanceState);
         String str =   savedInstanceState.getString("key");
         Log.i("axe.mg","onRestoreInstanceState");Log.i("axe.mg","get value:"+str);
       }
    
       @Override
       protected void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
         setContentView(R.layout.test_layout);
         Log.i("axe.mg","onCreate()");
       }
    
       @Override
       protected void onRestart() {
         super.onRestart();
         Log.i("axe.mg","onRestart");
       }
    
       @Override
       protected void onStart() {
         super.onStart();
         Log.i("axe.mg","onStart()");
       }
    
       @Override
       protected void onResume() {
         super.onResume();
         Log.i("axe.mg","onResume()");
       }
    
       @Override
       protected void onPause() {
         super.onPause();
         Log.i("axe.mg","onPause()");
       }
    
       @Override
       protected void onStop() {
         super.onStop();
         Log.i("axe.mg","onStop()");
       }
    
       @Override
       protected void onDestroy() {
         super.onDestroy();
         Log.i("axe.mg","onDestroy()");
       }
    

    横竖屏后获取到的Log。

    09-29 00:26:25.439 27568-27568/com.mg.axe.androiddevelop I/axe.mg: onPause()
    09-29 00:26:25.439 27568-27568/com.mg.axe.androiddevelop I/axe.mg: onSaveInstanceState
    09-29 00:26:25.439 27568-27568/com.mg.axe.androiddevelop I/axe.mg: onStop()
    09-29 00:26:25.439 27568-27568/com.mg.axe.androiddevelop I/axe.mg: onDestroy()
    
    09-29 00:26:25.499 27568-27568/com.mg.axe.androiddevelop I/axe.mg: onCreate()
    09-29 00:26:25.499 27568-27568/com.mg.axe.androiddevelop I/axe.mg: onStart()
    09-29 00:26:25.499 27568-27568/com.mg.axe.androiddevelop I/axe.mg: onRestoreInstanceState
    09-29 00:26:25.499 27568-27568/com.mg.axe.androiddevelop I/axe.mg: get value:value_string
    09-29 00:26:25.499 27568-27568/com.mg.axe.androiddevelop I/axe.mg: onResume()
    

    通过Log来分析:
    1、Activity销毁,调用onSaveInstanceState,在onSaveInstanceState方法里面
    通过outState.putString("key","value_string");保存了“value_string”这个值。

    2、Activity重建,调用onRestoreInstanceState,在onSaveInstanceState方法里面
    通过savedInstanceState.getString("key");获取出了“value_string”这个值。

    3、如何防止横竖屏切换时Activity重建###

    可能在开发中并不希望横竖屏切换后Activity重建。此时需要配置configChange参数,
    可以设置: android:configChanges="orientation|screenSize"

    <activity
       android:name=".develop.ActivityA"
       android:label="@string/app_name"
       android:configChanges="orientation|screenSize"
       android:theme="@style/AppTheme.NoActionBar">
         <intent-filter>
           <action android:name="android.intent.action.MAIN" />
           <category android:name="android.intent.category.LAUNCHER" />
       </intent-filter>
    </activity>
    

    配置添加android:configChanges="orientation|screenSize"
    (跟踪framework层代码,是由于google在android3.2中添加了screensize改变的通知,在转屏的时候,不仅是orientation发生了改变,screensize同样也发生了改变所以要添加“screenSize”)
    这种情况下横竖屏切换后不再重建Activity。同时会调用如下方法:

    @Override
    public void onConfigurationChanged(Configuration newConfig) {
     super.onConfigurationChanged(newConfig);
    }
    

    通过代码验证:
    Activity添加android:configChanges="orientation|screenSize"

    <activity
       android:name=".develop.ActivityA"
       android:configChanges="orientation|screenSize"
       android:label="@string/app_name"
       android:theme="@style/AppTheme.NoActionBar">
         <intent-filter>
           <action android:name="android.intent.action.MAIN" />
           <category android:name="android.intent.category.LAUNCHER" />
       </intent-filter>
    </activity>
    
    public class ActivityA extends Activity {
    
      @Override
      public void onConfigurationChanged(Configuration newConfig) {
         super.onConfigurationChanged(newConfig);
         Log.i("axe.mg","onConfigurationChanged");
      }
    
       @Override
       protected void onSaveInstanceState(Bundle outState) {
         super.onSaveInstanceState(outState);
         outState.putString("key","value_string");
         Log.i("axe.mg","onSaveInstanceState");
       }
    
       @Override
       protected void onRestoreInstanceState(Bundle savedInstanceState) {
         super.onRestoreInstanceState(savedInstanceState);
         String str =   savedInstanceState.getString("key");
         Log.i("axe.mg","onRestoreInstanceState");Log.i("axe.mg","get value:"+str);
       }
    
       @Override
       protected void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
         setContentView(R.layout.test_layout);
         Log.i("axe.mg","onCreate()");
       }
    
       @Override
       protected void onRestart() {
         super.onRestart();
         Log.i("axe.mg","onRestart");
       }
    
       @Override
       protected void onStart() {
         super.onStart();
         Log.i("axe.mg","onStart()");
       }
    
       @Override
       protected void onResume() {
         super.onResume();
         Log.i("axe.mg","onResume()");
       }
    
       @Override
       protected void onPause() {
         super.onPause();
         Log.i("axe.mg","onPause()");
       }
    
       @Override
       protected void onStop() {
         super.onStop();
         Log.i("axe.mg","onStop()");
       }
    
       @Override
       protected void onDestroy() {
         super.onDestroy();
         Log.i("axe.mg","onDestroy()");
       }
    

    横竖平切换后:

    09-29 00:54:00.849 21338-21338/com.mg.axe.androiddevelop I/axe.mg: onConfigurationChanged
    

    通过Log分析:
    此时Activity不再重建, 不会调用生命周期的方法,也不会调用onSaveInstanceState和onRestoreInstanceState。会调用onConfigurationChanged方法。

    +++++++++附件信息:configChanges属性的值+++++++++++

    通过设置这个属性可以使Activity捕捉设备状态变化,以下是可以被识别的内容:
    设置方法:将下列字段用“|”符号分隔开,例如:“locale|navigation|orientation

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

    参考链接:
    http://www.cnblogs.com/-cyb/articles/Android_onConfigurationChanged.html (要添加screenSize的问题)
    http://www.cnblogs.com/carlo/p/4311010.html (附件信息:configChanges属性的值)

    参考书籍:Android开发艺术探索。

    相关文章

      网友评论

        本文标题:Activity横竖屏切换的那些事

        本文链接:https://www.haomeiwen.com/subject/ljyhyttx.html