Activity是可以给用户提供交互操作的程序组件,例如打电话,拍照,发送邮件,抑或者是显示地图。通常窗口会填满屏幕,但是也可以做到比屏幕小或者是悬浮在窗口顶部。
App通常由多个Activities组成,它们之间支持相互跳转。一般情况下,每个Activity在应用中都是特别的,就好像 主Activity一样,主activity是应用第一个Activity,其他Activity可以通过其他操作启动。一个新的Activity的启动,那么旧Activity就会被停止,但是系统会保存这些activity至栈中。当一个新的activity启动,activity被放入栈中并且操作获得焦点,当用户完成当前activity操作或者回退操作时,那activity将会出栈中取出,之前入栈的activity 将会被再次启动。
当一个Activity暂停是因为一个新的Activity的启动,通过Activity的生命周期回调方法通知改变状态。Activity通过系统的回调方法,去创建,销毁,停止,恢复它。当Activity停止时,对象需要被释放,例如网络操作或者是数据库操作。当Activity恢复时,你可以重新恢复获得所需资源和输入操作。这些状态转换都是生命周期的一部分。
这篇博客的其他部分会探讨如何构建和使用Activity的知识。包括activity的生命周期探讨,可以帮助你管理各种Activity状态的转换。
创建一个Activity
要创建一个activity,就需要创建一个Activity的子类(或者已经存在的子类)。在你的子类中,需要执行回调方法,来实现在其生命周期的各个状态之间的活动转换。例如Activity的创建,停止,恢复,或者是销毁,下面是两个非常重要的回调方法:
OnCreate()
这个方法是必须要去实现的,当Activity被创建的时候,系统会调用这个方法,在这个方法中,我们可以去初始化一些重要组成部分。重中之重的是,你需要调用setContentView()方法去定义一个布局给这个Activity
OnPause()
当离开当前Activity时,会调用这个方法,注意:离开Activity的意思不仅仅是指:销毁了Activity了。(可以是简单的覆盖一个Actvity时也会调用)
Activity还有其他几个生命周期回调方法,我们应该使用它们,以达到活动之间流畅的用户体验,同时处理突发中断引起你的活动被停止,甚至破坏。所有的生命周期回调方法都在后面讨论。
实现用户接口
一个Activity的用户界面是由来自视图类的视图对象的层次结构提供的。每个视图在活动窗口中控制一个特定的矩形空间,并且可以响应用户交互。例如,一个按钮,当用户触摸到它时,它就会响应一个动作。
Android提供了一些已有的View,我们可以用这些View来设计和组织我们想要的界面。”部件”是一个可视化的(互动)的屏幕元素,如按钮、文本显示控件、复选框,又或者只是个图片。”Layouts“属于ViewGroup,可以提供一个独特的布局,如线性布局,网格布局,或相对布局。你还可以继承View和ViewGroup类(或现有的子类)来创建自己的小部件和布局,并把它们应用到你的Activity布局。
最常见的方法是在XML布局文件中构建我们的布局,并且将其保存在应用程序的路径下。通过这种方式,可以在源代码中保持用户界面的设计,在此布局中来定义活动的行为。我们通过setContentView()来给Activity设定布局,设定方法是通过原先设定的ID去指向布局文件。不过,我们也可以在Activity的代码中新建View。
有关创建用户界面的内容,请查看用户界面文档。
在配置文件中声明Activity
想要系统可以访问,就需要在配置文件中声明这个Activity。打开你的配置文件,声明方式如下:
<manifest ... >
<application ... >
<activity android:name=".ExampleActivity" />
...
</application ... >
...
</manifest >
这里还有几个其他属性,你可以定义这些属性,如活动的label,图标,或主题,设定主题的用户界面。安卓:名称属性是它指定活动的类名称的唯一属性。一旦你发布你的应用程序,你不应该更改这个名称,因为如果你这样做,你可能会破坏一些功能,如应用程序快捷方式。
使用意图过滤器
元素也可以使用<意图筛选器>元素指定各种意图筛选器,以便声明其他应用程序组件如何激活它。
当你使用Android SDK创建一个新的应用,短的活动,会自动为你创建一个intent过滤器包括声明活动响应的“主体”作用,应该放在“启动”的范畴。意图过滤器如下:
<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>
元素指定了该应用程序的“主”入口点。元素指定此活动应在系统的应用程序启动程序中列出(允许用户启动此项活动)。
如果你想让你的应用程序是自包含的,不允许其他应用程序来激活它的Activity,那么你不需要任何其他的意图过滤器。
然而,如果你想让你的活动响应的隐式意图从其他应用程序交付,那么你必须为你的活动定义额外的意图过滤器。对于要响应的每个类型的意图,写一个<意图筛选器>,其中包含一个元素和可选的,元素和/或<数据>元素。这些元素指定了你的活动可以响应的意图类型。
启动Activity
你可以通过调用startActvity()来启动另外的Activity, 在Intent对象中描述需要启动的Activity。Intent指定要启动或描述要执行的动作类型的确切活动(和系统为你选择适当的活动,这可能是来自不同的应用程序)。一个意图也可以携带少量的数据。
当在你的应用程序中工作时,你通常需要简单的启动一个已知的Activity。你可以通过创建一个意图,明确定义你想要开始的活动,使用这个类名称。例如,这里有一个活动启动另一个活动叫signinactivity:
Intent intent = new Intent(this, SignInActivity.class);
startActivity(intent);
然而,您的应用程序可能还需要执行一些操作,如发送电子邮件、文本消息或状态更新,使用来自您的活动的数据。在这种情况下,您的应用程序可能没有它自己的活动来执行这样的操作,因此您可以使用其他应用程序提供的活动来进行操作,该设备可以为您执行该操作。这是intent真正有用的地方你可以创建一个意图,描述一个你想执行的动作,系统会从另一个应用程序的适当的活动。如果有多个可以处理该意图的活动,则用户可以选择使用哪个。例如,如果您希望允许用户发送电子邮件,您可以创建以下意图:
Intent intent = new Intent(Intent.ACTION_SEND);
intent.putExtra(Intent.EXTRA_EMAIL, recipientArray);
startActivity(intent);
这里extra_email额外添加的意图是电子邮件地址。当一个电子邮件应用程序响应这个意图时,它读取在“to”字段的电子邮件地址。在这种情况下,电子邮件应用程序的活动开始,并且去完成邮件的发送,最后你的Activity恢复。
开启一个带result的Activity
有时候,你可能有一个带result的Activity。在这种情况下,通过调用startactivityforresult()启动活动(而不是startactivity())。然后接收来自后续Activity的result,实现onactivityresult()回调方法。
例如,也许你希望用户从手机通讯录中选择联系人,你的Activity可以利用result这些信息做一些事情。如下:
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()方法,用来处理Activity的result。第一个条件检查请求是否成功,如果是的话,那么返回Result_OK
一个ContentResolver执行对内容提供商的查询,并返回一个Cursor,允许被读的数据。更多信息,参见内容提供者文档。
销毁Activity
你可以通过finish()方法,关掉Activity。调用finishactivity()方法,你也可以关闭一个独立的Actvity。
注意:在大多数情况下,你不应该使用这些方法来完成一个Activity。正如下面的关于Activity生命周期的章节讨论的,安卓系统为你管理Activity的生命周期,所以你不需要finish()你自己的活动。调用这些方法可能会对预期的用户体验产生不利的影响。
管理Activity的生命周期
通过实现回调方法来管理Activity的生命周期,对于开发一个强大且灵活的应用程序至关重要。活动的生命周期直接影响其与其他Activity、任务和后台的关联。
一个Activity有三个状态:
Resumed:
该Activity是在屏幕的顶部,并有焦点。(有时也被称为“运行”状态。)
Paused:
被另一个Activity覆盖,另一个Activity是在屏幕顶部且有焦点,但该Activity仍然是可见的。也就是说,另一个Activity是在该Activity的顶部暂停的Activity是依旧存活的(Activity对象保留在内存中,它维护所有状态和成员信息,并保持连接到窗口管理器),但可以在极低的内存情况下被系统杀死。
Stoped:
Activity完全被另一种活动所掩盖(当前Activity是现在的“背景”)。停止活动还活着(活动对象保留在内存中,它保持所有状态和成员信息,但不连接到窗口管理器)。然而,它不再是可见的用户,它可以被系统销毁。
如果Activity被暂停或停止时,系统通过要求它完成(调用它的finish()法)来从内存中删除它,或简单地杀死它的进程。当活动再次打开(完成或销毁)时,它必须被创建。
实现生命周期回调方法
当一个Activity过渡到上面描述的不同的状态时,所有的回调方法都是hook,当你的活动状态发生改变时,你可以重写来做适当的工作。如下:
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的整个生命周期发生oncreate()至ondestroy()。你的Activity应该执行设置“全局”的状态(如定义布局)在oncreate(),和ondestroy()释放所有剩余资源。例如,如果你的Activity有一个线程在后台运行,从网络上下载数据,它可能会创建线程oncreate()然后停止线程ondestroy()。
一个Activity的可视生命发生onstart()至onstop()。在此期间,用户可以看到活动屏幕上的活动,并与之互动。例如,onstop()称当一个新的Activity开始,这是不可见的。在这两者之间,你可以保持需要的资源,以显示该用户的Activity。例如,你可以在onstart()登记一个BroadcastReceiver来监视影响你的用户界面的变化,和注销它onstop()当用户无法看到你的显示。该系统可以称onstart()和onstop()多次Activity的整个生命周期过程中,作为活动的交替是可见的和隐藏的用户。
一个Activity的前台生命发生onresume()至onpause()。在此期间,Activity是在屏幕上的所有其他活动,并具有用户输入焦点。
下图说明了这些循环和路径的活动可能采取的状态。矩形代表在状态之间的活动转换时,可以实现操作的回调方法。
生命周期回调方法列出在表中,更详细的描述生命周期,并将每一个在Actviity的整个生命周期中定位。如下:
保存Activity状态
管理活动生命周期的介绍中,提到当一个Activity暂停或停止时,活动的状态被保留。这是真实的,因为在暂停或停止所有有关其成员和当前状态的所有信息的时候,活动对象仍然在内存中进行。因此,在活动中的用户所做的任何更改都将保留,以便当活动返回到前台(当它“恢复”)时,这些更改仍在那里。
然而,当系统破坏一个活动,以便恢复内存,活动对象被破坏,所以系统不能简单地恢复它的状态不变。相反,系统必须重新创建活动对象,如果用户导航回到它。然而,用户不知道系统销毁活动并重新创建它,因此,可能希望活动要完全一样。在这种情况下,你可以确保重要活动的相关信息是通过实施一个附加的方法,允许你保存你的活动的状态信息保存:onsaveinstancestate()。
系统调用onsaveinstancestate()保存用户中断操作前的状态。系统通过这一方法,你能保存活动的状态信息作为名称值对,使用方法如putstring()和putint()。然后,如果系统杀死你的应用程序进程和用户导航回到你的活动,系统会重新创建活动并通过oncreate()和onrestoreinstancestate()使用这些方法中的一个恢复之前的状态。你可以提取你的保存状态,并恢复Activity状态。如果没有状态信息来恢复,那么返回参数将会是空的(第一次创建活动时的情况下参数是空的)。
然而,即使你什么也不做,不执行onsaveinstancestate(),某些活动状态也是会由onsaveinstancestate()活动类的默认实现恢复。具体来说,默认的实现需要布局中的每个视图对应的onsaveinstancestate()方法,允许每个视图提供关于自身的信息对应保存。在Android框架中,几乎每一个部件合理地实现这个方法,这样对用户界面的任何可见的变化都是可以自动保存的,并且可以恢复Activity被重新创建时的状态。
因为onsaveinstancestate()默认的实现有助于同步UI的状态,重写这些方法,可以节省额外的保存状态信息,在做任何操作前,onsaveinstancestate()调用实现。然后你重写onrestoreinstancestate(),就可以实现还原视图状态。
注:onsaveinstancestate()并不能保证在任何情况下都可以做到状态的恢复,这只能用来记录Activity的瞬态,不应该用它来存储持久化数据。正确的做法是:当用户离开活动时,使用onpause()存储持久化数据(如数据应保存到数据库)。
有一个很好的方法,可以来测试你的应用程序的恢复状态的能力:简单地旋转设备,使屏幕方向的变化。当屏幕的方向改变时,系统销毁并重新创建Activity,这是非常重要的,你的活动完全恢复状态时,它是重现的,因为用户在使用应用时经常旋转屏幕。
处理配置的变化
一些设备配置可以在运行时改变(如屏幕方向,软键盘)。当发生这样的变化时,Android重新运行的Activity(系统调用ondestroy(),然后立即调用oncreate())。这种行为的目的是帮助您的应用程序的自动加载与替代资源,适应设备的变化,
如果你正确地设计你的Activity来处理一个重新启动,当屏幕方向等状况改变,你的应用程序将更灵活处理这种情况。
最好的解决方式是保存和恢复你的活动中使用onsaveinstancestate(), onrestoreinstancestate()(或oncreate()),如在上面有提到)。
协调活动
当一个Activity开始至另一个Activity,这个过程就是生命周期状态的转变。第一个活动销毁和暂停(它不是已销毁,仍然是可见的背景),重要的是要了解,第一个Activity是不完全停止的。相反,启动第二个Activity的过程中,是第一个Activity重叠的过程。
以上是Android官方文档Activity部分的简单翻译,勿喷~