Android Activity之生命周期

来源:互联网 发布:linux操作系统原理 编辑:程序博客网 时间:2024/06/05 09:24

前言

本编文章参考了《Android开发艺术探索》一书。
我们知道,Android的四大组件分别为Activity,Service,Broadcast Receiver,Content Provider。Activity作为四大组件之首,是使用最为频繁的一个组件,所以了解Activity的生命周期尤为重要。在Activity不同的生命周期对应做不同的工作,用户的操作会引起Activity哪些生命周期发生变化,会回调哪些方法是我们必须掌握的。

生命周期方法

  • onCreate():这个方法表示Activity正在被创建。一般情况下,我们在onCreate方法中进行初始化操作,比如:setContentView加载布局资源,初始化Activity所需要的数据,View等。
  • onRestart():这个方法表示Activity正在重新启动。比如:点击Home按键后,又切换到这个Activity,或者点击back按键回到这个Activity时会调用onRestart方法。如果是第一次启动这个Activity,该方法是不会被调用的。
  • onStart():这个方法表示Activity正在被启动。当Activity处于可见之前调用该方法。
  • onResume():此时Activity已经可见了,并且出现在前台,此时Activity已经有焦点了。这个方法里边我们可以做一些刷新UI状态的工作,但是不能太耗时,否则会引起Activity启动卡顿的现象。
  • onPause():这个方法表示Activity正在停止,此时Activity失去焦点了。此时我们可以做一些数据存储、动画停止等工作,但是不能太耗时,否则会影响新Activity的启动。
  • onStop():这个方法表示Activity即将停止,此时Activity并没有销毁,只是切换到后台了。可以做一些轻量级的垃圾回收,但是不能太耗时。
  • onDestroy():这个方法表示Activity即将被销毁。这是Activity生命周期中的最后一个回调,我们需要将Activity工作过程中占有的资源和内存进行释放,否则会引起内存泄漏,甚至可能会因为内存泄漏而导致OOM。

生命周期回调流程

那么正常情况下,当我们操作Activity时,他们的回调顺序又是怎样的呢?配合上图来说明一下。
针对Activity1,Activity2:
  1. 当Activity1第一次启动时,Activity1回调顺序为:onCreate → onStart → onResume。进行完这一系列回调后,Activity已经呈现在我们眼前,我们可以进行点击,滑动,拖拽等动作。
  2. 当点击back按键时,Activity1回调顺序为:onPause → onStop → onDestroy。
  3. 当用户在Activity1启动Activity2或者用户在Activity1点击了Home按键时,Activity1的回调顺序为:onPause → onStop。并没有调用onDestroy方法。Activity1和Activity2两个生命周期的回调顺序为:Activity1 onPause → Activity2 onCreate → Activity2 onStart → Activity2 onResume → Activity1 onStop。
  4. 当用户从Activity2重新回到Activity1时,Activity1的回调顺序为:onRestart → onStart → onResume。Activity1和Activity2两个生命周期的回调顺序为:Activity2 onPause → Activity1 onRestart → Activity1 onStart → Activity1 onResume → Activity2 onStop → Activity2 onDestroy。
从3、4已经可以看出,在onResume和onPause中不要做耗时操作的原因,因为它会影响别的Activity的启动与销毁,造成不同Activity之间切换出现卡顿的现象。
从整个生命周期来说,onCreate和onDestroy是配对的,分别表示Activity的创建和销毁,并且只可能调用一次。onStart和onStop是配对的,分别表示Activity是否可见。onResume和onPause适配对的,分别代表Activity是否有焦点。

特殊情况下,Activity生命周期

如果你认为Activity的生命只有这么简单,那就太天真了。Activity除了受用户操作所导致的正常的生命周期方法调度,还有一些异常情况,比如系统内存不足,系统配置发生改变,Activity就可能被系统直接kill,导致生命周期的回调也会出现不同的改变。

  1. 正常情况下,当用户在Activity1启动Activity2或者用户在Activity1点击了Home按键时,Activity1的回调顺序为:onPause → onStop。但是这里有一种特殊情况,当Activity2采用了透明主题或者未全部遮挡Activity1的dialog样式的Activity,此时Activity1的回调顺序只有onPause,是不会回调onStop的。因为Activity对于我们仍然是可见的,并没有切换到后台。
  2. 当系统配置发生改变时,系统会会被销毁并重新创建。此时Activity的生命周期为onPause → onSaveInstanceState → onStop → onDestroy → onCreate → onStart → onRestoreInstanceState → onResume。生命周期中多了onSaveInstanceState,onRestoreInstanceState两个方法。onSaveInstanceState是用于保存数据的,onRestoreInstanceState则是用来取出onSaveInstanceState保存的数据,通过这两个方法来防止Activity重建后无法恢复数据的问题。而且我们发现,当Activity被异常终止又恢复时,系统已经帮我们做了一些恢复工作,这是因为每个View都有onSaveInstanceState,onRestoreInstanceState这两个方法,当Activity终止时,会委托Window去保存数据,Window在委托顶层容器ViewGroup,ViewGroup通知子元素,这样层层传递,从而帮助我们保存和恢复数据。
  3. 当资源内存不足时,系统会杀死低优先级的Activity。并在后续通过onSaveInstanceState,onRestoreInstanceState来存储数据。其数据存储和系统配置发生改变时情况一样。
Activity的优先级从高到低,可以分为3种:
  • 前台Activity:获取焦点的Activity,正在和用户交互。优先级最高。
  • 可见但没有焦点的Activity:比如被部分遮挡的Activity,对于用户是可见的,但是无法获取焦点。
  • 后台Activity:调用了onStop后的Activity。优先级最低,在系统内存不足时,会被回收。    

        4. Activity的启动模式LaunchMode也会影响Activity的生命周期,这个会在下一遍Activity启动模式中详说。

当系统配置改变后,如何防止Activity重新创建

上边提到,当系统配置发生改变后,Activity会重新创建。如何防止Activity重建呢?可以在AndroidManifest.xml给Activity指定configChanges属性。
<activity            android:name="com.example.phone.MainActivity"            android:configChanges="keyboardHidden|navigation|orientation|locale|screenLayout|screenSize"            android:launchMode="singleTask"            android:theme="@style/no_title" />
这样,当keyboardHidden,navigation,orientation,locale,screenLayout,screenSize发生改变时,Activity就不会被重新创建了。多个值之间使用“|”连接起来。
系统配置中的项目含义如下表:
当我们指定configChanges属性后,Activity就不会重新创建了,而是调用了onConfigurationChanged方法。
例如:
android:configChanges="orientation|screenSize"
如果你编译时的minSdkVersion和targetSdkVersion高于13时,screenSize必须加上,否则Activity还是会重新创建。
    @Override    public void onConfigurationChanged(Configuration newConfig) {        super.onConfigurationChanged(newConfig);        if (newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE) {            Toast.makeText(this, "横屏", Toast.LENGTH_SHORT).show();            onLandScape();        } else if (newConfig.orientation == Configuration.ORIENTATION_PORTRAIT) {            Toast.makeText(this, "竖屏", Toast.LENGTH_SHORT).show();            onPortrait();        }    }
3 0
原创粉丝点击