活动声明周期
先看一张官方的图
这个图显示的是一个Android应用从启动到销毁的整个生命周期。从左边启动,到最右边销毁。
安卓应用一般会有多个Activity,这些Activity会按照启动的先后顺序组成一个栈,最先启动的在栈底,最后启动的也就是当前显示的在栈顶。每次用户看到的就是栈顶的一个Activity。
当新创建一个Activity的时候,会被push到栈顶,退出之后会被弹出。
一个安卓应用会有六种不同的状态,不过其中 created
和 started
只是启动应用的一个瞬间状态,destroyed是被回收前的一个状态,不会持续很长时间。所以长时间的状态只有三种:
- resumed 正在运行中,可见并且可以交互,也就是处于栈顶
- paused 暂停,只有当一个新的活动盖在它之上,并且新的活动由于是半透明或者不全屏等原因导致它还能被看到的时候才会处于暂停状态。可见但是不可交互。并且不会执行任何代码了。
- stopped 停止了,不可见,不可交互,也就是完全被其他活动盖住了。这种情况下,活动的状态(数据等)还是被保留的,但是不会执行任何代码了。
配置Launcher
当用户点击主屏幕上的应用图标的时候,系统会调用制定的主活动的 onCreate
方法来启动应用,这个主活动 我们称之为 launcher activity
。在 AndroidManifest.xml
中这样配置主活动:
<activity android:name=".MainActivity" android:label="@string/app_name">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
如果上面的 MAIN
和 LAUNCHER
都没有指定,那么你的应用就不会出现在主屏上。
创建Activity
任何时候创建一个activity 实例的时候,系统都是通过调用 onCreate
放来来创建的。所以那些在活动的整个生命周期中只执行一次的一些逻辑应该写在 onCreate
方法中,比如一些初始化配置。比如下面这样:
TextView mTextView; // Member variable for text view in the layout
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Set the user interface layout for this Activity
// The layout file is defined in the project res/layout/main_activity.xml file
setContentView(R.layout.main_activity);
// Initialize member TextView so we can manipulate it later
mTextView = (TextView) findViewById(R.id.text_message);
// Make sure we're running on Honeycomb or higher to use ActionBar APIs
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
// For the main activity, make sure the app icon in the action bar
// does not behave as a button
ActionBar actionBar = getActionBar();
actionBar.setHomeButtonEnabled(false);
}
}
当 onCreate
执行完之后,系统会迅速顺序调用 onStart
和 onResume
方法。所以活动不会长时间停留在 created
或者 started
状态。
系统调用onCreate
方法会传入一个 savedInstanceState
参数,这个参数是用来在销毁之后重新创建活动用的。
销毁活动
一个活动的生命周期从 onCreate
开始,到 onDestroy
结束。一般情况下都不需要实现 onDestroy
方法,因为系统会自动销毁 class 引用。大部分的清理工作应该放在 onPaused
和 onStoped
方法中。不过,如果你的活动中包含一些后台线程或者其他可能导致内存泄露的资源,那么你需要在 onDestroy
方法中销毁他们。
正常情况下,系统都会先调用 onPaused
和 onStop
方法,然后再调用 onDestroy
方法。但是有一种例外情况,就是你在 onCreate
中通过调用 onFinish
方法直接结束活动,这个时候因为活动仅仅处在 created
状态,所以系统会直接调用 onDestroy
方法来销毁,而不会调用 onPaused
和 onStop
方法。
暂停和恢复活动
当一个活动被另一个活动部分遮盖的时候,比如启动了一个新的半透明的活动,那么被遮住的活动会进入 paused
状态。如果完全被遮住,则进入 stop
状态。
当一个活动进入 paused
状态的时候,系统会调用 onPaused
方法,你可以在这个方法中停止一些在暂停状态不需要做的事(比如播放视频),或者是保存一些必要的数据以免应用退出之后无法恢复状态。
如果一个活动处在 paused
状态,当用户再次返回这个活动的时候,会调用 onResume
方法。
当 onPause
方法调用的时候,可能意味着用户暂时离开了这个活动,也可能是用户即将退出应用,当然更多情况下还是意味着用户离开了这个活动,并且这个活动将很快进入 stoped
状态。一般情况下你在 onPaused
方法中需要做这些事:
- 停止一些正在进行的消耗CPU的任务,比如动画和视频
- 保存一些没提交的修改。注意,请确认是是用户需要保存的,不是任何修改都需要在这里保存。
- 释放系统资源,比如GPS等
例如当前活动在使用 camera ,那么在 onPause
方法中你应该释放相机资源:
@Override
public void onPause() {
super.onPause(); // Always call the superclass method first
// Release the Camera because we don't need it when paused
// and other activities might need to use it.
if (mCamera != null) {
mCamera.release();
mCamera = null;
}
}
注意,一般情况下你不应该在 onPause
方法中持久化保存用户的修改,除非你确定用户需要自动保存(比如邮件草稿)。但是,onPause
方法中应该避免任何消耗CPU的任务,比如写数据库,因为这样会导致切换活动变卡。
当活动从暂停状态恢复运行的时候,系统会调用 onResume
方法。每次活动从后台变到前台的时候都会执行这个方法,所以你应该在这个方法中初始化你在 onPause
中释放的那些资源,以及一些每次恢复活动都要进行的初始化操作。
@Override
public void onResume() {
super.onResume(); // Always call the superclass method first
// Get the Camera instance as the activity achieves full user focus
if (mCamera == null) {
initializeCamera(); // Local method to handle camera init
}
}
上例中是重新初始化在 onPause
中释放的相机。
停止和恢复活动
注意和上面的区别,这里是停止而不是暂停。
这些情况下会导致活动停止:
- 用户切换到了其他应用。那么你的应用中的前台活动就会进入停止状态。当用户返回的时候就会
restart
- 创建了一个新的活动,那么当前的活动就会进入停止状态。
- 用户接听电话。
当进入暂停状态的时候,表示当前活动已经完全不可见。
一个活动进入停止状态的时候会依次调用 onPause
和 onStop
方法。恢复运行的时候会依次调用 onStart
和 onResume
方法。
因为在停止状态的时候,系统还是保留了当前活动的实例(只有销毁才会从内存中删除),所以很多时候你并不需要实现 onStart
和 onStop
方法,你只需要实现 onPause
和 onResume
即可。
当活动被调用 onStop
的方法的时候,已经是完全不可见状态,应该释放所有不需要的系统资源。如果一个活动处在 stopped
状态,那么当系统内存不足的时候,极端情况下,系统甚至不调用 onDestroy
方法而直接杀掉进程,所以一定要在 onStop
方法中释放系统资源。
前面说过不应该在 onPause
方法中执行耗时的任务,那么你应该在 onStop
中执行这些任务,比如写数据库。
当活动处在 stopped
状态的时候,活动的实力依然存在内存中。你不需要重新初始化那些在 onCreate
到 onResume
之间初始化过的组件。系统也会自动保存所有的 View状态,比如用户在文本框中输入的内容依然会保留。
销毁和重新创建活动
当用户旋转屏幕的时候,系统会销毁并重新创建前台活动。
默认情况下,系统在销毁活动的时候会使用 Bundle 来保存活动中View的状态,并且在重新启动的时候自动恢复。但是如果你有除了 View 以外的其他数据需要保存的时候,你就需要自己写代码了。
注意Android是通过 id 来保存活动信息的,所以请确保你的每一个活动都有一个唯一的id,通过 android:id
来设置。
如果你需要保存额外数据,那么应该重写 onSaveInstanceState()
方法。系统在销毁活动的时候会自动调用这个方法,并且传入一个 Bundle 对象。当系统重新创建活动的时候,会把同样的 Bundle 对象作为参数传入,注意这个时候在 onCreate
和 onRestoreInstanceState()
方法中都会传入。
当系统销毁活动的时候,这样保存数据:
static final String STATE_SCORE = "playerScore";
static final String STATE_LEVEL = "playerLevel";
@Override
public void onSaveInstanceState(Bundle savedInstanceState) {
// Save the user's current game state
savedInstanceState.putInt(STATE_SCORE, mCurrentScore);
savedInstanceState.putInt(STATE_LEVEL, mCurrentLevel);
// Always call the superclass so it can save the view hierarchy state
super.onSaveInstanceState(savedInstanceState);
}
当系统重新创建活动的时候,会给 onCreate
传入上面的 Bundle 对象。但是因为第一次创建也是调用 onCreate
方法,所以在 onCreate
方法中使用 bundle的时候请先检查是否为空:
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); // Always call the superclass first
// Check whether we're recreating a previously destroyed instance
if (savedInstanceState != null) {
// Restore value of members from saved state
mCurrentScore = savedInstanceState.getInt(STATE_SCORE);
mCurrentLevel = savedInstanceState.getInt(STATE_LEVEL);
} else {
// Probably initialize members with default values for a new instance
}
...
}
另外系统还会调用 onRestoreInstanceState()
方法,并且只有 bundle 不为空的时候才会调用,因此你可以重写这个方法而不用检查 bundle 是否为空:
public void onRestoreInstanceState(Bundle savedInstanceState) {
// Always call the superclass so it can restore the view hierarchy
super.onRestoreInstanceState(savedInstanceState);
// Restore state members from saved instance
mCurrentScore = savedInstanceState.getInt(STATE_SCORE);
mCurrentLevel = savedInstanceState.getInt(STATE_LEVEL);
}