Activity横竖屏切换的那些事

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开发艺术探索。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,732评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,496评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,264评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,807评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,806评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,675评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,029评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,683评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 41,704评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,666评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,773评论 1 332
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,413评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,016评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,978评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,204评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,083评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,503评论 2 343

推荐阅读更多精彩内容

  • Android开发中,大多APP可能根据实际情况直接将APP的界面方向设死了,或竖屏或横屏。但是,我们还是会遇到横...
    yoosir阅读 49,552评论 7 112
  • 在前面几期学习了Activity的创建、配置、启动和停止,还学了Activity的生命周期,本期一起来学习Acti...
    今生心理金馀阅读 761评论 0 0
  • Android手机或平板都会存在横竖屏切换的功能,通常是由物理重力感应触发的,但是有时候也不尽然,通常在设置里面我...
    Lost_Robot阅读 6,661评论 1 5
  • apk在下载、安装、更新前,都会显示安装包的大小,虽然现在移动流量日趋优惠,但是过大的安装包还是会降低下载量,ap...
    工木南ng阅读 560评论 0 49
  • 目击证人 作者:荒古百川流 一 从夜市回来,天还未黑,在经过公司大门拐弯的路口,一同事从后跟上来。本想回头给他打声...
    彭北阅读 405评论 1 0