`
jishublog
  • 浏览: 869017 次
文章分类
社区版块
存档分类
最新评论

Android Developers:Activities

 
阅读更多

Activity

Activity是应用程序的组件,它提供了一个屏幕 ,用户可以与之互动,以做一些事情,如拨打电话,拍照发送电子邮件,或查看地图。每个Activity会提共一个窗口,在其中绘制它的图形界面。通常窗口会填满整个屏幕,但也有可能比屏幕小并且浮动在其他窗口之上。

应用程序通常是多个松散并且相互绑定的Activity组成。一般,用户首次启动应用时,将启动一个被指定为”main”的Activity。每个Activity都可以启动另一个Activty,以执行不同的动作。每次启动一个的Activity,以前的Activity停止,但在系统堆栈保留Activity(”回栈“)。一个新的Activity启动时,它将Activity压到栈里并取得用户的焦点。回堆栈遵守基本的”先进先出“的堆栈机制,这样,当用户在前Activity,按下返回按钮,则弹出堆栈(并销毁)和恢复以前的Activity。(回栈在任务和返回堆栈--tasks-and-back-stack文件有详细说明。)

Activity停止是因为一个新的Activity的开始,通过活动的生命周期回调方法,通知这种状态发送变化。一个Activity可能会收到多个回调方法,当状态发生变化时。产生,停止,恢复,销毁,这些回调在适当的实际提供给您相应的工作机会。例如,停止时,你的Activity应该释放大型对象,如网络或数据库连接。恢复Activity时,你可以重新获得必要的资源和恢复被中断的Activity.这些状态转换是所有Activity生命周期的一部分。

本文件的其余部分将讨论如何建立和使用Activity,包括讨论一个完整的Activity程序周期是如何工作,你能正确的管理各种Activity状态之间的转换。

生成Activity

要生成一个Activity,你必须生成一个Activity子类Activity(或已有的子类)。在你的子来中,创建,停止,恢复和销毁Activity时,你要实现回调方法,系统调用时,用这些方法在Activity生命周期的各种状态之间转换。两个最重要的回调方法是:

onCreate():必须实现这个方法。生成Activity是系统调用。在你实现中,你应该初始化你的Activity中的组件。最重要的是,这是你必须调动setContentView()定义Activity界面的布局。
onPause():当用户离开你的Activity的时候(尽管它并不总是意味着被销毁Activity),系统调用此次方法。通常如果你需要保持当前绘画的话,你所有的改动都应该在这提交(因为用户可能不返回)。

还有其他几个生命周期回调方法,你应该使用这些方法处理Activity与导致使Activity必须停止,甚至销毁的突发中断之间的事情,来提供流畅的用户体验。所有的声明周期回调方法在稍后讨论,有关管理Activity声明周期部分。

实现用户界面

一个Activity的用户界面是有一组按派生是视图类—View的视图对象组成。每个视图控制Activity窗口的特定矩形控件,以响应用户交互。例如,一个视图可能是一个按钮,当用户触摸它启动一个操作。

Android提供了一些现成的视图,你可以用它来设计和组织布局。“Widgets”就是视图,它提供了一个可视的可交互的屏幕元素,如按钮,文本字段,复选框,或只是一个图像。“布局”是从视图组--ViewGroup派生的,提供了对子视图特殊的布局模式,如线性布局,网格布局,或相对布局来创建自己的Widgets和布局,并将其应用到你的Activity布局中。

最常见的方式来定义个布局的意见,是一个XML布局文件保存你的应用程序资源。这种方式,你可以单独从资源中维护你的用户界面设计以及定义Activity的行为。你可以通过setContentView()设置你的Activity的UI布局,传入布局的资源ID。或者,你也可以在Activity代码中生成新的视图--View层次结构插入到视图组--ViewGroup,然后传入根试图组--ViewGroup给setContentView()进行布局。

有关创建用户界面的信息,请参阅用户界面文档。

声明Activity

要在系统中使用Activity,你必须在manifest文件中声明你的Activity。打开你的manifest文件,并添加<activity-element>作为<application>元素一个子元素,例如:

在这个元素可以包含一些属性,包括定义属性,如Activity的标签,图标的Activity,或Activity的主题UI风格。属性android:name是唯一需要的属性,它指定Activity的类名。一旦你发布你的应用程序,你不应该改变这个名字,因为如果这样做,你可能会破坏一些功能,如应用程序的快捷方式。有关在manifest文件声明Activity的更多的信息请查阅<activity>元素。

使用intent过滤器

一个<activity>元素可以使用<intent-filter>的元素指定的各种intent过滤器,以说明其它应用程序组件可以如果激活它。当你使用Android SDK工具为你创建一个新的应用,<activity>标签下就自动包括用于声明Activity响应”main”的动作的intent过滤器和用于启动的”launcher”分类。intent过滤器看起来像这样。

<action>元素指定应用程序”main”的入口。<category>元素指定系统的activity列表上应用启动的Activity,(允许用户启动这个Activity)。如果你打算让你的应用程序成为一个独立的应用,不允许其它应用程序启动应用中的Activity,那你就不需要其它的intent过滤器。如前面示例所示,只有一个Activity带有”main”动作和“launcher”类别。你不让其它Activity用其它应用程序,那它们不应有任何intent过滤器,你必须显示的调用intent启动它们(在下一节讨论)。

但是,如果你希望你的Activity响应其它应用程序(和自己)的隐式intent,那么你必须在你的Actibity中定义额外的intent过滤器。为了响应你需要响应的每种intent,你必须包括<intent-filter>,其中包括一个<action>元素和一个可选的<category>元素或<data>元素。这些元素指定你的Activity可以响应的intent类型。

查看更过关于你的Activity能够响应intent类型的信息,查看intent和intent过滤器文档。

启动Activity

你可以通过调用startActivity()启动另一个Activity,它传递了一个intent描述你要启动的Activity。intent指定了你要启动的Actvity,或描述要执行的动作类型(系统为你选择合适的Activity,甚至可能是其它应用程序的Activity)。intent也可携带少量数据被用于要启动的Activity。

在自己的应用程序中,你会经常需要简单启动一个已知的Activity。你可以使用类名来创建一个intent,明确定义你要启动的Activity。例如,如下是一个Activity的启动和另一个命名为SignInActivity的Activity:

另外,你的应用程序可能还需要执行一些动作,例如发送电子邮件,文字信息,或状态更新,使用Activity中的数据。在这种情况下,你的应用程序可能无法有其自身的Activity,执行这些行动,所以你可以转而利用设备上其它应用程序提供的Activity为你执行。这是intent真正有价值的地方----你可以创建一个描述了要执行的一个动作的intent,系统从另一个应用程序启动的Activity。如果有多个Activity可以处理intent,那么用户可以选择使用哪一个。例如,如果你想允许用户发送电子邮件,你可以创建以下intent:

EXTRA_EMAIL为发送电子邮件的邮电地址字符串数组,其充当intent的额外数据。但一个电子邮件应用程序响应此intent,它读取额外提供的字符串数组,并把它们放在程序的“to”地址栏。在这种情况下,应用程序启动电子邮件Activity,当用户完成后,恢复到你的Activity。

启动Activity返回结果

有时,你可能要取得你启动的Activty的结果。在这种情况下,使用Activity的startActivityForResult()(而不是startActivity())。然后再后续实现了onActivityResult()回调方法的Activity取得结果。后续Activity完成后,它会返回一个intent给你onActivityResult()方法。

例如,也许你希望用户选择他们的联系人之一,便于你的Activity可以做一些与该联系人的信息相关的事情。下面是怎样生成这样的intent并处理结果:

这个例子说明了使用onActivityResult()方法处理Activity的结果的基本逻辑。首要条件是检验请求是否成功和这个结果是否响应已知,如果是,那么ResultCode就会是Activity.RESULT_OK,在这种情况下,requestCode匹配startActivityForResult()的第二个参数。从那起,代码在intent中处理取得Activty查询数据的返回结果(data参数)。

ContentResolver针对一个content provider执行查询,返回一个游标--Cursor,允许查询的数据被读取。欲了解更多信息,请参阅content providers文档。

关闭Activity

你可以通过调用finish()方法关闭Activity。你也可以通过调用finishActivity()关闭之前你启动的一个独立的Activity。
注意:在大多数情况下,你应该不需要显示地使用这些方法结束Activity。在下面一节讨论有关Activity生命周期,Android系统为你管理Activity,所以你不需要自己结束Activity。调用这些方法可对用户体验产生影响。只有在你确定不想让用户返回此Activity实例时使用。

管理Activity生命周期

实施生命周期回调方法来管理你的Activity是开发强大和灵活的应用至关重要的。一个与其关联的其它Activity直接影响其Activity的生命周期,任务和返回堆栈。

一个Activity可以基本上存在三种状态:
恢复:这项Activity是在屏幕前的,并使用户取得其焦点。(在此状态,有时也简称为”运行“)
暂停:另一个Activity在屏幕前,取得焦点,但原来的Activity仍然可见。也就是说,另一个Activity是这一个顶部可见,或者是部分透明的或不覆盖整个屏幕。暂停的Activity完全是存在的(Activity对象保留在内存中,它是维护所有状态和成员信息,并保持窗口管理器的联系),但在极低的内存的情况下,可以被系统终止。
停止:Activity完全被另一个Activity遮住了(现在Activity是在”background“)。停止Activity也仍然存在(Activity对象保留在内存中,它保持状态和成员信息,但不和窗口管理器有关联)。然而它已不再是对用户可见,其它地方需要内存时,它可以被系统终止。

如果一项Activity被暂停或停止,该系统可以从内存中删除它,要求它结束(调用它的finish()方法),或者干脆杀死它的进程。Activity再次打开时(在被结束或被杀死),它必须创造所有的一切。

实现声明周期回调函数

当Activity按照如上所述在不同状态转进、出的时候,是通过各种回调方法进行通知的。所有的回调方法都是钩子,当Activity的状态变化时你可以覆盖它们来做适当的工作。以下的Activity,包括基本生命周期的每一个方法:
注意:在做任何事情之前,实现这些生命周期方法,必须始终调用父类的实现,如上面的例子所示。

综合来看,这些方法定义一个Activity的整个生命周期。通过实现这些方法,你可以监视Activity生命周期的三个嵌套循环:
1.Activity的整个存在周期发生在onCreate()调用和onDestroy()调用之间。Activty调用onCreate()执行“全局状态”设置(如定义布局),并调用onDestroy()释放所有剩余资源。例如,如果Activity有一个线程在后台运行,从网络下载数据,它可能会调用onCreate()创建该线程,然后又onDestroy()停止线程。
2.Activity的可见周期发生在onStart(0调用和onStop()调用之间。在这段时间内,用户可以看到屏幕上的Activity,并与其它交互。例如,一个新的Activity启动时,onStop()被调用,这时Activity不再可见。这两个方法之间,你可以维持运行Activity所需要的资源,提供给用户。例如,你可以再调用onStart()注册broadcastReceiver见此影响你用户界面的变化,当用户可以不再看到内容时,在onStop()时注销。在整个存在周期的Activty,Activity在可见和不可见的变化中,系统可能多次调用onStart()和onStop()。
3.Activity的前台周期发生在onResume()调用和onPause()调用之间。在这段时间,该Activity显示在屏幕上,在所有其它Activity之前,用户具有输入焦点。一个Activity经常在前台后台之间转换,例如,当设备进入睡眠状态,或弹出一个对话框是onPause()被调用。因为这种状态转换,在这两种方法中的代码应该是相当轻量级的,以避免缓慢的转换,使用户等待。
图1.Activity的声明周期。说明了这些循环和Activity状态之间可能转换的路径。矩形代表在Activity状态转化之间要执行操作的回调方法。

同样表1列出了所有的生命周期回调方法,描述了每一个回调方法细节和在Activity的整个生命周期内的位置,包括系统完成回调方法后是否能杀死Activity。
方法 说明 之后是否可Kill? 之后调用
onCreate() Activity第一次被创建时调用。通常你在此处理静态设置--比如创 否 onStart()
建视图,数据绑定列表等。如果状态可被捕获,一个Bundle包含
Activity以前的状态对象将传递给这个方法,之后是onStart()。
onRestart() Activity停止之后,启动之前调用。 否 onStart()
onStart() 当Activity将要可见的时候调用,如果之后前台可见,调用onRes 否 onResume()
ume(),如果其前台不可见调用onStop()。 onStop()
onResume() 在Activity和将要和用户交互的时候调用,此时Activity位于Activi 否 onPause()
ty栈的栈顶,并且正在获取用户的输入设备,之后调用onPause
()
onPause() 当系统恢复另外一个Activity时调用它,通常用户保存没有保存的数 是 onResume()
据,停止消耗cpu的动画处理和其它事情,只有当它返回后,其它的 onStop()
Activity才能恢复,因此它调用时间很短。之后如果另外一个Activty
返回到前台,将调用onResume(),否则调用onStop()
onStop() 当Activity对用户不在可见时调用,发生在当另一个已存在或者新的A 是 onRestart()
ctivity恢复并覆盖它的时候,要不就是在自己被销毁的时候,之后如 onDestroy()
果Activity又恢复到前台并能与用户交互,调用onRestart(),否则调用
onDestroy()
onDestroy() 当销毁Activity时候调用,这是Activity最后能接受的到的回调方法, 是 nothing
要不是由Activity已经完成(有finish()调用),或者是系统由于节省
资源的需要临时销毁Activity,你可以通过isFinishing()方法来判断
这两种情况是哪一种。
列表中“之后是否可Kill?”表示在功能返回后系统可以随时Kill Activity的主进程,不会执行Activity的其它代码。表中有三种方法填的“是”:(onPause(),onStop(),和onDestroy())。 onPause()是三个方法中最先被调用的,Activity创建后,onPause()是在系统能kill进程之前保证能被调用到的方法----如果系统在紧急情况下必须恢复内存,之后onStop()和onDestroy()可能不会被调用,因此,你应该使用onPause()写入写持久性数据(如存储用户正在编辑的数据)。然而对于要保存的数据,你应该有选择性,因为任何阻塞方法将阻塞系统转到下一个Activity,降低了用户体验。

“之后是否可以Kill?”列中被标记为“否”的方法,表示此时系统会保护Activity的主进程不被kill。因此,Activity在从onPause()返回到onResume()被调用的这段时间是可被kill的。在下次onPause()被调用并返回之前,将不能被kill。
注:对于Activity,表1中的定义,技术上来说并不是“可kill”,Activity仍然可以被系统“kill”,但仅在系统资源匮乏的极端情况下才会发生。Activity何时能被kill,更多信息在进程和线程文档中讨论。

保存Activity状态

管理Activity生命周期介绍中简要提及当Activity暂停或停止的时候,Activity的状态被保留。这是观点是正确的,因为当它暂停或停止的时候,Activity对象一直保存在内存当中,它的成员和当前状态的所有信息一直存在。因此,任何用户在这个Activity内的改变都保存在内存中,所以当Activity返回到前台的时候(when it “resumes”),这些改变将被还原。
图2.一个Activityan保持它完整的状态返回到用户的焦点的两种方式:要么Activity被停止,然后恢复并且Activity的状态要保持完整(左)。要么Activity被销毁,然后创新创建并且Activity必须还原前Activity的状态(右)。

然而,当系统为了回收内存而销毁一个Activity的时候,这个Activity对象被销毁,所以系统不能简单地恢复到之前的完整状态。相反,如果用户返回到它,系统必须重新创建Activity对象。但是,用户并不关心系统销毁Activity,并重新创建它。而是,更关心Activity是否能恢复到所期望的状态。 在这种情况下,你可以通过实现一个允许你保存状态信息的附加回调函数,来确保有关Activity状态的重要信息被保存,然后再系统重新创建Activity的时候恢复它。

这个能让你保存你Activity的当前状态信息的回调方法是onSaveInstanceState()。在Activity易受损害将被销毁的之前, 系统调用onSaveInstanceState()方法,并传递给其一个Bundle对象。Bundler让你可以使用例如putString()和putInt()等方法,以名称--值对的形式保存状态信息。然后,如果系统kill你的activity的进程并且当用户返回你的Activity,系统传递这个Bundle对象给onCreate(),所以你能恢复你在onSvaInstanceState()方法中保存的Activity的状态信息。如果没有需要恢复的信息,Bundle传递的是null[只有在横竖屏切换的时候Bundle才为非null]
注:Activity被销毁之前不保证onSaveInstanceState()会调用,因为有些情况下,它不需要保存状态(例如,当用户使用“BACK”按键离开Activity的时候,因为用户已明确关闭Activity)。如果系统调用onSaveInstanceState(),那么它总是会在onStop()前并且也可能在onPause()前。

然而,即使你什么也不做且不实现onSaveInstanceState()方法,某些Activity状态会通过使用Activity类的默认onSaveInstanceState()实现来恢复。具体来说,默认实现调用了布局中每个View调用相应的onSaveInstanceState()方法,它允许每个视图提供它自己保存的相应信息。如此以至于UI的任何可见的改变都会自动的保存并且在你重新创建activity的时候恢复[在横竖屏切换和BACK键resume是实现]。例如,EditText控件保存由用户输入和任何文字,CheckBox控件保存它是否检查。对于你要保存其状态的每一个部件,你所需要做的唯一的工作是提供一个唯一的ID(使用android:id属性)。如果一个组件,如果没有一个ID,系统无法保存其状态。

虽然默认onSaveInstanceState()实现保存了有关Activity UI的有用信息,你仍可能需要重写它,以保存额外的信息。例如,在Activity中你可能需要在activity的生命周期内保存发生改变的成员变量。(可能在UI恢复时需要关联这些值,但默认的情况下,拥有UI值的成员都不会被还原)。

通过设置android:saveEnabled属性或调用setSaveEnable()方法。你也能在你的布局中明确停止一个view保存它的状态信息。通常,你不会取消它,但是如果你想恢复不同的Activity UI的状态的时候你可能会。

由于onSaveInstanceState()的默认实现帮助保存UI的状态,如果你为了要保存额外的状态信息而重写此方法,那么在你做什么工作之前,你一定要调用其超类的实现方法。同样,如果你重写它,你也应该调用onRestoreInstanceState()实现的超类方法,以此默认实现恢复视图状态。
注:因为onSaveInstanceState()方法不能保证被调用,所以在用户离开Activity的时候,你应该只是是用它记录Activty的瞬时状态(UI的状态),你不应该用它来存储持久数据。相反,你应该使用onPause()存储持久数据(例如保存到数据的数据)。

测试你的应用程序恢复其状态的能力的一个好方法是简单地旋转手机,使屏幕的方向发生变化。当屏幕方向发生变化的时候,为了替换适应新方向的资源,系统的销毁并重新创建Activity。因为这个原因,当actovotu被重建时,你的Activity完全恢复状态时就非常重要了,因为用户经常在使用应用程序时旋转屏幕。

处理配置更改

某些设备配置在运行时可以改变(如屏幕的方向,键盘的可用性,和语言)。当这种变化发生时,Android重新运行Activity(系统调用的onDestroy(),然后立即调用onCreate())。通过自动加载你提供的可替代资源到应用程序,这种重启行为帮助你的应用适应新的配置。如果你设计Activity以正确的处理这些事件,那么在Activity生命周期中,它对于其它突发事件的应对将更有弹性。

处理像屏幕方向改变等配置更改的最好方法,就是像上一章节讨论的那样,使用onSaveInstanceState()和onRestoreInstance()(或者onCreate())简单的保存你的应用的状态。

更多运行时设备配置的更改,以及如何处理它们信息,请阅读Handing Runtime Changes

并列的Activity

当一个Activity启动另外一个时,它们都经历了生命周期的转换。第一个Activity pauses和stops(不过,如果它仍然在后台可见,它不会stop),一会儿另一个被Activity创建。在这些Activity的共享被保存在磁盘上或其它地方,它非常重要的,了解在第二个Activity没有被创建之前,第一个Activity是不会完全被停止的。相反,启动第二个Activity进程覆盖第一个Activity进程。

生命周期回调方法的顺序被很好的定义了,特别是在同一个进程中两个Activity,一个启动另外一个的时候。如果下是当Activity A启动Activity B是产生的操作顺序
1.ActivityA执行onPause()方法
2.ActivityB按照onCreate(),onStart(),onResume()的顺序执行方法(ActivityB 现在取得用户的焦点。)
3.然后,如果ActivityA已不在是显示在屏幕上,它执行方法onStop()。

这个可预测的生命周期回调顺序,可让你管理的从一个Activity到另一个Activity的转换信息。例如,如果第一个Activity停止时你必须写数据库,让之后的Activity读取数据库,那么你应该在onPause()期间写数据库,而不是onStop()。

文档目录:Developers/API Guides/App Components/Activities

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics