• 【Android】Activity生命周期(亲测)


    测试手机:Nexus 5   系统:4.4

    一、测试

    测试代码:

     1 package com.example.androidalarm;
     2 
     3 import android.app.Activity;
     4 import android.content.Context;
     5 import android.content.res.Configuration;
     6 import android.os.Bundle;
     7 import android.util.AttributeSet;
     8 import android.util.Log;
     9 import android.view.View;
    10 import android.widget.Button;
    11 
    12 public class MainActivity extends Activity {
    13     Button addButton, cancelButton;
    14     
    15     @Override
    16     protected void onCreate(Bundle savedInstanceState) {
    17         super.onCreate(savedInstanceState);
    18         setContentView(R.layout.activity_main);
    19         Log.d("BigFootprint", "onCreate");
    20     }
    21 
    22     @Override
    23     public void onConfigurationChanged(Configuration newConfig) {
    24         Log.d("BigFootprint", "onConfigurationChanged");
    25         super.onConfigurationChanged(newConfig);
    26     }
    27 
    28     @Override
    29     public View onCreateView(String name, Context context, AttributeSet attrs) {
    30         Log.d("BigFootprint", "onCreateView");
    31         return super.onCreateView(name, context, attrs);
    32     }
    33 
    34     @Override
    35     protected void onDestroy() {
    36         Log.d("BigFootprint", "onDestroy");
    37         super.onDestroy();
    38     }
    39 
    40     @Override
    41     protected void onPause() {
    42         Log.d("BigFootprint", "onPause");
    43         super.onPause();
    44     }
    45 
    46     @Override
    47     protected void onRestart() {
    48         Log.d("BigFootprint", "onRestart");
    49         super.onRestart();
    50     }
    51 
    52     @Override
    53     protected void onRestoreInstanceState(Bundle savedInstanceState) {
    54         Log.d("BigFootprint", "onRestoreInstanceState");
    55         super.onRestoreInstanceState(savedInstanceState);
    56     }
    57 
    58     @Override
    59     protected void onResume() {
    60         Log.d("BigFootprint", "onResume");
    61         super.onResume();
    62     }
    63 
    64     @Override
    65     protected void onSaveInstanceState(Bundle outState) {
    66         Log.d("BigFootprint", "onSaveInstanceState");
    67         super.onSaveInstanceState(outState);
    68     }
    69 
    70     @Override
    71     protected void onStart() {
    72         Log.d("BigFootprint", "onStart");
    73         super.onStart();
    74     }
    75 
    76     @Override
    77     protected void onStop() {
    78         Log.d("BigFootprint", "onStop");
    79         super.onStop();
    80     }
    81 }
    View Code

    XML配置:

     1 <?xml version="1.0" encoding="utf-8"?>
     2 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
     3     package="com.example.androidalarm"
     4     android:versionCode="1"
     5     android:versionName="1.0" >
     6 
     7     <uses-sdk
     8         android:minSdkVersion="8"
     9         android:targetSdkVersion="18" />
    10 
    11     <application
    12         android:allowBackup="true"
    13         android:icon="@drawable/ic_launcher"
    14         android:label="@string/app_name"
    15         android:theme="@style/AppTheme" >
    16         <activity
    17             android:name="com.example.androidalarm.MainActivity"
    18             android:label="@string/app_name" >
    19             <intent-filter>
    20                 <action android:name="android.intent.action.MAIN" />
    21                 <category android:name="android.intent.category.LAUNCHER" />
    22             </intent-filter>
    23         </activity>
    24     </application>
    25 </manifest>
    View Code

    以以上的代码运行,打开应用,LOG输出如下“

    可以看到,打开Activity的时候,生命周期是符合文档描述的,但是onCreateView接口会被多次调用,所以最好不要在这边实例化数据。按下BACK键退出,LOG如下:

    生命周期非常正常。当Activity显示的时候,屏幕暗掉,LOG如下:

    红框中为多打印的3个生命周期过程,可以看到onSaveInstanceState的调用时机!亮起屏幕,LOG如下:

    生命周期一如文档所说。如果按下Home键退出,则LOG如下:

    可以看到,和屏幕暗掉的LOG完全一样。重新点击应用图标打开Activity,得到如下LOG:

    这个时候并没有去OnCreate,而是调用了方法onRestart方法。

    这时候切换屏幕(竖屏切为横屏):(备注:因为onCreateView调用次数太多,而且不是重点研究对象,后面去掉此处LOG)

    可以看到切换的时候,生命周期又走了一遍,并且调用了onSaveInstanceState和onRestoreInstanceState方法用于保存和恢复状态。然后从横屏恢复为竖屏,LOG如下:

    调用的生命周期过程完全和上面的切换完全一样。

    接下来要试验的是,重新在XML文件中配置Activity。

     1 <?xml version="1.0" encoding="utf-8"?>
     2 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
     3     package="com.example.androidalarm"
     4     android:versionCode="1"
     5     android:versionName="1.0" >
     6 
     7     <uses-sdk
     8         android:minSdkVersion="8"
     9         android:targetSdkVersion="18" />
    10 
    11     <uses-permission android:name="android.permission.CHANGE_CONFIGURATION"></uses-permission>
    12     
    13     <application
    14         android:allowBackup="true"
    15         android:icon="@drawable/ic_launcher"
    16         android:label="@string/app_name"
    17         android:theme="@style/AppTheme" >
    18         <activity
    19             android:name="com.example.androidalarm.MainActivity"
    20             android:configChanges="orientation"
    21             android:label="@string/app_name" >
    22             <intent-filter>
    23                 <action android:name="android.intent.action.MAIN" />
    24                 <category android:name="android.intent.category.LAUNCHER" />
    25             </intent-filter>
    26         </activity>
    27     </application>
    28 </manifest>
    View Code

    多加了一个配置: android:configChanges="orientation"。并且需要添加permission。

    这是竖屏——>横屏——>竖屏切换过程中打印的LOG,可以看到,和没有配置的时候完全一样。再配置如下:添加: android:configChanges="orientation|keyboardHidden"

     1 <?xml version="1.0" encoding="utf-8"?>
     2 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
     3     package="com.example.androidalarm"
     4     android:versionCode="1"
     5     android:versionName="1.0" >
     6 
     7     <uses-sdk
     8         android:minSdkVersion="8"
     9         android:targetSdkVersion="18" />
    10 
    11     <uses-permission android:name="android.permission.CHANGE_CONFIGURATION"></uses-permission>
    12     
    13     <application
    14         android:allowBackup="true"
    15         android:icon="@drawable/ic_launcher"
    16         android:label="@string/app_name"
    17         android:theme="@style/AppTheme" >
    18         <activity
    19             android:name="com.example.androidalarm.MainActivity"
    20             android:configChanges="orientation|keyboardHidden"
    21             android:label="@string/app_name" >
    22             <intent-filter>
    23                 <action android:name="android.intent.action.MAIN" />
    24                 <category android:name="android.intent.category.LAUNCHER" />
    25             </intent-filter>
    26         </activity>
    27     </application>
    28 </manifest>
    View Code

    打印的LOG还是一样,接下来再配置:改成android:configChanges="orientation|screenSize", 切换横竖屏打印的LOG如下:

    注意,这里也是竖屏——>横屏——>竖屏切换,每次切换只打印一行LOG。

    二、结论

      在网上看到很多的资料讲述生命周期,结论应该只有一个:生命周期会因为系统版本甚至因为定制等各种因素而各有差异。所以本文一开始就给出了测试环境。上面的测试只在一种环境下完成,不能代表所有系统和所有机型。读者如需了解问题,还应该在当前环境下自己去进行测试。但是由此依然可以得出一些结论:

    1)onCreateView接口会被多次调用,在这个接口中的代码要好好考虑,实例化数据,加载资源的动作最好不要放在这个方法中;

    2)如果不是程序主动关闭Activity(比如按下回退键),onPause()之后会调用onSaveInstanceState方法保存状态,此后恢复Activity,如果在这之间调用了onDestory,即Activity被意外销毁,会在onStart()和onResume()之间调用onRestoreInstanceState方法恢复状态,否则,会以onRestart->onStart()->onResume()的顺序重新打开Activity;

    3)如果不配置Activity的configChanges或者配置没有起效果(注:如何起效果,视环境而定,最保险的方案目前是:android:configChanges="orientation|screenSize|keyboardHidden"),则在横竖屏切换的时候,会重新走一遍生命周期,否则,只会调用onConfigurationChanged方法;

    补充一下关于configChanges的参数值解释:

    Value Description
    “mcc“ The IMSI mobile country code (MCC) has changed — that is, a SIM hasbeen detected and updated the MCC.移动国家号码,由三位数字组成,每个国家都有自己独立的MCC,可以识别手机用户所属国家。
    “mnc“ The IMSI mobile network code (MNC) has changed — that is, a SIM hasbeen detected and updated the MNC.移动网号,在一个国家或者地区中,用于区分手机用户的服务商。
    “locale“ The locale has changed — for example, the user has selected a new language that text should be displayed in.用户所在地区发生变化。
    “touchscreen“ The touchscreen has changed. (This should never normally happen.)
    “keyboard“ The keyboard type has changed — for example, the user has plugged in an external keyboard.键盘模式发生变化,例如:用户接入外部键盘输入。
    “keyboardHidden“ The keyboard accessibility has changed — for example, the user has slid the keyboard out to expose it.用户打开手机硬件键盘
    “navigation“ The navigation type has changed. (This should never normally happen.)
    “orientation“ The screen orientation has changed — that is, the user has rotated the device.设备旋转,横向显示和竖向显示模式切换。
    “fontScale“ The font scaling factor has changed — that is, the user has selected a new global font size.全局字体大小缩放发生改变

    根据这份解释,个人感觉其实系统是有BUG的,理论上configChanges=orientation这样的配置在设备旋转后就应该会去调用onConfigurationChanged方法,但实际上连亲生儿子也不遵循。

    最后根据这次试验,总结一下Activity认为意外关闭的三种场景:

    1)屏幕暗下去;

    2)按下HOME键退出Activity;

    3)横竖屏切换;

    这三种情景都会导致Activity调用onSaveInstanceState去保存自己的状态以便于恢复。

  • 相关阅读:
    CSS3 Flex布局整理(二)-容器属性
    CSS3 Flex布局整理(一)
    .Net Core中文编码问题整理
    Karma:1. 集成 Karma 和 Jasmine 进行单元测试
    Protractor
    翻译: TypeScript 1.8 Beta 发布
    webpack 插件: html-webpack-plugin
    How I came to find Linux
    翻译:Angular 2
    在 Angular 中实现搜索关键字高亮
  • 原文地址:https://www.cnblogs.com/lqminn/p/3856089.html
Copyright © 2020-2023  润新知