博客出自:http://blog.csdn.net/liuxian13183,转载注明出处! All Rights Reserved !
Activity主要用来展示给用户,让用户与后台数据交互,以获得其想要的结果。
以下文章它代指“Activity”,创建代指"onCreate",中止代指"onPause",恢复代指"onResume",销毁代指"onDestroy"
Activity是一个应用程序组件,它提供了一个屏幕,用户可以参与互动做一些事情,比如打电话、拍照、发送电子邮件或者查看地图。每个Activity都有一个窗体,用来绘制用户界面。通常情况下,窗口会填满整个屏幕,但也可能比屏幕小而浮在它的顶部。
一个应用程序通常是由多个彼此松散的Activity绑定在一起。通常情况下,一个Activity在应该程序中被指定为“main”,那么首次启动应用程序时,它将展现给用户。然后每个Activity都可以通过动作来启动其他Activity,每次一个新Activity启动时,上一个活动就会停止,但系统会把这个Activity保存在堆栈里(“后退堆栈”)。当一个新的Activity启动时,它被推入后退堆栈并成为用户操作对象。后退堆栈遵循“后进先出”的原则,这样用户按下后退键时,它被弹出堆栈(销毁),并恢复到以前的Activity(后退堆栈会在“任务和后退堆栈文档里讲述)。
当一个活动因一个新活动的启动而停止时,它通过生命周期的回调查方法来改变通知。有几种Activity可能因改变其状态而会接收的回调方法,无论是处于系统创建(create)、停止(stop)、恢复(resume)还是销毁(destroy)状态,每一个回调方法都提供执行具体工作的机会。例如,当Activity停止(stop)时,它需要翻译大数据对象,如网络或数据库连接。当它恢复(resume)时,你可以去获取必要的资源和恢复被中断的操作,这些状态转变是生命周期的所有组成部分。
接下来将基础的讲述如果创建并使用它,包括一个完整的生命周期是如何工作的,这样你就能正确的管理它的各种状态之间的过渡。
创建它
要创建它,你必须创建一个它的子类(或现有的子类)。在子类中,你要实现当它的各种状态发生改变时系统所调用的回调方法,比如它的创建(oncreate)、停止(onstop)、恢复(onresume)和销毁(ondestroy),以下是两个最重要的回调方法:
onCreate()
你必须实现这个方法,当你创建它的时候系统会调用这个方法。在你的实现方法中,你应该初始化它所需要的各种重要组件,最重要的你必须调用 setContentView()方法来定义用户界面的布局。
onPause()
系统调用这个方法的第一个迹象是,用户离开了当前的Activity(尽管这并不意味着它已经被销毁)。在这里应用提交用户的所有更改,因为超过了当前的会话时间(用户可能不回来了)。还有其它几个需要用到的生命周期的回调方法,主要用来提供一个流畅的用户体验,处理它可能被停止或者销毁的一些突发事件。所有的生命周期回调方法将在稍后的“管理生命周期”部分有讲。
实现用户界面
一个用户界面的Activity,提供从view类派生的视图对象层次结构。每个视图都控件着一个特定矩形的活动窗口,用来响应用户的交互。例如,一个视图可能是一个按钮,用户触摸它启动一个动作。
安卓提供了一系列现成的view用来设计和组织布局,“Widgets”是一种为屏幕提供可视化互动元素的组件,提供如按钮,文本字段,复选框,或只是一张图片。布局是一些来自己ViewGroup的视图,为其子类提供独特的布局模型,如线性布局,网格布局,或相对布局。你还可以使用View或ViewGroup的子类(或现有的子类)来创建自己的"widgets"和布局,将它们应用到Activity的布局。
最常用定义布局的方法是使用一个保存在应用程序中资源的xml文件。通过这种方式,你可以保持你的用户界面设计与定义Activity行为的源代码分开。你可以通过setContentView()来加载UI设置的布局,通过资源的ID来定义操作布局。但是,你也可以在Activity里通过代码创建新的视图,并创建一个视图层次结构,通过使用通过根结点ViewGroup的setContentView()方法来插入新的视图。
创建用户界面的详细信息,请参见用户接口文档。
在manifest声明Activity
你必须在manifest文件中声明它,以便它可以访问系统。声明它的时候,需要打开manifest文件,并为<application>添加子元素<activity>,例如:
<manifest ... >
<application ... >
<activity android:name=".ExampleActivity" />
...
</application ... >
...
</manifest >
还有其它几个属性可以包含在此元素中,来定义它的属性,如它的标签,它的图标以及它的主题样式。android:name这个属性是必须的,用来区别它的名字。一旦你发布了你的应用程序,你就不能去改变它了,因为这么可能会破坏一些功能,如应用程序的快捷方式(阅读记录以及其它一些无法改变的事情)。
参阅<activity>元素的引用,获得更多关于在manifest文件中声明你的Activity的信息。
使用intent filters
<activity>元素可以指定,使用<intent-filter>元素声明的不同意图的过滤器,以使其他组件能够激活它。
当你使用Android SDK工具创建一个新的应用,自动创建的子Activity会为你创建一个过滤器,用来声明主活动,并放入"launcher"类别。
<activity android:name=".ExampleActivity" android:icon="@drawable/app_icon">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<action>元素指定这是主程序入口,<category>元素指定,它可以在系统应用程序中列出来(允许用户启动它)。
如果你打算让你的应用程序是独立的,不让其他应用程序激活其activity,那就没有必要设置过滤器,就像前面的例子,设置一个主动作和"launch"就行。如果你不想让其他应用看到你的activities,就不要设置过滤器,你可以自己用显式启动(在下面的章节中讨论)。
但是如果你希望你的Activity可以响应来自其它或自己的intent,那么你必须为你的Activity定义一个附加过滤器。对于每一个你想响应的intent,必须包含一个 <intent-filter> 元素和一个<action>元素,同时<category>和<data>元素是可选的。这些元素用来区别activity响应的不同意图。
想要了解更更多关于意图的信息,请参阅意图和意图过滤器(Intent and Intent Filters)文件。
启动它
你可以传递一个intent,说明启动Activity的类型,并通过startActivity()方法来启动另一个Activity。intent用于指定确切的Activity,并描述执行的操作类型(系统会选中合适的Activity,甚至不同应用程序的Activity)。用Intent启动另外一个活动时,也可以携带少量数据。
在自己的应用程序中,你经常需要启动一个已知的Activity。你可以通过类名来创建一个intent启动确定的Activity。例如,下面是如何启动一个叫SignInActivity的Activity。
Intent intent = new Intent(this, SignInActivity.class);
startActivity(intent);
但是,你的应用程序可能想通过当前Activity的数据,执行一些操作如发邮件、短信,或状态更新。在这种情况下,应用程序可能没有相应的Activity来执行这些操作,这样你可以利用设备上的其他应用程序所包含的Activity来执行相应操作。这就是intent有用的地方--你可以创建一个你想执行动作的intent,系统就会启动相应其他程序的activity。如果有很多可以处理这个意图的应用程序,那么用户可以选择一个使用。例如,如果你想发邮件,你可以使用下面的intent:
Intent intent = new Intent(Intent.ACTION_SEND);
intent.putExtra(Intent.EXTRA_EMAIL, recipientArray);
startActivity(intent);
添加到intent上的 EXTRA_EMAIL数据是一个字符串的电邮地址。当一个电邮程序响应这个意图时,它读取这个字符串作为电邮的接收方。在这种情况下,电邮程序启动,完成后activity就会恢复。
启动一个Activity并得到一个结果
有时,你需要从一个刚启动的Activity处得到一个返回结果,这种情况下,使用startActivityForResult(而不是startActivity)。然后从子Activity处得到一个结果,实现onActivityResult()方法,当子Activity处理结束,它会返回一个带有结果的intent给父Activity的onActivityResult()方法。
例如,可能你想从众多联系人中获取其中一个,使当前Activity可以处理一些关于那个联系人的信息。下面就是你怎样创建一个intent和处理返回结果的。
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);
}
@Override
protected void onActivityResult(int requestCode, int resultCode, 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 contact's content provider for the contact's name
Cursor cursor = getContentResolver().query(data.getData(),
new String[] {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 contact's name...
}
}
}
这个例子说明了一个用onActivityResult方法处理返回结果的简单逻辑。第一个条件是检查请求是否成功,如果成功了,resultCode==RESULT_OK,然后检查这样的结果请求响应是否已知,这样用requestCode与startActivityForResult()发送的第二个参数相匹配。从那里,代码查询在intent中返回的数据处理Activity的返回结果(数据参数)。
有一种情况,ContentResolver提供一个content provider查询对象,返回一个Cursor来查询已知数据。有关详细信息,请参阅Content Providers文档。
更多intent的详细信息,请查阅intent和intent filter文档。
关闭Activity
你可以通过finish方法关闭一个Activity,你也可以通过finishActivity方法关闭一个先前启动的单独Activity。
注:大多情况下,你不能显式的通过这些方法来关闭一个Activity。就像接下来讨论的Activity生命周期一样,Android系统为你管理Activity ,所以你没必要关闭你的Activity。用这些方法会产生不好的用户体验,除了你不想用户再回到这个Activity实例中来。
管理Activity的生命周期
通过实现回调方法是一个强大而灵活的管理应用程序。Activity的生命周期会通过任务、堆栈直接影响到其他Activity。
Activity在本质上存在三种状态:
Resumed
它处理屏幕的前台,并成为用户焦点(此状态有时也简称为“运行”)。
Paused
另一个Activity回到前台并成为焦点,这次仍是可见的,即另一个Activity在顶部可见,但它仅是部分透明的或并不覆盖整个屏幕。被暂停的Activity是活着的(Activity 对象保留在内存中,它保持所有状态和成员信息,但是连接着窗口管理器),但在内存极低时也会被杀死。
Stopped
一个Activity被另一个所覆盖(这个Activity存在于后台中)。被停止的Activity仍然是活着的(Activity对象保留在内存中,它保持所有状态和成员信息,但是没有连接到窗口管理器)。然而,对于用户它是不可见的,同时其它地方需要内存系统也会杀死它。
如果一个Activity暂时或停止了,系统可以通过调用finish()方法或干脆杀死进程的方法来结束它。当它被再一次打开(被关闭或杀死)时,则必须创建一个全新的。
实现生命周期回调方法
当它转换如上所述的各种状态时,会被通知调用相应回调方法。所有的回调方法都可以重写,来做一些当各种状态切换时的工作。下面的示例Activity里包括基本的每一个生命周期回调方法:
public class ExampleActivity extends Activity {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(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.onPause();
// 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.
}
}
注:在父类方法实现之后,这些生命周期回调方法的才能实现并工作,就像上面的例子一样。
总的来说,这些方法定义的Activity的整个生命周期。通过实现上述方法,你可以监控Activity生命周期这三个嵌套的循环。
Activity的整个生存周期存在onCreate()和onDestroy()之间。你的Activity应该设置全局状态(如定义布局)在onCreate()方法中,在onDestroy()方法中释放所有剩余资源。举例,如果你的Activity有一个后台进程,在进行网络下数据的操作,它可能在onCreate()方法里创建一个线程,然后在onDestroy()方法中停止它。
可见的Activity活动情况介于onStart()和onStop()方法之间。在这两上方法中间,用户可以看见Activity的活动并和它交互。举例,当一个新的Activity启动并且这个Activity不再显示的时候会调用onStop()方法。在这两种方法之间,你可以展示必要的给用户看的资源。举例,你可以在onStart()方法里注册一个BroadcastReceiver来监控UI的变化,然后当用户不再看到你所展示的内容时,就在onStop()方法里注销它。在Activity的生命周期中,随着Activity对用户可见或隐藏,系统可能会多次调用onStart()和onStop()方法。
前台展示Activity活动情况介于onResume()和onPause()方法之间。在这两个方法中间,Activity会出现在所有Activity的最前面,并具有用户输入焦点。一个Activity可以频繁的在前台转变,举例,在设备准备休眠或一个dialog出现时,系统会调用onPause()方法。因为这个状态可以被经常转换,所以这两个方法必须是轻量的,用于避免转变时让用户等待的情况。
图1说明了一个Activity可能需要在不同状态转换的循环和路径,这些长方形代表Activity切换时执行操作所实现相应的回调方法。
Table 1. 生命周期所有回调方法的总结。
Method |
Description |
Killable after? |
后一个 |
onCreate() |
当Activity第一次被创建时调用。 这里是你所有静态操作的地方,创建views,为list绑定数据等等。这个Activity方法会传递一个包含上个状态的bundle对象,如果这个状态被保存(稍后参Saving Activity State)。 之后经常执紧跟onStart()方法。 |
No |
onStart() |
|
onRestart() |
当Activity被停止时,再启动时执行,后面经常紧跟跟 onStart()方法。 |
No |
onStart() |
onStart() |
仅在Activity出现在用户前执行,经常紧 onResume()方法,如果出现在在前台,或者onStop()方法,如果它被隐藏。 |
No |
onResume() or onStop() |
|
onResume() |
在与用户交互前调用,此时Activity是位于Activity堆栈 的顶端,伴随着用户的输入状态。 经常紧onPause(). |
No |
onPause() |
onPause() |
系统打算打开另一个Activity时,调用此方法。 这个方法主要用来保存未 保存的数据改变,停止特效,以及其它会占用CPU的操作。这里应该执行 一些快速的操作,因为只有它完成,下一个Activity才会 被打开经常紧跟 onResume()方法,如果出现在在前台,或者onStop()方法,如果它被隐藏。. |
Yes |
onResume() or onStop() |
onStop() |
在Activity不再可见时调用。在Activity将被销毁或另一 个Activity(一个存在或新的)已经被打开并覆盖。 跟随onRestart() ,如果Activity重新返回与用户进行交互;或onDestroy(),如果你的Activity将要消失。 |
Yes |
onRestart() or onDestroy() |
onDestroy() |
当Activity被销毁时调用。这是Activity收到的最后一个回调。 在Activity被关 闭(或调用finish()方法)或系统为节省空间时会关才这个Activity实例。你可以 区分一下finish和isFinishing方法。 |
Yes |
nothing |
被标记“killable”标签的列,表明在方法返回时,控制Activity的进程可以随意关闭,不用执行Activity的另一行代码。
被标记“Yes”的三种方法(onPause(),onStop()和onDestroy()),因为一旦Activity被创建,onPause()方法是三个中的第一个,onPause()是在进程可以被杀死前的最后一个方法,如果系统必须紧急恢复内存,然后是onStop()和onDestroy()方法。因此,你可以用onPause()方法来写关键持久性数据(如用户编辑)存储。但是,你应选择什么样的信息必须在onPause()里操作,因为任何阻塞程序都会影响到下个Activity和降低用户体验。
被标记“No”标签的列,保护控制Activity的进程不被关闭,当相关方法被调用时。因此,一个Activity在onPause()方法时可以被杀死,在onResume()被调用时返回。这个Activity不会被杀死,直到onPause()方法被调用。
注释:表1中一个Activity如果不被故意杀死,也会被系统杀死,但这种情况会在没有其他资源的极端情况下发生。关于何时Activity被杀死会在进程和线程文档详细介绍。
保存Activity的状态
在Activity生命周期简要中有提到,当Activity暂停或停止时,Activity的状态会被保存。因为此时Activity的对象仍然在内存中被保存,所有关于它的成员变量和状态的信息都还存在。因此,用户所做任何与Activity有关的改变都会被保存,然后当它恢复时,这些信息仍然可用。
但是,系统为了恢复内存会销毁一个Activity,它被销毁后,系统不能使用它的状态信息,简单的进行恢复。当然,用户不会意识到系统销毁了它,因为它会被重新创建,呈现预想中以前的界面。这种情况下,你可以保证一些重要的信息如Activity的状态,通过实现附加的回调方法onSaveInstanceState()来保存状态信息。
系统会在Activity被破坏前调用onSaveInstanceState()。系统运行这个方法会用一个bundle对象来保存一对名值对,使用putString()或putInt()方法。然后,如果系统杀死应用进程并返回你的Activity,系统会重新创建Activity,会在onCreate()和onRestoreInstanceState()方法返回一个bundle对象。使用其中一种方法,你可以准确的使用bundle对象保存状态和恢复状态。如果没状态信息被保存,传递的bundle对象为空(当Activity第一次被创建的时候)。
图2,两种Activity返回用户焦点的方式:一种Activity被销毁,然后重新创建,Activity必须重新保存先前的状态,另一种Activity停止时,然后恢复,状态保持不变。
注释:很显然onSaveInstanceState()会在Activity销毁前被调用,因为有很多情况是不必要保存状态的(比如用户点击back按钮离开当前Activity,因为用户显式的关闭了它)。如果系统调用onSaveInstanceState(),它会在onStop()甚至onPause()前执行。
但是,即使你什么也没做,也没有实现onSaveInstanceState()方法,一些Activity的状态也会在Activity默认方法里保存。具体来说,默认的实现方法会为每个View在布局里调用onSaveInstanceState()方法,这允许每个View提供各自的信息然后保存。几乎Android Framework里所有的widget都会实现这个方法,一些UI显而易见的改变会在Activity重建时自动保存。举例,EditText会保存用户输入的内容,CheckBox会保存它是否被选中。你唯一需要做的是为每个widget提供一个独一无二的ID(使用android:id属性)去保存状态。如果一个widget没一个id,那么系统不会保存它的状态。
你也可以明确的停用布局里的View保存状态,通过设置android:saveEnabled属性为false,或者调用setSaveEnabled()方法。通常,你最好不要这么做;但如果你真的想重新保存其状态的话,你可以这么做。
虽然onSaveInstanceState()方法的默认实现会保存Activity UI的相关有用信息,你仍需要重写它来保存更多信息。举例,你也许需要保存Activity生命周期中改变的值(可能恢复UI保存的值,但默认这些UI的值不会被保存)。
因为onSaveInstanceState()方法的默认实现会帮助保存UI的状态,如果你重写这个方法来保存更多信息,你仍需要先调用其父类。同样的,你仍需要调用onRestoreInstanceState()方法的父实现方法来重写,因为默认实现会恢复View的各种状态。
注释:因为onSaveInstanceState()不能保证被调用,你应使用它来保存一些过渡数据(UI的状态),而不要用来保存持久化数据。相反,当用户离开Activity时,你应使用onPause()来保存持久化数据(如应保存在数据库里的数据)。
一个检测你的应用程序能否保存状态信息的方法是,简单的旋转设备使屏幕转动。当屏幕方向改变,系统会销毁并重建Activity,来使用为屏幕配置的新资源。仅仅出于这个原因,你的Activity在重建时完全恢复它的状态,因为用户在使用程序时会经常的旋转屏幕。
处理配置更改
一些设备配置可以在运行期间改变(比如屏幕方向,键盘可用性以及语言)。当这样一个改变发生时,Android会重建这个运行的Activity(Android会调用onDestroy(),然后立即调用onCreate())。这种行为的目的为帮助你的应用自动适应新配置,并加载相应提供的资源(如不同屏幕的不同布局和大小)。
如果你正确的设计你的Activity,去处理由于屏幕方向改变或重置Activity如上的状态而重新启动,你应用的生命周期中会更有弹性的来处理一些突发事件。
在上面的讨论中,最好使用onSaveInstanceState()和onRestoreInstanceState()(或onCreate())来保存和恢复来处理这样一个重启事件。
有关更多运行机制期间配置改变和处理这些问题的信息,请参见处理运行时的更改文档。
协调活动
当一个Activity启动另外一个,他们都在经历生命周期的切换。第一个Activity会暂停尔后停止(不过,如果在后台仍能运行(内存允许)则不会执行onStop()方法),而另一个则被创建。这种情况下,这些Activity共享存在光盘或其他地方的数据。你需要清楚第一个Activity在第二个被创建前不会完全停止。相反,第一个被停止和第二个被启动的进程是重叠的。
生命周期的回调方法定义的非常好,特别是当两个Activity在同一进程中,其中一个启动另外一个。下面是Activity A启动Activity B的操作顺序。
首先Activity A的onPause()方法执行
然后Activity B顺序执行onCreate(),onStart()和onResume()方法(现在Activity B获得用户焦点)
再之后,如果Activity A不再屏幕上显示,那它的onStop()方法就会执行。
这个可预知的生命周期回调方法允许你管理一个Activity向另一个Activity切换的信息。举例,如果你写一个数据库,并想让后面的Activity也能用到,你要写在onPause()方法里,而不是onStop()方法里。
Actvity的翻译已经告一段落,大家看懂了没有呢,后面我会单独写一些Activity的精要部分,供初学者参考。