基本类,必须熟知。用户要使用它,就必须从Activity派生出自己的Activity子类。
可以认为它是和用户进行交互的最小的独立的任务单位,所以称之为“活动”。一个活动在和用户进行交互、完成工作的过程中,可以有多个Java线程辅助其工作。
几乎所有的Activity都要和用户进行交互,所以它要创建一个属于自己的UI界面,而且经常是全屏的。当然也可做成浮动窗口的形式,或者嵌入别的Activity中,结成一个组合。
必须要实现的两个方法:
- onCreate(Bundle)
把Activity的初始化代码放在此处。经常使用setContentView(int)和findViewById(int)来设置UI元素。
- onPause()
当用户暂时不需要和该Activity交互而离开的时候,系统会回调此方法。此处要保存用户数据!(经常使用ContentProvider)
若想使用Context.startActivity()启动某个Activity,则该Activity必须在AndroidManifest.xml文件中配置自己的<activity>属性。
Activity是一个Android应用程序最重要的组成部分。它影响了应用程序的生存周期、组成方式、启动模式。关于这方面,请看《应用程序基础》和《任务与活动栈》。
Android系统中的所有“活动”是以“活动栈”(activity stack)的形式组织管理的。一个Activity被创建,则被放到栈顶,变成“活动”状态。其它的活动则被压到它的下面。等到什么时候,该活动退出了,则下面的活动又顶上来。
Activity有四种状态:
1> 如果显示在屏幕上,且接收用户输入,则是处于栈顶,是“活动”(active, running)的。
2> 如果显示在屏幕上,但不能接收用户的输入,失去了焦点,则说明有其它的透明的、或非全屏的Activity存在于其上。此时其为“暂停”状态(paused)。处于暂停的Activity,其内部所有信息都仍然存在,而且和“窗口管理器”仍然连接着。但有可能在内存极为紧缺时,被系统强行杀掉。
3> 如果一个Activity完全被其它的Activity挡住了,已经不可见时,是处于“停止”状态(stoped)。它仍然保有内部状态,但其窗口已经隐藏,且常常在内存吃紧时被系统强行杀掉。
4> 当一个Activity暂停或停止时,会被系统喝令终止(finish),或者强行杀掉。当用户重新启动它,它又重获焦点的时候,相当于重新启动,需要自己恢复状态。
这涉及到七个回调函数:
1> onCreate() 从零开始启动
2> onCreate() -> onStart() -> onResume() 处于可见状态,可以和用户交互了
3> 别的应用跑出来,覆盖到它上面,-> onPause()
4> 它完全看不见了,-> onStop()
5> 处于“暂停”状态时,用户重新选择回它,-> onResume() 重又获得焦点
6> 处于“停止”状态时,用户重新选择回它,-> onRestart() -> onStart() -> onResume()...
7> 处于“停止”状态时,长时间不理它,内存少,-> onDestroy()
8> 处于“暂停”或“停止”状态时,内存吃紧,被系统杀掉。此时无回调!
又有三个关键点:
1> 完整的生命周期
以onCreate()为始,以onDestroy()为终。所以一个Activity要在onCreate()里做初始化工作,在onDestroy()里释放资源。
2> 可见的生命周期
以onStart()为始,以onStop()为终。此期间,用户可见该Activity在屏幕上(有可能被挡在后台,没和用户交互)。在这两个方法中维护那些要显示到UI上的资源。
例如,在onStart()里注册(register)一个BroadcastReceiver来监视影响UI的事情;在onStop()里销掉注册(unregister),因为用户已看不到UI了。
onStart()和onStop()可在整个活动的生命周期内被回调多次。
3> 前台的生命周期
以onResume()为始,以onPause()为终。处于和用户交互的状态。当然,在活动的生命周期内会被回调多次。
- onCreate(Bundle)
第一次创建时调用。一般地静态初始化工作在此完成。有时带参数,保存着上一次被销毁时所冻结的状态。
onStart()紧跟此方法被回调。
- onRetart()
从停止状态返回到活动状态时被回调。
onStart()紧跟此方法被回调。
- onStart()
处于用户可见的状态时被回调。
若获得用户焦点,则后跟一个onResume();若变为不可见,后跟一个onStop()。
- onResume()
获得用户焦点时回调。后跟onPause()。
- onPause()
当系统退回到以前的Activity时回调。
一般在此外保存用户数据,停止动画及其它耗CPU的工作。因为只有此方法退出时才会真正进入下一个Activity。
- onStop()
用户不可见时被回调。一个新活动被创建,或以前的某活动重获焦点挡在它前面。
- onDestroy()
可在活动被销毁前释放一次资源。有两种情况会调用此方法:1> 有人调用了finish()方法 2> 系统内存吃紧。
可用isFinishing()方法区分二者。
不能靠此方法保存数据!应在onPause()或onSaveInstanceState(Bundle)里执行数据保存操作。onDestroy()只适合释放线程一类的资源,以保证在活动被杀掉后不会遗留东西给正在运行的应用程序。
有时系统会强行杀掉活动而不回调此方法。
- onLowMemory()
系统在内存吃紧时回调此方法,但何时调用没有准确定义。一般而言,系统会先关掉所有的后台进程,最后杀掉作为进程总控和前台UI的主进程。此函数会在主进程被杀前回调。
应用程序若想积极响应内存低的警报,可实现此方法,主动释放资源。系统会在此方法后,自动调用gc回收。
- onRestoreInstanceState (Bundle)
当活动从以前保存的状态重新初始化时,此方法在onStart()以后回调。
大多数应用会在onCreate(Bundle)中恢复状态,但有时某些工作在此处做比较方便。比如直接调用缺省实现,恢复在onSaveInstanceState(Bundle)中被冻结的View的状态。
- onSaveInstanceState (Bundle)
在活动被杀掉前,保存实例里的状态。保存的东西用在onCreate()或onRestoreInstanceState()中。
比如,B活动被创建,A活动被压入栈。那么A有可能会被杀掉。在被杀前可把UI相关的状态存储起来,在以后用户回到A的时候重新恢复出来。
不要和onPause()和onStop()混淆。onPause()被回调的机率大多了;onStop()则是在销毁前被回调。
例如,用户从B回到A,此时不会调用B的onSaveInstanceState(),只调用onPause()和onStop()。因为B不会被恢复。
再例如,B被创建,A被压栈。若在B的生命周期内A没有被杀掉,则不会调用A的onSaveInstanceState(),只调用onPause()。
调用在onStop()之前。和onPause()的前后则无关系,可前可后。
若设备发生“配置改变”事件(比如更换了语言、输入设备,改变了朝向等等),所有的UI要都重新从配置文件中读取资源、布局、文本等数据,然后重新建立UI,呈现给用户。
这将导致Activity发生一系列的状态变化:onPause() -> onStop() -> onDestroy() -> onCreate() -> onResume()... 即重建了整个Activity。
若想忽略某个事件,需在AndroidManifest.xml里配置android:configChanges属性。(同时,实现onConfigurationChanged(Configuration)方法)。
使用startActivity(Intent)启动的新活动会被放到活动栈的顶。Intent参数描述了要启动何种Activity。
有时想在某个Activity结束时获取一个返回值,则要调用startActivityForResult(Intent,int)。则在宿主Activity的onActivityResult(int,int,Intent)里会获取返回值。
寄主Activity要在结束前调用setResult(int)。还可以附加一个Intent作为附加数据。
若寄主Activity未正常结束(比如崩溃了),宿主只会得到一个RESULT_CANCELED返回值。
public class MyActivity extends Activity {
...
static final int PICK_CONTACT_REQUEST = 0;
protected boolean onKeyDown(int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_DPAD_CENTER) {
startActivityForResult(
new Intent(Intent.ACTION_PICK, // 用户想选择一个联系人
new Uri("content://contacts")),// 联系人列表
PICK_CONTACT_REQUEST); // 自定义的Activity ID
return true;
}
return false;
}
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == PICK_CONTACT_REQUEST) {
if (resultCode == RESULT_OK) { // 把返回的联系人显示给用户
startActivity(new Intent(Intent.ACTION_VIEW, data));
}
}
}
}
Activity有两种保存数据的方式。
- 共享文档式的数据(存储到SQLite数据库中);
- 内部私有的数据,比如“用户偏好”(user preferences)。
第一种存储方案建议使用“即编即存”的模式。有两个要点:
- 建立新文档时,立刻在后台数据库建立一个条目。比如想编辑一条新邮件,马上在数据库建新条目。这样,用户跑到其它Activity时,邮件会自动保存到草稿箱。
- 活动的onPause()回调时,马上保存。保证了数据可被其它运行的activity看到。
这意味着用户按BACK时,不是CANCEL,而是SAVE。
第二种方案,使用getPreferences(int)方法,保存“键值对儿”到该Activity相对应的存储区域。
注意,不同Package之间不能访问这些内部数据。同一Package的不同Activity是可以互访的。
public class CalendarActivity extends Activity {
...
static final int DAY_VIEW_MODE = 0;
static final int WEEK_VIEW_MODE = 1;
private SharedPreferences mPrefs;
private int mCurViewMode;
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
SharedPreferences mPrefs = getPreferences(MODE_PRIVATE);
mCurViewMode = mPrefs.getInt("view_mode" DAY_VIEW_MODE);
}
protected void onPause() {
super.onPause();
SharedPreferences.Editor ed = mPrefs.edit();
ed.putInt("view_mode", mCurViewMode);
ed.commit();
}
}