Android-Activity所应该了解的大概就这样。(上)

本文出自 “阿敏其人” 简书博客,转载或引用请注明出处。

一、前言

Activity,安卓四大组件之一。

每个 Activity 都会获得一个用于绘制其用户界面的窗口。窗口通常会充满屏幕,但也可小于屏幕并浮动在其他窗口之上。
一个应用通常由多个彼此松散联系的 Activity 组成。每次新 Activity 启动时,前一 Activity 便会停止,但系统会在堆栈(“返回栈”)中保留该 Activity。 当新 Activity 启动时,系统会将其推送到返回栈上,并取得用户焦点。 返回栈遵循“后进先出”堆栈机制,因此,当用户完成当前 Activity 并按“返回” **按钮时,系统会从堆栈中将其弹出(并销毁),然后恢复前一 Activity。

当一个 Activity 因某个新 Activity 启动而停止时,系统会通过该 Activity 的生命周期回调方法通知其这一状态变化。Activity 因状态变化—系统是创建 Activity、停止 Activity、恢复 Activity 还是销毁 Activity— 而收到的回调方法可能有若干种,每一种回调方法都会为您提供执行与该状态变化相应的特定操作的机会。

本文按
生命周期、
进程的5种优先级、
Activity的正常销毁和异常销毁、
Activity的启动模式/4种任务栈,
Activity的Flag的使用、
围绕展开。

二、Activity的生命周期

1、Activity生命周期概述

1.1、生命周期6+1方法

简单来说,6+1的组成的模式(6分为三对)

6个常见的生命周期方法:

  • onCreate() 当Activity创建时执行
  • onStart() 当Activity可见时执行(可见了,但是看不到,没获得焦点)
  • onResume() 当Activity获取焦点是执行
  • onPause() 当Activity失去焦点时执行
  • onStop() 当Activity不可见时执行
  • onDestroy() 当Activity销毁时执行
    (我的理解是获取焦点才算真正可见,因为获取了焦点用户才可以操作,所以可见但是看不到这句话不矛盾)

加1就是加上这个:

  • onRestart() 当Activity正在重新启动时执行。
    .
    .
    就上面的6个常见的生命周期:
    他们可以说是根据特征可以分成三组的:

onCreate() 对应 onDestroy() 创建和销毁
onStart() 对应 onStop() 可见和不可见
onResume() 对应 onPause() 获取焦点和失去焦点

1.2 生命周期流程图

官网翻译Activity生周期流程图.png

1.3 Activity的三种形态

Activity 基本上以三种状态存在:正继续,已暂停,已停止

正继续 (Active/Running)
  此 Activity 位于Activity的栈的最顶层,位于屏幕前台并具有用户焦点,可与用户进行交互。(有时也将此状态称作“运行中”。)
注:关于栈的知识请看本文的: Activity的启动模式/4种任务栈 这一部分
已暂停(Paused)
  Activity已经失去焦点,无法与用户进行交互。
   什么?我们的Activity是可见的?但是没办法和用户交互?弄啥咧?
  是这样子的,假设甲Activity是可见的可交互的,但是这时我们的乙Activity(一个新的非全屏的Activity或者一个透明的Activity)至于栈顶时,即在任务栈里我们的乙位甲的上方,此刻我们的甲Activity就会处于Paused状态了,也就是可见但是没能进行交互。
  
  处于Paused状态的甲对象保留在内存中,它保留了所有状态和成员信息,并与窗口管理器保持连接),但在内存极度不足的情况下,可能会被系统终止(进程优先级的关系)。

关于 任务栈 和 进程优先级 的知识后面我们也会谈及。

已停止(Stoppted)
  该 Activity 被另一个 Activity 完全遮盖(该 Activity 目前位于“后台”)。 已停止的 Activity 同样仍处于 Activity 状态(Activity对象保留在内存中,它保留了所有状态和成员信息,但 没有 与窗口管理器连接)。
  它对用户不再可见,在他处需要内存时可能会被系统终止。

2、生命周期方法逐个分析

最普通的正常的情况下我们点开一个新的Activity然后按下返回键关了这个Activity生命周期是这样子走的:
点开一个新的Activity(还没开启过): 先执行onCreate,紧接着执行onStart,接着这行onResume,然后就停在这个onResume,我们做一些操作嘛。
按下返回键:执行onPause,接着onStop,然后onDestroy,执行了onDestroy了Activity也就销毁了。

2.1、onCreate()

当Activity被创建时的调用的方法。只在创建的时候调用一次。
可以在这个方法里面做一些初始化的工作,比如setContentView加载布局文件,初始化一些变量的值等。这个是开发中最常见的方法。

2.2、onStart()

Activity已经可见了,但是还没办法进行交互,可以说我们还看不见。(不要纠结这句看不见,我们这里本文对于看见的理解是,我必须要能交互我才算看见,不然你说给我看见但是我不能操作屏幕有什么意思。)

2.3 onResume()

Activity已经获取焦点了,Activity处于可见的前台了。用户可以进行交互了在这个阶段。也可以理解为,必须获取焦点才能进行交互。

假设甲Activity是可见的可交互的,但是这时我们的乙Activity(一个新的非全屏的Activity或者一个透明的Activity)至于栈顶时,即在任务栈里我们的乙位甲的上方,此刻我们的甲Activity就会处于Paused状态了,也就是可见但是没能进行交互。

2.4 onPause()

Activity已经失去焦点了。用户没有办法在这个Activity进行操作了。一般来说当用户按下Home键或者按下Back键就会执行这个方法,这个方法执行后紧跟着都是执行onStop()
如果是按下back键:onPause() → onStop() → onDestroy()
如果是按下Home键:onPause() → onStop()

onPause方法不能不能进行回收工作,简单说就是这里进行回收工作很可能会拖慢影响其他Activty的显示,后面会涉及到。
回收和清理工作轻一点的科技交给onStop,重一些的交给onDestroy。

2.5 onStop()

Activity不可见了。
在这个方法我们可以进行一些比较简单的回收工作。

2.6 onDestroy()

Activity被销毁了,这个Activity死掉了,出栈了,拜拜了。
在这里我们可以做一些最终的回收和资源释放的工作。

2.7 onRestart()

Activity正在重新启动,也就是从不可见变为可见的一个过程。
当用户按下Home键然后有回到当前程序,就会执行这个方法,或者当用户从当前甲Activity打开一个新的Activity,然后又back键返回到甲Activity,又或者用户按下任务列表,然后选择了刚刚打开过的那个程序,那么这个方法也会执行。

3、常见的Activity的操作涉及的生命周期

附上代码先:
MainActivity


public class MainActivity extends Activity {

    private static final String TAG="Lifecycle";



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

        Log.d(TAG, "MainActivity onCreate  创建 执行");

        findViewById(R.id.mTvOpen).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                startActivity(new Intent(MainActivity.this,SecondActivity.class));
            }
        });

    }



    @Override
    protected void onStart() {
        super.onStart();
        Log.d(TAG, "MainActivity onStart  可见 执行");
    }


    @Override
    protected void onResume() {
        super.onResume();
        Log.d(TAG, "MainActivity onResume  获取焦点 执行");

    }


    @Override
    protected void onPause() {
        super.onPause();
        Log.d(TAG, "MainActivity onPause  失去焦点 执行");
    }

    @Override
    protected void onStop() {
        super.onStop();
        Log.d(TAG, "MainActivity onStop  不可见 执行");
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        Log.d(TAG, "MainActivity onDestroy  销毁 执行");
    }


    // 以上6个 加 另外一个 onRestart


    @Override
    protected void onRestart() {
        super.onRestart();
        Log.d(TAG, "MainActivity onRestart  重新打开Activity");
    }

    // 重写两个方法,数据的恢复和保存
    @Override
    protected void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
        Log.d(TAG, "MainActivity onSaveInstanceState  保存数据");
    }

    @Override
    protected void onRestoreInstanceState(Bundle savedInstanceState) {
        super.onRestoreInstanceState(savedInstanceState);
        Log.d(TAG, "MainActivity onRestoreInstanceState  恢复数据");
    }
}

.
.

SecondActivity


public class SecondActivity extends Activity{

    private static final String TAG="Lifecycle";


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

        Log.d(TAG, "SecondActivity onCreate  创建 执行");

    }


    @Override
    protected void onStart() {
        super.onStart();
        Log.d(TAG, "SecondActivity onStart  可见 执行");
    }


    @Override
    protected void onResume() {
        super.onResume();
        Log.d(TAG, "SecondActivity onResume  获取焦点 执行");

    }


    @Override
    protected void onPause() {
        super.onPause();
        Log.d(TAG, "SecondActivity onPause  失去焦点 执行");
    }

    @Override
    protected void onStop() {
        super.onStop();
        Log.d(TAG, "SecondActivity onStop  不可见 执行");
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        Log.d(TAG, "SecondActivity onDestroy  销毁 执行");
    }


    // 以上6个 加 另外一个 onRestart


    @Override
    protected void onRestart() {
        super.onRestart();
        Log.d(TAG, "SecondActivity onRestart  重新打开Activity");
    }
}


这两份代码里面我们在每一个6+1个生命周期的方法都进行了对应的log打印语句,另外,我们还给MainActivity添加了onSaveInstanceState(数据保存)和onRestoreInstanceState(数据恢复)的方法的log打印。

3.1、打开一个全新的Activity

(注:3.1-3.6的示例中,先开启自动屏蔽log中的onSaveInstanceState方法的打印,到了我们说Avtivity的异常销毁的时候在回来看,就会知道onSaveInstanceState为什么会出现和出现的作用了。)
onCreate → onStart → onPause

12-02 22:23:42.052 16933-16933/? D/Lifecycle: MainActivity onCreate  创建 执行
12-02 22:23:42.052 16933-16933/? D/Lifecycle: MainActivity onStart  可见 执行
12-02 22:23:42.052 16933-16933/? D/Lifecycle: MainActivity onResume  获取焦点 执行

3.2 打开一个Activity,接着按下Back键

onCreate → onStart → onPause → onPause → onStop → onDestroy

打开,back.gif

12-02 22:29:50.100 21748-21748/? D/Lifecycle: MainActivity onCreate  创建 执行
12-02 22:29:50.100 21748-21748/? D/Lifecycle: MainActivity onStart  可见 执行
12-02 22:29:50.100 21748-21748/? D/Lifecycle: MainActivity onResume  获取焦点 执行
12-02 22:29:51.304 21748-21748/com.amqr.activitylifecycle D/Lifecycle: MainActivity onPause  失去焦点 执行
12-02 22:29:51.808 21748-21748/com.amqr.activitylifecycle D/Lifecycle: MainActivity onStop  不可见 执行
12-02 22:29:51.808 21748-21748/com.amqr.activitylifecycle D/Lifecycle: MainActivity onDestroy  销毁 执行

3.3、打开一个Activity,然后按下Home键

打开一个新的Activity:
onCreate → onStart → onResume

按下Home键:
onPause → onStop

打开,home.gif
12-04 21:41:35.407 9001-9001/com.amqr.activitylifecycle D/Lifecycle: MainActivity onCreate  创建 执行
12-04 21:41:35.407 9001-9001/com.amqr.activitylifecycle D/Lifecycle: MainActivity onStart  可见 执行
12-04 21:41:35.407 9001-9001/com.amqr.activitylifecycle D/Lifecycle: MainActivity onResume  获取焦点 执行

12-04 21:41:36.919 9001-9001/com.amqr.activitylifecycle D/Lifecycle: MainActivity onPause  失去焦点 执行
12-04 21:41:37.415 9001-9001/com.amqr.activitylifecycle D/Lifecycle: MainActivity onSaveInstanceState  保存数据
12-04 21:41:37.415 9001-9001/com.amqr.activitylifecycle D/Lifecycle: MainActivity onStop  不可见 执行

(有一个关于透明主题不执行onStop的说法还没验证)

3.4、打开程序A,(启动默认的启动页MainActivity),按下任务列表,重新选择程序A

12-04 21:30:43.979 4670-4670/? D/Lifecycle: MainActivity onCreate  创建 执行
12-04 21:30:43.979 4670-4670/? D/Lifecycle: MainActivity onStart  可见 执行
12-04 21:30:43.979 4670-4670/? D/Lifecycle: MainActivity onResume  获取焦点 执行
// 按下任务列表
12-04 21:30:47.319 4670-4670/com.amqr.activitylifecycle D/Lifecycle: MainActivity onPause  失去焦点 执行
12-04 21:30:47.979 4670-4670/com.amqr.activitylifecycle D/Lifecycle: MainActivity onSaveInstanceState  保存数据
12-04 21:30:47.979 4670-4670/com.amqr.activitylifecycle D/Lifecycle: MainActivity onStop  不可见 执行
// 选择打开app
12-04 21:30:50.811 4670-4670/com.amqr.activitylifecycle D/Lifecycle: MainActivity onRestart  重新打开Activity
12-04 21:30:50.811 4670-4670/com.amqr.activitylifecycle D/Lifecycle: MainActivity onStart  可见 执行
12-04 21:30:50.811 4670-4670/com.amqr.activitylifecycle D/Lifecycle: MainActivity onResume  获取焦点 执行

任务列表重选当前app.gif

打开自然是: onCreate → onStart → onResume
按下任务列表:onPause → onStop
选择这个app:onRestart → onStart → onResume

3.5、打开甲Activity,然后打开乙Activity,接着按下Back键 (注意onPause和onStop之间)

打开甲:
甲onCreate → 甲onStart → 甲onResume

接着打开乙:
甲onPause
  → 乙onCreate
  → 乙onStart
  → 乙onResume
→ 甲onStop
(此时界面停留在乙)

接着按下Back:
乙onPause
  甲onRestart
  甲onstart
  甲onResume
乙onStop
乙Destroy
(此时界面停留在甲)

在上面的流程中,我们发现,涉及到其他的Activity的时候,其他的Activity的生命周期流程是在上一个Activity的onPause和onStop之间完成的。
  记得,不是按部就班等到等到上一个先onPause接着onStop之类在执行另外一个Activity的生命周期。

源码其实也证明了这一点,也就是,旧的Activity必先Pause,接着新的Activity才可以创建。
MainActivity代表甲,SecondActivity代表乙

打开A,A打开B,back.gif

12-04 21:53:10.751 12020-12020/? D/Lifecycle: MainActivity onCreate  创建 执行
12-04 21:53:10.751 12020-12020/? D/Lifecycle: MainActivity onStart  可见 执行
12-04 21:53:10.751 12020-12020/? D/Lifecycle: MainActivity onResume  获取焦点 执行
打开B
12-04 21:53:12.919 12020-12020/com.amqr.activitylifecycle D/Lifecycle: MainActivity onPause  失去焦点 执行
12-04 21:53:12.923 12020-12020/com.amqr.activitylifecycle D/Lifecycle: SecondActivity onCreate  创建 执行
12-04 21:53:12.923 12020-12020/com.amqr.activitylifecycle D/Lifecycle: SecondActivity onStart  可见 执行
12-04 21:53:12.923 12020-12020/com.amqr.activitylifecycle D/Lifecycle: SecondActivity onResume  获取焦点 执行
12-04 21:53:13.315 12020-12020/com.amqr.activitylifecycle D/Lifecycle: MainActivity onSaveInstanceState  保存数据
12-04 21:53:13.315 12020-12020/com.amqr.activitylifecycle D/Lifecycle: MainActivity onStop  不可见 执行
(别看执行是MainActivity的onStop,但是现在停留的界面是B)


// Back
12-04 21:53:22.255 12020-12020/com.amqr.activitylifecycle D/Lifecycle: SecondActivity onPause  失去焦点 执行
12-04 21:53:22.255 12020-12020/com.amqr.activitylifecycle D/Lifecycle: MainActivity onRestart  重新打开Activity
12-04 21:53:22.255 12020-12020/com.amqr.activitylifecycle D/Lifecycle: MainActivity onStart  可见 执行
12-04 21:53:22.255 12020-12020/com.amqr.activitylifecycle D/Lifecycle: MainActivity onResume  获取焦点 执行
12-04 21:53:22.619 12020-12020/com.amqr.activitylifecycle D/Lifecycle: SecondActivity onStop  不可见 执行
12-04 21:53:22.619 12020-12020/com.amqr.activitylifecycle D/Lifecycle: SecondActivity onDestroy  销毁 执行


3.6、打开一个新的Activity,锁屏,解锁屏幕,

打开新的Activity:
onCreate → onStart → onResume

锁屏
onPause → onStop

解锁:
onRestart → onStart → onResume

锁屏 解锁.gif

12-04 22:02:42.191 15855-15855/com.amqr.activitylifecycle D/Lifecycle: MainActivity onCreate  创建 执行
12-04 22:02:42.191 15855-15855/com.amqr.activitylifecycle D/Lifecycle: MainActivity onStart  可见 执行
12-04 22:02:42.191 15855-15855/com.amqr.activitylifecycle D/Lifecycle: MainActivity onResume  获取焦点 执行

// 锁屏
12-04 22:02:46.951 15855-15855/com.amqr.activitylifecycle D/Lifecycle: MainActivity onPause  失去焦点 执行
12-04 22:02:46.951 15855-15855/com.amqr.activitylifecycle D/Lifecycle: MainActivity onSaveInstanceState  保存数据
12-04 22:02:46.951 15855-15855/com.amqr.activitylifecycle D/Lifecycle: MainActivity onStop  不可见 执行


// 解锁
12-04 22:02:49.291 15855-15855/com.amqr.activitylifecycle D/Lifecycle: MainActivity onRestart  重新打开Activity
12-04 22:02:49.291 15855-15855/com.amqr.activitylifecycle D/Lifecycle: MainActivity onStart  可见 执行
12-04 22:02:49.315 15855-15855/com.amqr.activitylifecycle D/Lifecycle: MainActivity onResume  获取焦点 执行

.
.
大概的常见的几种就是像上面这个样子了。
看了上面打印的log,我们知道 onResume如果要出现一定先出现onstart,对应的,onStop要出现那么前面一定先出现onPause。

onstart 接 onResume
onPause 接 onStop

只要清楚了 焦点 和 可见 的区别,那么上面的流程都是自然而言的,也可以说焦点是个中间人。

谷歌的文档建议我们不要在onPause做过多的工作,现在通过上面的两个Activity的切换过程我们也是可以理解的。
旧的Activity必须先Pause,新的才能onCreate,onStart和onResume,既然这样,为了让新的界面能够快速的显示出来给用户看,那么onPause肯定不能有太多的重量级操作。
所以,onPause里面不能放耗时操作,否则影响界面切换速度。

.
.

三、进程的优先级

上文中我们多次提到当内存不足时,当前Activity被系统gc回收的。那么这回收大概是怎么回收,这肯定是一套复杂的系统,但是这里面涉及到一个进程优先级的问题。

gc的回收涉及到一个进程的优先级的问题

1、进程的几个小特点

首先我们知道,一般而言一个App运行的就代表一个进程在系统执行,进程大概有以下这么几个特点:

** (1)应用程序启动时创建了进程;**
** (2)应用程序退出的时候,进程可能并没有退出;**
** (3)当可用内存空间不足,系统会自动清理没有用到的进程;**

2、进程的优先级分类

进程的优先级​ (针对垃圾回收,谁的优先级低就越容易被回收)

安卓的进程可以分为这么几种:

  • Foreground process(前台进程)
  • Visible process (可视进程)
  • Service process (服务进程)
  • Background process(后台进程)
  • Empty process (空进程)

2.1. Foreground process(前台进程)

用户正在操作的应用程序所在的进程,就是前台进程。即当前Activity的onResume方法被执行了,可以响应点击事件。

2.2. Visible process (可视进程)

应用程序的ui界面,用户还可以看到,但是不能操作了。(比如全透明了,比如一个非全屏的界面在我们的界面的上方)

2.3. Service process (服务进程)

当前操作的不是这个程序,但是这个程序有一个后台的 服务 还处于运行状态。

2.4. Background process(后台进程)

应用程序没有服务处于运行状态,也没有服务在运行,应用程序被最小化了,(activity执行了onStop方法,就是界面最小化)

2.5. Empty process (空进程)

没有任何四大组件在运行,所有的Activity都关闭了,任务栈清空了。(任务栈的概念我们后面有介绍)

.
.

进程的里面优先级依次递减,前台进程优先级最高,空进程优先级最低。
**
  
当手机系统内容不足,那么手机会自动回收进程,从低级回收起。**

*是不是担心如果这样那如果手机把我们正在用的进程给回收掉怎么办?如果手机内存满到要回收前台进程,那么手机距离卡死关机或者自动重启也就不远了

四、Activity的正常销毁和异常销毁

1、正常销毁

一个Activity我们通过按下Home键,Back键,或者某一个屏幕的空间我们finish掉都是正常销毁。

2、异常销毁

正常销毁自然是最好的,但是Activity也会有异常销毁的情况,比如下面这两种情况:

  • 1、手机横竖屏的切换,Activity被强制撤销重建,那么就算是异常销毁了。
  • 2、当前程序为后台进程时,因为系统内存不足给gc回收了。

3、手机横竖屏的Activity异常销毁与SaveInstanceState保存数据

我们手机横竖屏会导致重走生命周期这点我们肯定已经是知道的了。
  当我们在竖屏的时候往Edittext里面填写一些数据,然后在切换到横屏,这时候我们发现重建完的Activity还保留我们在Edittext的文本。但是在这个过程中我们开发人员并没有做什么保存数据的操作。那这些为什么数据是怎么保存下来的呢?

其实这就是SaveInstanceState帮我们做的。

说之前我们先来看一下我们熟悉的onCreate的参数
我们的编码的时候复写onCreate是经常的事,每次参数里都有一个savedInstanceState,平时有人也许没有多大注意它,其实它干的事情就是在我们的Activity异常销毁的时候帮我们保存数据用的。

代码依然采用上面的提供的生命周期示例演示的MainActivity和SecondActivity的代码。

横竖屏切换保存数据.gif
12-03 02:17:25.388 6883-6883/? D/Lifecycle: MainActivity onCreate  创建 执行
12-03 02:17:25.388 6883-6883/? D/Lifecycle: MainActivity onStart  可见 执行
12-03 02:17:25.388 6883-6883/? D/Lifecycle: MainActivity onResume  获取焦点 执行

12-03 02:17:28.908 6883-6883/com.amqr.activitylifecycle D/Lifecycle: MainActivity onPause  失去焦点 执行
12-03 02:17:28.908 6883-6883/com.amqr.activitylifecycle D/Lifecycle: MainActivity onSaveInstanceState  保存数据
12-03 02:17:28.908 6883-6883/com.amqr.activitylifecycle D/Lifecycle: MainActivity onStop  不可见 执行
12-03 02:17:28.908 6883-6883/com.amqr.activitylifecycle D/Lifecycle: MainActivity onDestroy  销毁 执行

12-03 02:17:28.932 6883-6883/com.amqr.activitylifecycle D/Lifecycle: MainActivity onCreate  创建 执行
12-03 02:17:28.932 6883-6883/com.amqr.activitylifecycle D/Lifecycle: MainActivity onStart  可见 执行
12-03 02:17:28.932 6883-6883/com.amqr.activitylifecycle D/Lifecycle: MainActivity onRestoreInstanceState  恢复数据
12-03 02:17:28.932 6883-6883/com.amqr.activitylifecycle D/Lifecycle: MainActivity onResume  获取焦点 执行

从上面的日志打印中我们知道,由于Activity异常销毁,那么这个时候的savaInstanceState和onRestoreInstanceState方法都被执行了。

就是利用这两个方法我们才得以实现数据的保存和恢复的。

当我们的程序Activity异常销毁时,那么savaInstanceState就会调用,将保存着数据的Bundler对象传递给onRestoreInstanceState和onCreate()方法。

利用他们两者一个保存数据一个恢复数据的特点,其实我们可以做很多事,只需要在对应的复写的里面加上对应的逻辑就行。比如我们的存数据在 安卓的Application,可能因为程序异常销毁而导致数据丢失,那么这个时候应可以利用这对方法来进行完善了。
相关了解请参见: 莫往Applicaotion存缓存/app被系统回收之后再打开发生了什么

savaInstanceState和onRestoreInstanceState方法一般都是配对使用的。

4、savaInstanceState、onRestoreInstanceState的作用

savaInstanceState的作用 : 当程序的组件被异常销毁时,做一定的数据保存的工作。
onRestoreInstanceState的作用:恢复程序被异常的终止时的数据。

5、onRestoreInstanceState方法和onCreate的savedInstanceState参数

.
.
onCreate的savedInstanceState参数

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

        Log.d(TAG, "SecondActivity onCreate  创建 执行");

    }

.

.

onRestoreInstanceState方法

    @Override
    protected void onRestoreInstanceState(Bundle savedInstanceState) {
        super.onRestoreInstanceState(savedInstanceState);
        Log.d(TAG, "MainActivity onRestoreInstanceState  恢复数据");
    }

当Activity被异常销毁时,savaInstanceState会保存的数据这个我们已经知道了。

保存没什么可说,恢复却出现了不同。
就算我们不复写onRestoreInstanceState方法,也可以利用生命周期的onCreate方法参数 savaInstanceState来进行数据恢复。
当然如果我们复写onRestoreInstanceState方法,一样可进行数据恢复。

两者有什么区别呢?

  • 针对onCreate的参数Bundle savedInstanceState有可能为空:
      如果之前Activity的savaInstanceState方法没有执行过,那么onCreate的参数Bundle savedInstanceState有可能为空,这样就导致了onCreate的参数Bundle savedInstanceState有可能为空,所以在利用onCreate的参数Bundle savedInstanceState进行数据恢复的时候需要进行参数的非空判断,这个参数不一定是有值的。
  • 针对onRestoreInstanceState(推荐):
      如果之前Activity的savaInstanceState方法没有执行过,那么onRestoreInstanceState肯定不会执行。也就是说,只要onRestoreInstanceState方法执行,那么之前肯定执行过savaInstanceState方法。所以,在onRestoreInstanceState方法进行恢复数据的时候,不需要进行什么非空判断,直接用。

所以:推荐在 onRestoreInstanceState 方法进行数据恢复。
(Google也是推荐我们这么做的)

6、savaInstanceState和onRestoreInstanceState何时执行

savaInstanceState何时执行:

  • 1.当用户按下HOME键时。
      这是显而易见的,系统不知道你按下HOME后要运行多少其他的程序,自然也不知道acitvity A是否会被销毁所以系统会调用onSaveInstanceState,让用户有机会保存某些非永久性数据,以下几种分析都遵循该原则。(参见 一、3.3,有具体代码和gif图片演示 )
  • 2.打开任务列表(长按HOME键/长按选项键,因机型而异),按下就执行保存数据。(参见 四 3)
      因为你按下任务列表,你完全有可能选择其他程序然后玩很久,当前这个程序就被冷落好久了,既然被冷落了,就有可能被gc回收,所以保存数据很正常。(参见 一、3.4)
  • 3.从甲Activity 中启动一个新的activity时。(参见 一、3.5)
  • 4.屏幕横竖屏切换
  • 5、锁屏(锁屏会执行savaInstanceState,解锁不会执行)(参见 一、3.6)
    以上说的几种情况全经测试。

具体示例请看 生命周期的示例

onRestoreInstanceState何时执行

Activity被异常销毁后打开Activity,
横竖屏切换后打开Activity,
或者说gc回收后打开Activity。

7、题外话,android:configChanges,切屏后不重走生命周期。

可否让程序切换横竖屏时不重走生命周期?可以的
在Activity的manifest里面的配置加上这么一句
android:configChanges="orientation|screenSize"

        <activity android:name=".MainActivity"
            android:configChanges="orientation|screenSize"
            >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>

就可以实现。为什么呢,我们来分析下:

屏幕方向是一个系统的属性,键盘是否隐藏也是系统的一个属性,语言也是系统的一个属性,系统为我们提供了很多的属性,这些属性我们都可以利用manifest里面的android:configChanges来执行控制是否改变,只要是被指定了的属性,就会固定下来,无视这个属性发生的改变。

安卓部分属性表

属性 含义
mcc 移动国家号码,由三位数字组成,每个国家都有自己独立的MCC,可以识别手机用户所属国家。
mnc 移动网号,在一个国家或者地区中,用于区分手机用户的服务商。
locale 所在地区发生变化。
touchscreen 触摸屏已经改变。(少见)
keyboard 键盘模式发生变化,例如:用户接入外部键盘输入。
keyboardHidden 键盘的可访问,用户调出了键盘
navigation 导航型发生了变化,比如轨迹球(少见)
orientation 最常见,设备旋转,横向显示和竖向显示模式切换。
screenSize 当屏幕的尺寸发生了改变,但是当改变屏幕时尺寸就会认为发生了改变,MiniSdkVersion和 TargetSdkVersion属性大于等于13的情况下,如果你想阻止程序在运行时重新加载Activity,除了设置"orientation",你还必须设置"screenSize"。
fontScale 全局字体大小缩放发生改变

当我们想指定多个值,可以用“ | ”把多个属性连接起来。

其实这个这个东西用得很少,几乎都是只用于下面这一点:
改变屏幕方向的时候不要重走生命周期。
(有时也用于控制键盘)

注意的是:
当我们的app运行的API版本高于13的时候,需要这么配置:
android:configChanges="orientation|screenSize“

其他的就没什么啦。

分篇完,其他中篇和下篇链接如下

Android-Activity所应该了解的大概就这样。(中)
Android-Activity所应该了解的大概就这样。(下)

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

推荐阅读更多精彩内容

  • Activity https://developer.android.com/guide/components/a...
    XLsn0w阅读 695评论 0 4
  • 启动与销毁Activity 不同于使用 main() 方法启动应用的其他编程范例,Android 系统会通过调用对...
    安卓Boy阅读 1,733评论 3 5
  • 学习资料: Android群英传 Android开发艺术探索 Activity是与用户交互的第一接口,感觉说是四大...
    英勇青铜5阅读 2,474评论 15 41
  • 4月份围墙砌起来之后,母亲就在那块预留地挖出几垄小小的土堆,在适合下种的清明节种了一些蔬菜。6月份端午我再回家的时...
    不一_cc阅读 422评论 0 0
  • 那时的我们不以为然,后来的我们无比怀念。 青春大概就是这样一个矛盾体。 我们一年一年的换教室,一年一年的把我们书本...
    简简单单_阅读 203评论 0 0