Android应用开发(11)Activity生命周期

Android应用开发学习笔记——目录索引

 参考android官网:

Activity  |  Android Developers

activity 生命周期的阶段  |  Android 开发者  |  Android Developers

一、介绍Activity的生命周期

每个 activity 都具有生命周期。

activity 生命周期由 activity 可能会经历的不同状态组成:从 activity 首次初始化,到最终销毁,再由系统收回其内存。当用户启动您的应用、在 activity 之间导航、在应用内外部导航时,activity 会切换状态。下图显示了 activity 生命周期的所有状态。顾名思义,这些状态表示 activity 所处的状态。

 在 activity 生命周期状态发生变化时,通常需要更改某些行为,或者运行一些代码。因此,Activity 类本身以及 Activity 的任何子类(例如 AppCompatActivity)都会实现一组生命周期回调方法。Android 会在 activity 从一种状态切换为另一种状态时调用这些回调,可以在自己的 activity 中替换这些方法,通过执行任务来响应这些生命周期状态变化。下图显示了生命周期状态以及可用的可替换回调。

activity的生命周期

oncreate()->onstart()->onResume()->onRestart()->onPouse()->onStop()->onDestory()

 上面图概括了android生命周期的各个环节,描述了activity从生成到销毁的过程。

  • onCreate() : 创建活动。把页面布局加载进内存,通常做一些初始化设置;
  • onStart(): 开始活动。把活动页面显示在屏幕上,在Activity即将可见时调用;
  • onResume(): 恢复活动。在Activity已可见,获取焦点开始与用户交互时调用;
  • onPause(): 暂停活动。在Activity失去前台状态、不再可聚焦或转换到停止/隐藏或销毁状态之前调用;
  • onStop() : 停止活动。在Activity对用户不可见时调用,页面将不在屏幕上显示。
  • onDestroy() :销毁活动。在Activity销毁时调用;回收活动占用的系统资源,把页面从内存中清除。
  • onRestart() : 重启活动。重新加载内存中的页面数据。在Activity从停止状态再次启动时调用,始终跟随onStart()

二、测试Activity的生命周期

1. 测试Activity(活动)打开和关闭

1.1 打开新Activity(活动)页面

打开新页面的方法调用顺序为onCreate→onStart→onResume

07-30 21:01:36.219  7623  7623 D lzl-test-MainActivity: [21:01:36:217]onCreate
07-30 21:01:36.229  7623  7623 D lzl-test-MainActivity: [21:01:36:228]onStart
07-30 21:01:36.232  7623  7623 D lzl-test-MainActivity: [21:01:36:232]onResume

1.2 Activity(活动)退到后台并从后台恢复

页面退到后台的方法调用顺序为onPause→onStop

页面从后台恢复到前台的方法调用顺序为onRestart→onStart→onResume

//页面退到后台

07-30 21:02:59.412  7623  7623 D lzl-test-MainActivity: [21:02:59:411]onPause
07-30 21:03:00.128  7623  7623 D lzl-test-MainActivity: [21:03:00:127]onStop

// 从后台恢复

07-30 22:00:26.217 30850 30850 D lzl-test-MainActivity: [22:00:26:215]onRestart
07-30 22:00:26.229 30850 30850 D lzl-test-MainActivity: [22:00:26:228]onStart
07-30 22:00:26.236 30850 30850 D lzl-test-MainActivity: [22:00:26:235]onResume

onRestart() 又是什么情况呢?onRestart() 方法与 onCreate() 非常相似。无论是 onCreate() 还是 onRestart(),都会在相应 activity 变得可见之前调用。onCreate() 方法只在第一次被调用,之后会调用 onRestart()onRestart() 方法用于放置仅在 activity 是首次启动时才需要调用的代码。 

在应用启动并且系统调用 onStart() 后,该应用将在屏幕上变得可见。当应用恢复并且系统调用 onResume() 后,应用可获得用户焦点,即,用户可以与应用交互。应用在屏幕上完全显示并且具有用户焦点时的这部分生命周期称为“交互式”生命周期。

当应用进入后台后,焦点在 onPause() 后便会丢失,并且在 onStop() 后,该应用将不再可见。

1.3 Activity(活动)完全关闭或在最近任务清除应用

关闭旧页面的方法调用顺序为onPause→onStop→onDestroy

07-30 21:25:56.472 18087 18087 D lzl-test-MainActivity: [21:25:56:471]onPause
07-30 21:25:56.506 18087 18087 D lzl-test-MainActivity: [21:25:56:505]onStop
07-30 21:25:57.681 18087 18087 D lzl-test-MainActivity: [21:25:57:680]onDestroy

 activity(和应用)完全关闭。执行 onDestroy() 方法意味着相应 activity 已完全关闭,可以进行垃圾回收。垃圾回收是指自动清理不再使用的对象。调用 onDestroy() 后,系统会知道这些资源是可丢弃的,然后开始清理这部分内存。如果您的代码手动调用该 activity 的 finish() 方法,或者用户强行退出该应用(例如,用户强行退出,或在“最近使用的应用”屏幕关闭该应用),您的 activity 也可能会完全关闭。如果您的应用长时间没有在屏幕上显示,Android 系统也可能会自行关闭您的 activity。Android 这样做是为了节省电量,同时允许其他应用使用您应用的资源。

注意:在单个 activity 实例的生命周期内,onCreate() 和 onDestroy() 仅调用了一次:onCreate() 用于首次初始化应用,onDestroy() 则用于清理您的应用所用的资源。 

2. Activity(活动)旋转

通过如下方法获取屏幕横竖屏状态

    /* 获取当前屏幕是否是竖屏显示 */
    public static boolean isScreenOrientationPortrait(Context context) {
        boolean isPortrait = true;
        try {
            //获取设置的配置信息
            Configuration configuration = context.getResources().getConfiguration();
            int orientation = configuration.orientation; //获取屏幕方向
            if (orientation == configuration.ORIENTATION_PORTRAIT) {
                //竖屏
                isPortrait = true;
            } else if (orientation == configuration.ORIENTATION_LANDSCAPE) {
                //横屏
                isPortrait = false;
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return isPortrait;
    }


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

        if (Utils.isScreenOrientationPortrait(getApplicationContext())) {
            Utils.printLifecycle(TAG, "当前状态为竖屏");
        } else {
            Utils.printLifecycle(TAG, "当前状态为横屏");
        }
        Utils.printLifecycle(TAG, "onCreate");
        findViewById(R.id.button_to_next).setOnClickListener(this);
    }

横竖屏切换涉及到的是Activity的android:configChanges属性;

参考:android:configChanges属性解析_互联网小熊猫的博客-CSDN博客
android:configChanges可以设置的属性值我们暂时只关注和屏幕旋转相关的:

  • orientation: 屏幕方向改变了,消除横竖屏的影响
  • screenSize: 屏幕大小改变了,消除屏幕大小的影响
  • keyboardHidden:键盘的可用性发生了改变,消除键盘的影响

2.1 不配置android:configChanges

不配置android:configChanges:横竖屏切换事,当前活动的Activity会重新启动,其中的过程是:在销毁之前会先调用onSaveInstanceState()方法去保存你应用中的一些数据,然后调用onDestroy()方法,最后调用onCreate()、onStart()、onResume()等方法启动一个新的Activity。

07-30 23:09:13.956  6720  6720 D lzl-test-MainActivity: [23:09:13:953]当前状态为竖屏
07-30 23:09:13.956  6720  6720 D lzl-test-MainActivity: [23:09:13:956]onCreate
07-30 23:09:13.967  6720  6720 D lzl-test-MainActivity: [23:09:13:967]onStart
07-30 23:09:13.971  6720  6720 D lzl-test-MainActivity: [23:09:13:970]onResume

// 竖屏 切到 横屏
07-30 23:09:15.842  6720  6720 D lzl-test-MainActivity: [23:09:15:841]onPause
07-30 23:09:15.845  6720  6720 D lzl-test-MainActivity: [23:09:15:845]onStop
07-30 23:09:15.847  6720  6720 D lzl-test-MainActivity: [23:09:15:846]onSaveInstanceState
07-30 23:09:15.848  6720  6720 D lzl-test-MainActivity: [23:09:15:848]onDestroy
07-30 23:09:15.947  6720  6720 D lzl-test-MainActivity: [23:09:15:946]当前状态为横屏
07-30 23:09:15.948  6720  6720 D lzl-test-MainActivity: [23:09:15:947]onCreate
07-30 23:09:15.951  6720  6720 D lzl-test-MainActivity: [23:09:15:951]onStart
07-30 23:09:15.952  6720  6720 D lzl-test-MainActivity: [23:09:15:952]onRestoreInstanceState
07-30 23:09:15.956  6720  6720 D lzl-test-MainActivity: [23:09:15:956]onResume

// 横屏 切到 竖屏
07-30 23:09:19.248  6720  6720 D lzl-test-MainActivity: [23:09:19:248]onPause
07-30 23:09:19.250  6720  6720 D lzl-test-MainActivity: [23:09:19:249]onStop
07-30 23:09:19.251  6720  6720 D lzl-test-MainActivity: [23:09:19:250]onSaveInstanceState
07-30 23:09:19.252  6720  6720 D lzl-test-MainActivity: [23:09:19:251]onDestroy
07-30 23:09:19.330  6720  6720 D lzl-test-MainActivity: [23:09:19:330]当前状态为竖屏
07-30 23:09:19.331  6720  6720 D lzl-test-MainActivity: [23:09:19:331]onCreate
07-30 23:09:19.334  6720  6720 D lzl-test-MainActivity: [23:09:19:333]onStart
07-30 23:09:19.335  6720  6720 D lzl-test-MainActivity: [23:09:19:334]onRestoreInstanceState
07-30 23:09:19.339  6720  6720 D lzl-test-MainActivity: [23:09:19:338]onResume

2.2 配置为android:configChanges="orientation"

同【不配置android:configChanges】上面打印的log一模一样

07-30 23:10:53.278 10401 10401 D lzl-test-MainActivity: [23:10:53:277]当前状态为竖屏
07-30 23:10:53.279 10401 10401 D lzl-test-MainActivity: [23:10:53:279]onCreate
07-30 23:10:53.287 10401 10401 D lzl-test-MainActivity: [23:10:53:287]onStart
07-30 23:10:53.290 10401 10401 D lzl-test-MainActivity: [23:10:53:289]onResume

// 竖屏 切到 横屏
07-30 23:11:01.222 10401 10401 D lzl-test-MainActivity: [23:11:01:221]onPause
07-30 23:11:01.238 10401 10401 D lzl-test-MainActivity: [23:11:01:237]onStop
07-30 23:11:01.239 10401 10401 D lzl-test-MainActivity: [23:11:01:239]onSaveInstanceState
07-30 23:11:01.241 10401 10401 D lzl-test-MainActivity: [23:11:01:240]onDestroy
07-30 23:11:01.310 10401 10401 D lzl-test-MainActivity: [23:11:01:310]当前状态为横屏
07-30 23:11:01.311 10401 10401 D lzl-test-MainActivity: [23:11:01:311]onCreate
07-30 23:11:01.314 10401 10401 D lzl-test-MainActivity: [23:11:01:314]onStart
07-30 23:11:01.315 10401 10401 D lzl-test-MainActivity: [23:11:01:315]onRestoreInstanceState
07-30 23:11:01.320 10401 10401 D lzl-test-MainActivity: [23:11:01:319]onResume

// 横屏 切到 竖屏
07-30 23:11:05.461 10401 10401 D lzl-test-MainActivity: [23:11:05:460]onPause
07-30 23:11:05.462 10401 10401 D lzl-test-MainActivity: [23:11:05:462]onStop
07-30 23:11:05.463 10401 10401 D lzl-test-MainActivity: [23:11:05:463]onSaveInstanceState
07-30 23:11:05.464 10401 10401 D lzl-test-MainActivity: [23:11:05:464]onDestroy
07-30 23:11:05.599 10401 10401 D lzl-test-MainActivity: [23:11:05:599]当前状态为竖屏
07-30 23:11:05.601 10401 10401 D lzl-test-MainActivity: [23:11:05:600]onCreate
07-30 23:11:05.604 10401 10401 D lzl-test-MainActivity: [23:11:05:603]onStart
07-30 23:11:05.604 10401 10401 D lzl-test-MainActivity: [23:11:05:604]onRestoreInstanceState
07-30 23:11:05.607 10401 10401 D lzl-test-MainActivity: [23:11:05:606]onResume

2.3 配置为android:configChanges="screenSize"

同【不配置android:configChanges】和【配置为android:configChanges="orientation"】上面打印的log一模一样

07-30 23:16:01.334 22179 22179 D lzl-test-MainActivity: [23:16:01:333]当前状态为竖屏
07-30 23:16:01.335 22179 22179 D lzl-test-MainActivity: [23:16:01:334]onCreate
07-30 23:16:01.343 22179 22179 D lzl-test-MainActivity: [23:16:01:343]onStart
07-30 23:16:01.347 22179 22179 D lzl-test-MainActivity: [23:16:01:346]onResume

// 竖屏 切到 横屏
07-30 23:16:12.236 22179 22179 D lzl-test-MainActivity: [23:16:12:235]onPause
07-30 23:16:12.238 22179 22179 D lzl-test-MainActivity: [23:16:12:237]onStop
07-30 23:16:12.239 22179 22179 D lzl-test-MainActivity: [23:16:12:239]onSaveInstanceState
07-30 23:16:12.240 22179 22179 D lzl-test-MainActivity: [23:16:12:240]onDestroy
07-30 23:16:12.317 22179 22179 D lzl-test-MainActivity: [23:16:12:316]当前状态为横屏
07-30 23:16:12.317 22179 22179 D lzl-test-MainActivity: [23:16:12:317]onCreate
07-30 23:16:12.319 22179 22179 D lzl-test-MainActivity: [23:16:12:319]onStart
07-30 23:16:12.320 22179 22179 D lzl-test-MainActivity: [23:16:12:320]onRestoreInstanceState
07-30 23:16:12.325 22179 22179 D lzl-test-MainActivity: [23:16:12:324]onResume

// 横屏 切到 竖屏
07-30 23:16:15.501 22179 22179 D lzl-test-MainActivity: [23:16:15:499]onPause
07-30 23:16:15.505 22179 22179 D lzl-test-MainActivity: [23:16:15:504]onStop
07-30 23:16:15.508 22179 22179 D lzl-test-MainActivity: [23:16:15:507]onSaveInstanceState
07-30 23:16:15.509 22179 22179 D lzl-test-MainActivity: [23:16:15:509]onDestroy
07-30 23:16:15.593 22179 22179 D lzl-test-MainActivity: [23:16:15:592]当前状态为竖屏
07-30 23:16:15.593 22179 22179 D lzl-test-MainActivity: [23:16:15:593]onCreate
07-30 23:16:15.595 22179 22179 D lzl-test-MainActivity: [23:16:15:595]onStart
07-30 23:16:15.598 22179 22179 D lzl-test-MainActivity: [23:16:15:598]onRestoreInstanceState
07-30 23:16:15.601 22179 22179 D lzl-test-MainActivity: [23:16:15:600]onResume

2.4 配置为android:configChanges="orientation|screenSize"或者配置为android:configChanges="orientation|keyboardHidden|screenSize"

07-30 23:18:46.715 27063 27063 D lzl-test-MainActivity: [23:18:46:714]当前状态为竖屏
07-30 23:18:46.716 27063 27063 D lzl-test-MainActivity: [23:18:46:715]onCreate
07-30 23:18:46.724 27063 27063 D lzl-test-MainActivity: [23:18:46:724]onStart
07-30 23:18:46.729 27063 27063 D lzl-test-MainActivity: [23:18:46:729]onResume

// 竖屏 切到 横屏
07-30 23:18:51.059 27063 27063 D lzl-test-MainActivity: [23:18:51:058]onConfigurationChanged

// 横屏 切到 竖屏
07-30 23:18:52.000 27063 27063 D lzl-test-MainActivity: [23:18:51:998]onConfigurationChanged

结论

1. 设置Activity的android:configChanges属性为【不设置】、【orientation】、【screenSize】、【keyboardHidden】、【orientation|keyboardHidden】、【screenSize|keyboardHidden】的时候,横竖屏切换会重新调用各个生命周期方法,切横屏时会执行1次,切竖屏时会执行1次;
2. 设置Activity的属性为android:configChanges属性为【orientation|screenSize】、【orientation|keyboardHidden|screenSize】时,横竖屏切换不会重新调用各个生命周期方法,只会执行onConfigurationChanged方法;

3. Activity(活动)跳转

从当前页面跳到新页面,跳转代码如下:    

         startActivity(new Intent(源页面.this, 目标页面.class));

不会引起歧义的话,也可或者简化为:      

        startActivity(new Intent(this, 目标页面.class));

从当前页面回到上一个页面,相当于关闭当前页面,返回代码如下:      

        finish();  // 结束当前的活动页面

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

        findViewById(R.id.button_to_next).setOnClickListener(this);
        printLifecycle(TAG, "onCreate");
    }

    @Override
    public void onClick(View v) {
        if (v.getId() == R.id.button_to_next) {
            // 从当前页面跳到其他页面
            startActivity(new Intent(this, SecondaryActivity.class));
        }
    }

07-30 22:34:59.801 19854 19854 D lzl-test-MainActivity: [22:34:59:799]当前状态为竖屏
07-30 22:34:59.802 19854 19854 D lzl-test-MainActivity: [22:34:59:802]onCreate
07-30 22:34:59.812 19854 19854 D lzl-test-MainActivity: [22:34:59:812]onStart
07-30 22:34:59.819 19854 19854 D lzl-test-MainActivity: [22:34:59:819]onResume


07-30 22:35:01.218 19854 19854 D lzl-test-MainActivity: [22:35:01:217]onPause
07-30 22:35:01.252 19854 19854 D lzl-test-SecondaryActivity: [22:35:01:252]当前状态为竖屏
07-30 22:35:01.253 19854 19854 D lzl-test-SecondaryActivity: [22:35:01:253]onCreate
07-30 22:35:01.255 19854 19854 D lzl-test-SecondaryActivity: [22:35:01:255]onStart
07-30 22:35:01.258 19854 19854 D lzl-test-SecondaryActivity: [22:35:01:258]onResume
07-30 22:35:01.835 19854 19854 D lzl-test-MainActivity: [22:35:01:834]onStop


07-30 22:35:02.978 19854 19854 D lzl-test-SecondaryActivity: [22:35:02:977]onPause
07-30 22:35:02.995 19854 19854 D lzl-test-MainActivity: [22:35:02:994]onRestart
07-30 22:35:02.998 19854 19854 D lzl-test-MainActivity: [22:35:02:998]onStart
07-30 22:35:03.002 19854 19854 D lzl-test-MainActivity: [22:35:03:001]onResume
07-30 22:35:03.593 19854 19854 D lzl-test-SecondaryActivity: [22:35:03:593]onStop
07-30 22:35:03.597 19854 19854 D lzl-test-SecondaryActivity: [22:35:03:597]onDestroy

测试代码:百度网盘链接:百度网盘 请输入提取码 提取码:test   ActivityLifecycleTest目录

app module

4. Activity保存/恢复 bundle 数据

4.1 使用 onSaveInstanceState() 保存 bundle 数据

onSaveInstanceState() 回调方法用于保存 Activity 被销毁后可能需要的任何数据。在生命周期回调图中,系统会在相应 activity 停止后调用 onSaveInstanceState()。每当您的应用进入后台时,系统都会调用它。

c259ab6beca0ca88.png

 请将 onSaveInstanceState() 调用视为一项安全措施;这让您有机会在相应 activity 退出前台时将少量信息保存到 bundle 中。系统现在会保存这些数据,这是因为如果等到关闭应用时再保存,系统可能会面临资源压力。

注意:有时,Android 会关闭整个应用进程,包括与应用相关联的每个 activity。Android 会在系统承受压力并面临视觉延迟风险时执行此类关闭操作,因此此时不会运行额外的回调或代码。应用的进程只会在后台静默地关闭。但对用户来说,应用似乎并没有关闭。当用户返回 Android 系统已关闭的应用时,Android 会重启相应应用。您需要确保发生这种情况时不会对用户造成任何数据损失。

每次都保存数据可以确保 bundle 中的更新数据可以根据需要恢复。

    // 使用这些键将数据保存到实例状态 bundle 以及从中检索数据。
    private final static String COUNT_KEY = "COUNT_KEY";
    private final static String LIFECYCLELOG_KEY = "LIFECYCLELOG_KEY";

    protected void onSaveInstanceState(@NonNull Bundle outState) {
        super.onSaveInstanceState(outState);
        String string = String.format("onSaveInstanceState: 你已点击【加1按键】次数:%d\n", mClickCount);
        Utils.printLogAndTextViewShowLifecycle(mTextView, TAG, string);

        outState.putInt(COUNT_KEY, mClickCount);
        outState.putString(LIFECYCLELOG_KEY, mTextView.getText().toString());
    }

Bundle 是键值对的集合,其中的键始终为字符串,您可以将简单数据(例如 Int 和 Boolean 值)放入 bundle 中。由于系统会将此 bundle 保留在内存中,因此最佳做法是让 bundle 中的数据量少一点。此 bundle 的大小也有限,但其大小因设备而异。如果您存储的数据过多,可能会面临应用崩溃并出现 TransactionTooLargeException 错误的风险。

通过putInt()/ putFloat() 和 putString()等方法将 要保存的数据放入 bundle 中。

4.2 使用 onCreate()或onRestoreInstanceState(Bundle) 恢复 bundle 数据

activity 状态可以在 onCreate(Bundle) 或 onRestoreInstanceState(Bundle) 中恢复(通过 onSaveInstanceState() 方法填充的 Bundle 将传递给这两种生命周期回调方法)。

请注意,onCreate() 会在每次调用时都获取 Bundle。当您的 activity 因进程关闭而重启时,您保存的 bundle 会传递给 onCreate()。如果您的 activity 重新启动了,那么 onCreate() 中的这个 Bundle 将是 null。因此,如果 bundle 不是 null,您就会知道自己是在基于一个先前已知的点重新创建该 activity。

注意:如果重新创建了 activity,onRestoreInstanceState() 回调会在 onStart() 之后随 bundle 一起调用。大多数情况下,您会将 activity 的状态恢复为 onCreate()。但是,由于 onRestoreInstanceState() 是在 onStart() 之后调用的,因此,如果您在系统调用 onCreate() 后需要恢复为某种状态,则可以使用 onRestoreInstanceState()

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

    mTextView = (TextView) findViewById(R.id.textView_main);

    if (savedInstanceState != null) {
        String lifecycleLog = savedInstanceState.getString(LIFECYCLELOG_KEY, " ");
        mTextView.setText(lifecycleLog);
    }
}

@Override
protected void onRestoreInstanceState(@NonNull Bundle savedInstanceState) {
    super.onRestoreInstanceState(savedInstanceState);
    Utils.printLogAndTextViewShowLifecycle(mTextView, TAG, "onRestoreInstanceState");

    if (savedInstanceState != null) {
        int count = savedInstanceState.getInt(COUNT_KEY, 0);
        mClickCount = count;
        String string = String.format("你已点击【加1按键】次数:%d\n", mClickCount);
        Utils.printLogAndTextViewShowLifecycle(mTextView, TAG, string);
        mTextViewCount.setText(string);
    }
}

 通过测试是否有 null,可以确定 bundle 中是否存在数据,或者 bundle 是否为 null,进而告知您应用是重新启动过,还是在关闭后重新创建过。此测试是从 bundle 恢复数据的常见模式。

使用的键与用于 putInt() 的键相同,为确保每次都使用相同的键,最佳做法是将这些键定义为常量。

4.3 测试代码

测试代码:百度网盘链接:百度网盘 请输入提取码 提取码:test   ActivityLifecycleTest目录

【savedatatest】 Module

编译并运行应用,点击【加1按键】,旋转设备。注意这一次,TextView中生命周期log打印按键次数不会被清掉,显示的是来自 bundle 的正确数据。

5. Activity的启动模式

某App先后打开两个Activity(活动),此时Activity(活动)栈的变动情况如下图所示。

依次结束已打开的两个Activity(活动),此时Activity(活动)栈的变动情况如下图所示。 

 5.1 在配置文件中指定启动模式

打开AndroidManifest.xml,给activity节点添加属性android:launchMode,activity节点配置内容示例如下: <activity android:name=".JumpFirstActivity" android:launchMode="standard" /> launchMode属性的取值说明见下表。

launchMode属性值

说明

standard

标准模式,无论何时启动哪个活动,都是重新创建该页面的实例并放入栈顶。如果不指定launchMode属性,则默认为标准模式

singleTop

启动新活动时,判断如果栈顶正好就是该活动的实例,则重用该实例;否则创建新的实例并放入栈顶,也就是按照standard模式处理

singleTask

启动新活动时,判断如果栈中存在该活动的实例,则重用该实例,并清除位于该实例上面的所有实例;否则按照standard模式处理

singleInstance

启动新活动时,将该活动的实例放入一个新栈中,原栈的实例列表保持不变

5.2 在代码里面设置启动标志

调用Intent对象的setFlags方法设置启动标志,示例如下:        

  1. Intent intent = new Intent(this, JumpSecondActivity.class);// 创建一个意图对象,准备跳到指定的活动页面
  2. intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);// 设置启动标志。Intent.FLAG_ACTIVITY_NEW_TASK表示创建新的任务栈
  3. startActivity(intent);  // 跳转到意图对象指定的活动页面

启动标志的取值说明如下:

Intent类中启动标志

说明

Intent.FLAG_ACTIVITY_NEW_TASK开辟一个新的任务栈,该值类似于android:launchMode="standard";不同之处在于,如果原来不存在Activity活动栈,则创建一个新栈
Intent.FLAG_ACTIVITY_SINGLE_TOP

当栈顶为待跳转的活动实例之时,则重用栈顶的实例,该值等同于

android:launchMode="singleTop"

Intent.FLAG_ACTIVITY_CLEAR_TOP当栈中存在待跳转的活动实例时,则重新创建一个新实例,并清除原实例上方的所有实例。该值与android:launchMode="singleTask"类似,但是singleTask采取onNewIntent方法启用原任务,而该flag采取先调用onDestroy再调用onCreate来创建新任务
Intent.FLAG_ACTIVITY_NO_HISTORY该flag与Intent.FLAG_ACTIVITY_NEW_TASK情况类似,但栈中不保存新启动的活动实例,这样下次无论以何种方式再启动实例,也要走standard模式的完整流程
Intent.FLAG_ACTIVITY_CLEAR_TASK跳转到新页面时,栈中的原有实例都被清空;注意改flag需要结合FLAG_ACTIVITY_NEW_TASK使用,既setFlag方法的参数为“Intent.FLAG_ACTIVITY_CLEAR_TASK | Intent.FLAG_ACTIVITY_NEW_TASK”

5.3 测试代码

测试代码:百度网盘链接:百度网盘 请输入提取码 提取码:test   ActivityLifecycleTest目录

【startactivitymodetest】 Module

     

 使用微信登录界面的三个界面简单举例

  1.  第一个页面可以跳转到第二个页面
  2.  第二个页面可以跳转到第三个页面 和 返回第一个页面
  3.  第三个页面返回只能直接返回到桌面

第一个页面可以跳转到第二个页面的代码

// 第一个页面跳转到第二个页面
    public void onClick(View v) {
        if (v.getId() == R.id.button_goto_secondary) {
            Utils.printLifecycle(TAG, "跳转到第二个页面");
            // 创建一个意图对象,准备跳到指定的活动页面
            Intent intent = new Intent(this, SecondaryActivity.class);
            // 当栈中存在待跳转的活动实例时,则重新创建该活动的实例,并清除原实例上方的所有实例
            intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); // 设置启动标志
            startActivity(intent);
        }
    }

 第二个页面跳转到第三个页面 和 返回第一个页面的代码

// 第二个页面跳转到第三个页面
// 第二个页面finish(),返回第一个页面
    public void onClick(View v) {
        if (v.getId() == R.id.button_goto_third) {
            Utils.printLifecycle(TAG, "跳转到第三个页面");
            // 创建一个意图对象,准备跳到指定的活动页面
            Intent intent = new Intent(this, ThirdActivity.class);
            // 设置启动标志:跳转到新页面时,栈中的原有实例都被清空,同时开辟新任务的活动栈
            intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK | Intent.FLAG_ACTIVITY_NEW_TASK); // 设置启动标志
            startActivity(intent);
        } else if (v.getId() == R.id.button_goto_main) {
            Utils.printLifecycle(TAG, "返回到上一页面");
            finish();
        }
    }

第三个页面返回只能直接返回到桌面

由于跳转到第三个页面的时候intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK | Intent.FLAG_ACTIVITY_NEW_TASK); ,所以第三个页面点击【返回到主桌面页】或者【导航返回键】,会直接退到桌面

    public void onClick(View v) {
        if (v.getId() == R.id.button_return_home) {
            Utils.printLifecycle(TAG, "返回到主桌面页");
            finish();
        }
    }

 

08-06 13:27:51.693 14281 14281 D lzl-test-MainActivity: [13:27:51:693]当前状态为竖屏
08-06 13:27:51.693 14281 14281 D lzl-test-MainActivity: [13:27:51:693]onCreate
08-06 13:27:51.698 14281 14281 D lzl-test-MainActivity: [13:27:51:698]onStart
08-06 13:27:51.700 14281 14281 D lzl-test-MainActivity: [13:27:51:700]onPostCreate
08-06 13:27:51.702 14281 14281 D lzl-test-MainActivity: [13:27:51:702]onResume
08-06 13:27:51.704 14281 14281 D lzl-test-MainActivity: [13:27:51:704]onPostResume
08-06 13:27:55.230 14281 14281 D lzl-test-MainActivity: [13:27:55:229]跳转到第二个页面
08-06 13:27:55.251 14281 14281 D lzl-test-MainActivity: [13:27:55:251]onPause
08-06 13:27:55.320 14281 14281 D lzl-test-SecondaryActivity: [13:27:55:320]当前状态为竖屏
08-06 13:27:55.320 14281 14281 D lzl-test-SecondaryActivity: [13:27:55:320]onCreate
08-06 13:27:55.324 14281 14281 D lzl-test-SecondaryActivity: [13:27:55:324]onStart
08-06 13:27:55.325 14281 14281 D lzl-test-SecondaryActivity: [13:27:55:325]onPostCreate
08-06 13:27:55.327 14281 14281 D lzl-test-SecondaryActivity: [13:27:55:327]onResume
08-06 13:27:55.328 14281 14281 D lzl-test-SecondaryActivity: [13:27:55:328]onPostResume
08-06 13:27:55.917 14281 14281 D lzl-test-MainActivity: [13:27:55:917]onStop
08-06 13:27:55.918 14281 14281 D lzl-test-MainActivity: [13:27:55:918]onSaveInstanceState
08-06 13:27:59.577 14281 14281 D lzl-test-SecondaryActivity: [13:27:59:575]跳转到第三个页面
08-06 13:27:59.605 14281 14281 D lzl-test-MainActivity: [13:27:59:604]onDestroy
08-06 13:27:59.612 14281 14281 D lzl-test-SecondaryActivity: [13:27:59:611]onPause
08-06 13:27:59.687 14281 14281 D lzl-test-ThirdActivity: [13:27:59:687]当前状态为竖屏
08-06 13:27:59.687 14281 14281 D lzl-test-ThirdActivity: [13:27:59:687]onCreate
08-06 13:27:59.692 14281 14281 D lzl-test-ThirdActivity: [13:27:59:691]onStart
08-06 13:27:59.693 14281 14281 D lzl-test-ThirdActivity: [13:27:59:693]onPostCreate
08-06 13:27:59.695 14281 14281 D lzl-test-ThirdActivity: [13:27:59:694]onResume
08-06 13:27:59.696 14281 14281 D lzl-test-ThirdActivity: [13:27:59:696]onPostResume
08-06 13:28:00.466 14281 14281 D lzl-test-SecondaryActivity: [13:28:00:465]onStop
08-06 13:28:00.470 14281 14281 D lzl-test-SecondaryActivity: [13:28:00:470]onDestroy
08-06 13:28:01.369 14281 14281 D lzl-test-ThirdActivity: [13:28:01:368]返回到主桌面页
08-06 13:28:01.392 14281 14281 D lzl-test-ThirdActivity: [13:28:01:391]onPause
08-06 13:28:02.036 14281 14281 D lzl-test-ThirdActivity: [13:28:02:034]onStop
08-06 13:28:02.046 14281 14281 D lzl-test-ThirdActivity: [13:28:02:045]onDestroy
 

三、配置变更

  • 当设备的状态发生了根本性改变,以至于系统解决改变的最简单方式就是销毁并重建 activity 时,就会发生配置变更。
  • 最常见的配置变更示例是用户将设备从纵向旋转为横屏模式,或者从横向转为纵向模式。当设备语言发生变化或插入硬件键盘时,也会发生配置变更。
  • 当发生配置变更时,Android 会调用所有 activity 生命周期的关闭回调。然后,Android 会从头开始重启相应 activity,同时运行所有生命周期启动回调。
  • 当 Android 因配置变更而关闭某个应用时,它会使用对 onCreate() 可用的状态 bundle 重启相应 activity。
  • 与进程关闭一样,系统会通过 onSaveInstanceState() 将应用的状态保存到 bundle 中。

四、测试程序

完整源码

百度网盘链接:百度网盘 请输入提取码 提取码:test

ActivityLifecycleTest目录

点此查看Android应用开发学习笔记的完整目录

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

liuzl_2010

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值