Activity生命周期
在系统中的Activity被一个Activity栈所管理。当一个新的Activity启动时,将被放置到栈顶,成为运行中的Activity,前一个Activity保留在栈中,不再放到前台,直到新的Activity退出为止。
Activity有四种本质区别的状态:
- 在屏幕的前台(Activity栈顶),叫做活动状态或者运行状态(active or running)
- 如果一个Activity失去焦点,但是依然可见(一个新的非全屏的Activity 或者一个透明的Activity 被放置在栈顶),叫做暂停状态(Paused)。一个暂停状态的Activity依然保持活力(保持所有的状态,成员信息,和窗口管理器保持连接),但是在系统内存极端低下的时候将被杀掉。
- 如果一个Activity被另外的Activity完全覆盖掉,叫做停止状态(Stopped)。它依然保持所有状态和成员信息,但是它不再可见,所以它的窗口被隐藏,当系统内存需要被用在其他地方的时候,Stopped的Activity将被杀掉。
- 如果一个Activity是Paused或者Stopped状态,系统可以将该Activity从内存中删除,Android系统采用两种方式进行删除,要么要求该Activity结束,要么直接杀掉它的进程。当该Activity再次显示给用户时,它必须重新开始和重置前面的状态。
下面的图显示了Activity的重要状态转换,矩形框表明Activity在状态转换之间的回调接口,开发人员可以重载实现以便执行相关代码,带有颜色的椭圆形表明Activity所处的状态。
在上图中,Activity有三个关键的循环:
- 整个的生命周期,从onCreate(Bundle)开始到onDestroy()结束。Activity在onCreate()设置所有的“全局”状态,在onDestory()释放所有的资源。例如:某个Activity有一个在后台运行的线程,用于从网络下载数据,则该Activity可以在onCreate()中创建线程,在onDestory()中停止线程。
- 可见的生命周期,从onStart()开始到onStop()结束。在这段时间,可以看到Activity在屏幕上,尽管有可能不在前台,不能和用户交互。在这两个接口之间,需要保持显示给用户的UI数据和资源等,例如:可以在onStart中注册一个IntentReceiver来监听数据变化导致UI的变动,当不再需要显示时候,可以在onStop()中注销它。onStart(),onStop()都可以被多次调用,因为Activity随时可以在可见和隐藏之间转换。
- 前台的生命周期,从onResume()开始到onPause()结束。在这段时间里,该Activity处于所有 Activity的最前面,和用户进行交互。Activity可以经常性地在resumed和paused状态之间切换,例如:当设备准备休眠时,当一个 Activity处理结果被分发时,当一个新的Intent被分发时。所以在这些接口方法中的代码应该属于非常轻量级的。
Android 状态
下面的 Activity 方法定义了 activity 完整的生命周期。他们全都是 hook 方法,你可以重载这些方法从而使 activity 在状态改变时执行你所期望的操作。所有activity 都应该实现自己的 onCreate(Bundle)方法来进行初始化设置;大部分还应该实现 onPause()方法提交数据的修改并且准备终止与用户的交互。尽管我们计划在系统中添加更多的工具来管理应用,现在大多 activity 仍需要实现 onFreeze()并且在 onCreate(Bundle)中执行对应的状态恢复。其他的方法可以在需要时进行实现,当实现这些方法的时候需要注意的是一定要调用父类中的对应方法
测试生命周期的小例子:
package com.android.com;
import android.app.Activity;
import android.util.Log;
public class androidLifeTest extends Activity {
/** Called when the activity is first created. */
private static final String TAG="AndroidLife";
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
Log.i(TAG, "onCreate");
}
protected void onStart(){
super.onStart();
Log.i(TAG, "onStart");
}
protected void onResume(){
super.onResume();
Log.i(TAG, "onResume");
}
protected void onStop(){
super.onStop();
Log.i(TAG, "onStop");
}
protected void onPause(){
super.onPause();
Log.i(TAG, "onPause");
}
protected void onDestory(){
super.onDestroy();
Log.i(TAG, "onDestory");
}
protected void onRestart(){
super.onRestart();
Log.i(TAG, "onRestart");
}
protected void onPostCreate(Bundle savedInstanceState){
super.onPostCreate(savedInstanceState);
Log.i(TAG, "onPostCreate");
}
protected void onPostResume(){
super.onPostResume();
Log.i(TAG, "onPostResume");
}
public void onContentChanged(){
super.onCreateDescription();
Log.e(TAG, "============> onContentChanged[1]");
}
}
首先我们看到的最上面的画面是最重要的,并且也是焦点所在。此时可以通过函数onWindowFocusChanged()来判度。此时activity在栈顶。
在onCreate()-->onContentChanged()-->onStart的过程中还要涉及到一些内部方法的调用,我们来看一下:
onWindowAttributesChanged(WindowManager.LayoutParams params) 当当前窗口属性更改时被调用。
public void onContentChanged() 当屏幕的目录视图改变(因调用 Window.setContentView 或Window.addContentView))时此钩子被调用。
protected void onApplyThemeResource(Resources.Theme theme, int resid, boolean first)
由setTheme(int) 和 getTheme()调用于应用一个主题资源到当前Theme对象。 可以覆盖更改默认的(简单)的行为。这种方法不会被称为多线程。
我们分情况讨论一下:
(1)只有一个activity的时候:
流程如下: onCreate()-->onStart()-->onResume() 现在就是用户看到的界面如果,
按下back键,activity的生命周期将会结束。流程:onPause()-->onStop()-->onDestroy();
如果按下Home键,首先会保存当前activity的实例状态。OnSaveInstanceState(), 然后转入后台处理,onPause(),最后onStop();当前activity界面状态不可见。
(2)如果有多个activity,并且在启动第二个activity后,调用finish()函数。当从第一个activity跳转到第二个activity的时候,当第二个
activity正要显示出来的时候,第一个activity会执行onPause()方法,转入后台。同时第二个activity执行onCreate()-->onStart()-->onResume().显示出界面。
第一个activity继续执行onStop()-->onDestory()方法。第一个activity生命周期结束。同样,多个activity在彼此调用后,都是这样的流程。
(3)如果有多个activity,并且在启动第二个activity后,没有调用finish()函数。
流程如下: onCreate()-->onStart()-->onResume() 现在就是用户看到的界面。如果,按下back键,activity的生命周期将会结束。流程:onPause()-->onStop()-->onDestroy();
如果按下Home键,首先会保存当前activity的实例状态。OnSaveInstanceState(), 然后转入后台处理,onPause(),最后onStop()。
如果继续跳转activity,并利用back键返回前一个activity,流程如下:onRestart()-->onStart()-->onResume()-->onStop()-->onDestory().前一个activity生命周期结束。
怎样保存Activity的状态:
当一个 Activity 被 kill 之前,它可以调用 onSaveInstanceState()来保存当前 activity的状态信息。用来保存状态信息的 Bundle 会同时传给两个 method,即
onRestoreInstanceState() and onCreate().
public void onSaveInstanceState(Bundle outState) {
outState.putBoolean("Boolean", true);
outState.putDouble("Double", 1.9);
outState.putInt("Int", 1);
outState.putString("String", "Welcome back to Android");
// etc.
这样,在activity转换的时候我们可以把我们要保存的数据值通过Bundle来保存到onCreate()中,等待下一次的初始化。同样在onRestoreInstanceState()中接受到要保存的信息:
public void onRestoreInstanceState(Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState);
boolean myBoolean = savedInstanceState.getBoolean("Boolean");
double myDouble = savedInstanceState.getDouble("Double");
int myInt = savedInstanceState.getInt("Int");
String myString = savedInstanceState.getString("String");
}
多个 activity 之间传输数据的主要方法
(1)bundle+Intent
举例如下:
我们可以在比如按钮事件中加入以下代码来实现 activity 的跳转和数据传入
Intent intent = new Intent();
intent.setClass(A.this,B.class);
Bundle bundle = new Bundle();
bundle.putDouble("height",height);
bundle.putString("sex",sex);
intent.putExtras(bundle);
startActivity(intent);
同时在 B 的 activity 中,我们必须要接受数据,并本地化这些数据。
Bundle bunde = this.getIntent().getExtras();
String sex = bunde.getString("sex");
double height = bunde.getDouble("height");
现在 activity 之间的数据传递已经完成,我们可以在 B 中使用 A 传来的这些数据。如果想从 B 中返回要得到的数据可以使用 startActivityForResult()方法。
好,我们现在来看一下是怎样传输的,其中都包含了什么?首先我们定义了 Bundle 的实例,作为存储数据的对象,利用 put 来把要传输的数据放入 bundle 这个实例中,我们来看一下效果
Bundle[{sex=M, height=172.0}]
这就是在传输过程中 Bundle 实例中的内容,利用 get 方法来获取到其中的内容。
注意类型的匹配。