启动一个Activity
不像其他编程规范,app启动是从main()方法开始的。而安卓系统是通过调用与activity生命周期相关的回调方法来初始化和启动activity的。Activity的启动和销毁都是与一些回调方法相关联的。
本课程会浏览一下生命周期中最重要的方法,并指导你初次创建一个activity时如何处理生命周期的回调方法。
理解生命周期回调方法
在activity生存期间,系统按顺序调用一系列核心的生命周期回调方法,这种调用顺序形如梯形金字塔(如下图)。也就是说,activity生命周期的每一个阶段都对应着金字塔上的每一个台阶。当系统创建一个新的activity实例时,每一个回调方法一步一步向上地改变activity的状态。金字塔的最高点就是表明activity在前台运行,此时用户可以与activity交互。
Figure 1. activity生命周期的简单示意图,采用梯形金字塔的形式表示.此图显示了如何经过哪些回调方法可以从下到顶将activity状态转换至运行(Resumed)状态,也有一些回调方法是向上走的. Activity也可以从暂停(paused)状态和停止(stopped)状态转换至运行状态。.
当用户准备离开activity时,系统也会沿着金字塔向下的方向调用回调方法来迁移状态,并销毁activity。在某些情况下,activity沿着金字塔向下走一部分然后等待(例如用户跳转到别的app),activity可以从这个等待点再向上返回到塔顶(如果用户返回到此activity),然后在用户离开的地方继续运行。
取决于你的activity的复杂度,你也许并不需要实现所有的回调方法。然而,重要的是你应该理解每一个回调方法,并且实现那些必须的,保证activity的行为符合用户的预期。通过实现你的activity的生命周期方法来保证实现用户的预期行为,可以从以下几方面入手:
当用户正在使用你的app时,此时用户收到一个来电或者跳转到别的app时,请保证你的app不会崩溃。
当用户不再主动使用某些系统资源时,请不要浪费它。
当用户离开你的app,过一会儿返回的时候,用户的操作与输入不应该丢失。
当屏幕方向在水平与垂直间变化时,请保证应用不会崩溃或者丢失用户操作与输入。
在接下来的课程中你将学到,有哪些条件会引起activity发生如图1所示的状态变化。无论如何,只有3种状态是稳定的。也就是说,一个activity在某个时间段内只能处于这3种状态中的一种情况下。
运行(Resumed)
在这个状态下,activity处于前台,用户可与之交互。(当然有时这种状态又称 “Running”)。
暂停(Paused)
在这个状态下,此activity被另一个activity部分遮挡----这个“另一个”activity在前台处于半透明状态或者没有完全占满整个屏幕。这个暂停的activity不能获得用户输入并且不能 执行任何代码。
停止(Stopped)
在此状态下,此activity完全隐藏,对用户不可见;它被认为处于后台。当处于停止状态时,这个activity实例和成员变量的信息都是被保存下来的,但是它不能执行任何代 码。
其他状态(创建(Created)和启动(Started))是不稳定的,系统会马上调用下一个回调方法进入下一个稳定状态。也就是,系统调用完onCreate()之后,会很快调用 onStart(),然后立即调用 onResume()。
这就是基本的activity生命周期。现在你将学习了解一些特别的生命周期行为。
指定你的app的入口Activity
当用户在主屏上点击你的app图标时,系统会在你的配置文件中找到声明为”Launcher”(或”main”)的activity也即入口activity,然后调用这个activity的onCreate()方法。这个activity就是你的app的整个UI界面的主入口。
你可以在AndroidManifest.xml中定义哪个activity作为入口activity,这个配置文件位于工程的根目录下。
在配置文件中定义的入口主Activity必须添加一个<intent-filter>声明,声明中需要包含MAIN动作和LAUNCHER域。例如:
<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>
如果在配置文件中没有为任何一个Activity声明MAIN动作和LAUNCHER域,那么你的应用图标就不会在主屏幕的应用列表中显示。
创建一个新实例
大多数应用都会包含若干不同的Activity来为用户执行不同的动作。无论一个activity是被用户点击应用图标启动创建的,还是因为响应用户某个操作而创建的,系统总是通过调用它的onCreate()方法来创建一个activity实例。
你必须实现onCreate()方法,在方法里你可以做一些在整个activity生命期只需要做一次的初始化操作。例如,你应该在onCreate()方法里定义用户界面,或者可能实例化一些类范围内的变量。
例如,下面的onCreate()例子代码显示了为activity所做的一些基本操作,例如声明用户界面(定义在一个XML布局文件里),定义成员变量,配置UI。
TextView mTextView; // 布局中的文本组件成员变量
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// 设置Activity的UI布局
// 这个布局文件在res/layout/main_activity.xml
setContentView(R.layout.main_activity);
// 初始化成员变量TextView,这样以后可以操作它
mTextView = (TextView) findViewById(R.id.text_message);
// 确保我们运行了足够高的版本,才能使用动作栏相关的API if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
// 确保此activity的动作栏应用图标不可以被当作动作按钮点击
ActionBar actionBar = getActionBar();
actionBar.setHomeButtonEnabled(false);
}
}
一旦onCreate()执行完,系统会马上按顺序调用onStart()和onResume()。你的activity永远不会停留在创建(Created)或者启动(Started)状态。从技术上讲,当onStart()调用后,activity就已经变成了可见状态,但是onResume()会被马上调用,然后activity停留在运行状态,直到发生一些事件来改变此状态,例如收到一个用户来电,或者用户跳转到别的activity,又或者屏幕灭了。
在接下来的一些课程里,你将看到其他启动方法onStart()和onResume(),当把activity从暂停或者停止状态恢复到运行状态时,这两个方法在整个生存期内是多么有用的。
注意:onCreate()方法有一个参数savedInstanceState,这个我们在后面的课程再讲。
Figure 2. 此图主要描述了当创建一个新的activity实例时,系统是如何按顺序调用 activity生命周期中最主要的3个回调方法: onCreate(), onStart(), and onResume(). 当按顺序调用完成后,activity就处于运行状态,用户可以与之交互直到跳转到别的activity.
销毁一个Activity
Activity的第一个生命周期回调方法是onCreate(),最后一个是onDestroy()。系统调用你的这个activity回调方法就等于是告诉你,这个activity实例将从系统内存中删除。
大多数应用不需要实现这个方法,因为局部类引用会在activity里被销毁,并且你的activity需要在onPause()和onStop()里执行大部分清理工作。但是,如果你的activity里包含了一些在onCreate()里创建的后台线程,或者存在一些可能由于不恰当地关闭而造成内存泄漏的长期运行的资源,你都应该在onDestroy()里杀掉它们。
@Override
public void onDestroy() {
super.onDestroy(); // 总是调用基类方法
// 停止在onCreate()里启动的方法跟踪
android.os.Debug.stopMethodTracing();
}
注意:系统在任何情况下,总是在调用了onPause()和onStop()方法后,调用onDestroy(),但是有一种情况除外:当你在onCreate()方法里调用finish()方法时。在某些情况下,例如,你的activity作为一个临时决策用来启动另一个activity,你可能会在onCreate()方法里调用finish()去销毁这个activity。在这种情况下,系统会直接调用 onDestroy()方法而不会调用其他生命周期方法。