您的位置:首页 > 移动开发 > Android开发

Android高级开发第二讲--Android中API翻译之Activity

2012-12-31 19:28 246 查看
博客出自: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的精要部分,供初学者参考。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: