1、Activity概述与生命周期ActivitiesActivity 是这样一个程序组件,它为用户提供一个用于任务交互的画面。例如,拨打电话,拍照,发邮件。或者查看地图。每一个activity都被分配一个窗口。在这个窗口里,你可以绘制用户交互的内容。 这个窗口通常占满屏幕,但也有可能比屏幕小,并且浮在其它窗口的上面。一个应用程序通常由多个activity组成,它们彼此保持弱的绑定状态。典型的,当一个activity在一个应用程序内被指定为主activity, 那么当程序第一次启动时,它将第一个展现在用户面前。为了展现不同的内容,每一个activity可以启动另外一个。 每当一个新的activit
2、y被启动,那么之前的将被停止。但系统将会把它压入一个栈(“back stack”即后退栈),当一个新的activity启动,它将被放到栈顶并获得用户焦点。后台栈遵循后进先出的栈机制。所以当用户完成当前页面并按下返回按钮时,它将被pop出栈(并销毁),之前的activity将被恢复。 (关于后退栈的更多讨论在任务和后退栈)当一个activity因为另一个activity的启动而被停止,那么其生命周期中的回调方法,将会以状态改变的形式被调用。 activity通过它自身状态的改变可以收到多个回调方法。当系统创建,停止,恢复,销毁它的时候。并且每个回调方法都给你做相应处理工作的机会。 例如,当停止的
3、时候,你的activity应当释放比较大的对象,例如网络连接,数据连接。当你的activity恢复时,你可以请求必须的资源并恢复一些被打断的动作。 这些状态事务的处理就构成了activity的生命周期。接下来将讨论如何搭建和使用activity,完整讨论activity的生命周期是怎么工作的,这样你就可以合理地管理不同activity状态间的事务处理。创建一个Activity要创建一个activity,你必须创建一个Activity(或者它存在的子类)的子类。 在你的子类里,你需要实现系统调用的回调方法,这些方法用于activity在生命周期中进行事务处理。例如创建,停止,恢复,销毁。其中两个
4、最重要的回调方法分别为:onCreate()你必须实现这个方法。系统会在创建activity的时候调用这个方法。 在实现这个方法的同时,你需要实现你activity的重要组件。 最重要的是,你必须在这里调用 setContentView() 来定义你activity用于用户交互的布局。onPause()系统将会调用这个方法作为用户离开activity的首先提示(虽然这并不意味着activity正在被销毁)。这通常是你应该在用户会话之前提交并保存任何更改的时机。 (因为用户可能不会再回到这个activity).你还应该会用到一些其他的生命周期回调方法,它们将帮助你在activity和可能导致你的
5、activity停止甚至销毁之间保持流畅的用户体验。 所有的生命周期回调方法都将在后面讨论。详细请看管理Activity的生命周期.实现一个用户交互界面activity的用户接口由一些View的派生类组成的层级结构提供。 每一个view控制acitivity所在window的一个特殊的矩形空间。并且可以响应用户的交互。 例如,一个view可能是一个按钮,当用户碰触的时候将发起动作。Layouts是一组继承了ViewGroup的布局。它们为子视图提供了唯一的布局模型。 例如线性布局,表格布局,相对布局。你也可以继承View和ViewGroup(或它们的子类)去创建你自己的组件或布局,并用它们组成
6、activity布局。定义布局最常用的方式是使用XML布局文件,它保存在你程序的资源中。这种方式可以保证你的业务逻辑代码和用户交互界面分开。你可以通过setContentView()传递布局文件的ID来设置程序UI。 当然,你也可以在activity代码里自己新建View,并通过插入子View到ViewGroup。 然后把这些视图的根视图传入到setContentView()。更多用户界面创建请参照User Interface 文档。在配置文件中声明activity为了可以访问activity,你必须把它配置到配置文件中。 首先打开配置文件,在中增加一个元素。例如: . .你可以给这个元素加入
7、很多其他的属性。 例如名称,图标,或者activity的主题风格。 android:name 属性是唯一用来指定acitivity名称的属性。 一旦你发布了程序,就不能改变它的名字,否则将破坏一些功能,例如程序图标。 (阅读博文查看你不能改变的属性查阅 来获得更多关于如何配置activity。(官方文档是最好的学习资源)。使用filter 也可以用很多 来指定其他的组件怎样激活它。当你使用Android SDK tools来创建一个程序,主activity将会自动包含一个被分类为launcher的intent filter,如下: 元素指定程序的入口。 指出该activity应该被列如系统的启
8、动器(launcher)(允许用户启动它)如果你想要你的程序更加独立,并不想让其他程序访问你的activity,那么你就不必声明intent filter,只有一个activity 应该有mainaction和launcher分类,例如上述例子。你不想公开的activity应该不包含任何intent filter.但你可以使用明确 的intent来启动它们。(下文将详述,显式与隐式启动)。然而,如果你想要你的activity响应其他程序(或当前程序)的隐式intent,你必须为activity定义额外的intent filter。 每一个你想响应的intent,都必须包含一个 ,并包含一个 元
9、素,另外,可以包含一个 也可以包含一个 元素。 这些元素指定了intent 的类型。关于响应intent的更多方式,请查阅 Intents 和 Intent Filter。启动一个Activity你可以启动一个其他的activity通过调用startActivity(), 并传递一个 Intent , 它用于描述acitity。 intent指定了你想要启动的activity,或者指定了你想展现的动作(系统帮你选择合适的activity,它可能来自于其他的程序)。 intent也可以携带比较小量的数据,用于启动acitivity。在你自己的应用中,你经常会简单地启动一个已知的activity,
10、 通过创建一个明确的intent。这个intent指定了activity的类名。 例如下面演示了如何启动一个叫SignInActivity的activity:Intent intent = new Intent(this, SignInActivity.class);startActivity(intent);然而,你的程序可能想要展示某些动作,例如发邮件,短信,微博,或者使用你activity中的数据。 这时候,你就不应该使用自己的activity来做这些工作。你应该调用系统中其他程序提供的响应功能。 这是intent真正体现其价值的地方。你可以创建一个描述了响应动作的intent,然后系统
11、来为你挑选完成任务的程序。 如果有多个选择,系统会提示用户进行选择。例如你想让用户发邮件,你可以创建下面的intent:Intent intent = new Intent(Intent.ACTION_SEND);intent.putExtra(Intent.EXTRA_EMAIL, recipientArray);startActivity(intent);EXTRA_EMAIL 是一个邮件intent中添加的额外字符串数组,它指定了邮件该发给哪些邮件地址。当一个邮件程序响应了这个intent, 它将读取这些地址,并把他们放置到邮件表单的被发送人栏。这时,邮件程序被启动。当用户完成了发送操作
12、,你的activity会被恢复。启动一个带返回结果的activity(单例模式的Activity无法向其他activity回调数据)有时候,你想要启动一个activity,并从这个activty获得一个结果。 这时,要通过 startActivityForResult() (取代startActivity() 来启动activity。 然后通过实现onActivityResult()回调方法来获得返回后的结果。 当这个后续的activity被关闭,它将发送一个 Intent 给 onActivityResult() 方法。例如,你可能想要取一个联系人的信息。下面介绍怎么创建intent并处理结
13、果:private void pickContact() / Create an intent to pick a contact, as defined by the content provider URI Intent intent = new Intent(Intent.ACTION_PICK, Contacts.CONTENT_URI); startActivityForResult(intent, PICK_CONTACT_REQUEST);Overrideprotected void onActivityResult(int requestCode, int resultCode
14、, Intent data) / If the request went well (OK) and the request was PICK_CONTACT_REQUEST if (resultCode = Activity.RESULT_OK & requestCode = PICK_CONTACT_REQUEST) / Perform a query to the contacts content provider for the contacts name Cursor cursor = getContentResolver().query(data.getData(), new St
15、ring Contacts.DISPLAY_NAME, null, null, null); if (cursor.moveToFirst() / True if the cursor is not empty int columnIndex = cursor.getColumnIndex(Contacts.DISPLAY_NAME); String name = cursor.getString(columnIndex); / Do something with the selected contacts name. 这个例子展示了使用onActivityResult() 来获取结果的基本方
16、法。 第一步要判断请求是否被成功响应,通过判断resultCode 是不是RESULT_OK, 然后判断这个响应是不是针对相应的请求 ,此时只要判断requestCode 和发送时提供的第二个参数 startActivityForResult() 是否相匹配。 最后,查询 Intent中的data信息。 (data 参数)。这个过程中,ContentResolver 开启了一个查询而不是content provider, 它返回一个 Cursor ,这将允许数据被读取。更多content provider相关信息,请查阅Content Providers 文档。关于intent的更多信息, 查
17、看 Intents and Intent Filters 文档。关闭Activity你可以通过调用finish() 来终止activity。 你也可以调用finishActivity() 来终止你之前启动了的一个独立activity。注意: 多数情况下,你不应该明确地通过这些方式来关闭acitivity。 就像下面要讨论的activity的生命周期。系统会为你管理。所以你不必关闭他们。 调用这些方法将有悖于用户体验。它们仅用于你绝对不想让用户再返回这个activity的实例。管理activity的生命周期通过实现回调方法来管理你的activity的生命周期,对于开发一个健壮而又灵活的应用程序而
18、言是至关重要的。 与其它activity的关联性、自身的任务和back stack直接影响着一个activity的生命周期。activity可能处于三种基本的状态: Resumed:activity在屏幕的前台并且拥有用户的焦点。(这个状态有时也被叫做“running”。) Paused:另一个activity在前台并拥有焦点,但是本activity还是可见的。 也就是说,另外一个activity覆盖在本activity的上面,并且那个activity是部分透明的或没有覆盖整个屏幕。 一个paused的activity是完全存活的(Activity 对象仍然保留在内存里,它保持着所有的状态和成
19、员信息,并且保持与window manager的联接),但在系统内存严重不足的情况下它能被杀死。 Stopped:本activity被其它的activity完全遮挡住了(本activity目前在后台)。 一个stopped的activity也仍然是存活的(Activity 对象仍然保留在内存中,它保持着所有的状态和成员信息,但是不再与window manager联接了)。 但是,对于用户而言它已经不再可见了,并且当其它地方需要内存时它将会被杀死。 如果activity被paused或stopped了,则系统可以从内存中删除它,通过请求finish(调用它的 finish() 方法)或者直接杀死
20、它的进程。 当这个activity被再次启动时(在被finish或者kill后),它必须被完全重建。实现生命周期回调方法当一个activity在上述描述的状态之间转换时,它将通过各种回调方法来获得通知。 所有的回调方法都是钩子(hook),当activity状态发生改变时你都可以重写这些方法来执行对应的工作。 以下的activity提纲包含了所有基本的生命周期方法:public class ExampleActivity extends Activity Override public void onCreate(Bundle savedInstanceState) super.onCreat
21、e(savedInstanceState); / The activity is being created. Override protected void onStart() super.onStart(); / The activity is about to become visible. Override protected void onResume() super.onResume(); / The activity has become visible (it is now resumed). Override protected void onPause() super.on
22、Pause(); / Another activity is taking focus (this activity is about to be paused). Override protected void onStop() super.onStop(); / The activity is no longer visible (it is now stopped) Override protected void onDestroy() super.onDestroy(); / The activity is about to be destroyed. 注意:实现这些生命周期方法时,必
23、须保证在其它代码之前首先调用一下父类的方法,如上例所示。 总体来讲,这些方法定义了一个activity的完整的生命周期。 通过实现这些方法,你可以监控activity生命周期中三个嵌套的循环:activity的完整生存期会在 onCreate() 调用和 onDestroy() 调用之间发生。 你的activity应该在 onCreate() 方法里完成所有“全局global”状态的设置(比如定义layout), 而在onDestroy() 方法里释放所有占用的资源。 例如,如果你的activity有一个后台运行的线程,用于从网络下载数据,那么你应该在 onCreate() 方法里创建这个线程
24、并且在 onDestroy() 方法里停止这个线程。activity的可见生存期会在 onStart() 调用和 onStop() 调用之间发生。在这期间,用户可在屏幕上看见这个activity并可与之交互,但是没有获取焦点。 例如,当一个新的activity启动后调用了 onStop() 方法,则这个activity就无法被看见了。 在这两个方法之间,你可以管理那些显示activity所需的资源。例如,你可以在 onStart() 方法里注册一个 BroadcastReceiver 用于监控影响用户界面的改动。并且当用户不再看到你的显示内容时,在 onStop() 方法里注销掉它。 系统会在
25、activity的整个生存期内多次调用 onStart() 和onStop(), 因为activity可能会在显示和隐藏之间不断地来回切换。activity的前台生存期会在 onResume() 调用和 onPause() 之间发生。在这期间,activity是位于屏幕上所有其它的activity之前,并且拥有用户的输入焦点。 activity可以频繁地进入和退出前台例如, 当设备进入休眠时或者弹出一个对话框时,onPause() 就会被调用。因为这个状态可能会经常发生转换,为了避免切换迟缓引起的用户等待,这两个方法中的代码应该相当地轻量化。 图1说明了activity在状态之间可能行走的这些
26、循环和路径。矩形代表了你可以实现的回调方法,用于activity状态转换时执行相应操作。 图 1.activity生命周期同样的生命周期回调方法已经在表1中列出了,该表更详细地描述了每个回调方法,并且指明了每个方法在activity的全生命周期中的位置, 包括回调方法完成后系统是否会杀死这个activity。标为“之后可否被杀死?”的列指明了系统是否可以在这个方法返回之后的任意时刻杀掉这个activity的宿主进程, 而不再执行其它流程上的activity代码。 有三个方法是标为“可以”:( onPause()、 onStop()、 和onDestroy())。 因为onPause()是三个方
27、法中的第一个, 一旦activity被创建, onPause() 就是进程可以被杀死之前最后一个能确保被调用的方法 如果系统在某种紧急情况下必须回收内存,则 onStop() 和onDestroy() 可能就不会被调用了。因此,你应该使用 onPause() 来把至关重要的需长期保存的数据写入存储器(比如用户所编辑的内容)。 不过,应该对必须通过 onPause() 方法进行保存的信息有所选择,因为该方法中所有的阻塞操作都会让切换到下一个activity的停滞,并使用户感觉到迟缓。“之后可否被杀死?”列中标为“否”的方法,在它们被调用时的那一刻起,就会保护本activity的宿主进程不被杀掉。
28、 因此,只有在 onPause() 方法返回时至 onResume() 方法被调用时之间,activity才会被杀掉。直到 onPause() 再次被调用并返回时,activity都不会再次允许被杀死。Note:表1中标明的技术上不“可杀”的activity仍然有可能会被系统杀死但那只有在没有任何资源的极端情况下才会发生。 什么时候activity会被杀掉,已在文档进程和线程里详细说明了。保存activity的状态(onSaveInstanceState何时调用)管理Activity生命周期一节中已简单提到,当一个activity被paused或者stopped时,activity的状态可以被
29、保存。 的确如此,因为 Activity 对象在paused或者stopped时仍然被保留在内存之中它所有的成员信息和当前状态都仍然存活。 这样用户在activity里所作的改动全都还保存着,所以当activity返回到前台时(当它“resume“),那些改动仍然有效。不过,如果系统是为了回收内存而销毁activity,则这个 Activity 对象就会被销毁,这样系统就无法简单地resume一下就能还原完整状态的activity。 如果用户要返回到这个activity的话,系统必须重新创建这个Activity 对象。可是用户并不知道系统是先销毁activity再重新创建了它的,所以,他很可能
30、希望activity完全保持原样。 这种情况下,你可以保证activity状态的相关重要信息都由另一个回调方法保存下来了,此方法让你能保存activity状态的相关信息: onSaveInstanceState()。在activity变得很容易被销毁之前,系统会调用 onSaveInstanceState()方法。 调用时系统会传入一个Bundle对象, 你可以利用 putString() 之类的方法,以键值对的方式来把activity状态信息保存到该Bundle对象中。 然后,如果系统杀掉了你的application进程并且用户又返回到你的activity,系统就会重建activity并将这个 Bundle 传入onCreate() 和onRestoreInstanceState() 中,你就可以从 Bundle 中解析出已保存信息并恢复activity状态。如果没有储存状态信息,那么传入的 Bundle 将为null(当activity第一次被创建时就是如此)。注意: activity被销毁之前,
copyright@ 2008-2022 冰豆网网站版权所有
经营许可证编号:鄂ICP备2022015515号-1