Activity

一、Activity创建、启动和关闭
  1.创建 Activity
  2.在清单文件中声明
  3.启动
  4.结束
二、Activity生命周期
三、Activity处理配置变更等问题


Activity创建、启动和关闭

Activity是一个应用组件,用户可与其提供的屏幕进行交互,以执行拨打电话、拍摄照片、发送电子邮件或查看地图等操作。 每个Activity都会获得一个用于绘制其用户界面的窗口。窗口通常会充满屏幕,但也可小于屏幕并浮动在其他窗口之上。

1.创建Activity

要创建Activity,必须先创建Activity的子类(或使用其现有子类)。需要在子类中实现Activity在其生命周期的各种状态之间转变时(例如创建Activity、停止Activity、恢复Activity或销毁Activity时)系统调用的回调方法。 两个最重要的回调方法是:

  • onCreate(),必须实现此方法,系统会在创建Activity时调用此方法。在实现该方法时,应该初始化Activity的必需组件。 最重要的是,必须在此方法内调用setContentView(),以定义Activity用户界面的布局。
  • onPause(),系统将此方法作为用户离开Activity的第一个信号(但并不总是意味着 Activity 会被销毁)进行调用。 在此方法内,通常应该确认当前用户会话结束后仍然有效的任何更改(因为用户可能不会返回)。
2.在清单文件中声明Activity

(1)在清单文件中声明了Activity,系统才能访问它。 要声明Activity,则需打开清单文件,并将 <activity/> 元素添加为<application/> 元素的子项。例如:

<manifest ... >
  <application ... >
      <activity android:name=".ExampleActivity" />
      ...
  </application ... >
  ...
</manifest > 

您还可以在此元素中加入几个其他特性,以定义Activity标签、Activity图标或风格主题等用于设置Activity UI风格的属性。android:name特性是唯一的必需特性—它指定。
(2)使用 Intent 过滤器
  元素 <activity/> 还可指定各种Intent过滤器—使用<Intent-filter/>元素—以声明其他应用组件激活它的方法。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>

<action>元素指定这是应用的“主”入口点。<category/>元素指定此 Activity应列入系统的应用启动器内(以便用户启动该 Activity)。
  如果打算让应用成为独立应用,不允许其他应用激活其Activity,则不需要任何其他Intent过滤器。 正如前例所示,只应有一个Activity具有“main”和“launcher”
类别。 如果不想提供给其他应用的Activity不应有任何Intent过滤器,可以利用显式 Intent 自行启动它们。不过,如果想让 Activity对衍生自其他应用(以及您的自有应用)的隐式Intent作出响应,则必须为Activity定义其他 Intent 过滤器。 对于您想要作出响应的每一个 Intent类型,都必须加入相应的<Intent-filter/>,其中包括一个<action/>元素,还可选择性地包括一个<category/>元素和/或一个<data/>元素。这些元素指定您的Activity可以响应的Intent类型。

3.启动 Activity

(1)调用startActivity(),并将其传给想启动Activity的Intent来启动另一个Activity
Intent对象会指定您想启动的具体Activity或描述您想执行的操作类型(系统会为您选择合适的Activity,甚至是来自其他应用的Activity)。 Intent 对象还可能携带少量供所启动Activity使用的数据。
例如,可以通过以下代码让一个Activity启动另一个已知为SignInActivity:

Intent intent = new Intent(this, SignInActivity.class);
startActivity(intent);

不过,您的应用可能还需要利用您的Activity数据执行某项操作,例如发送电子邮件、短信或状态更新。 在这种情况下,您的应用自身可能不具有执行此类操作所需的Activity,因此您可以改为利用设备上其他应用提供的Activity为您执行这些操作。 这便是Intent对象的真正价值所在—您可以创建一个Intent对象,对您想执行的操作进行描述,系统会从其他应用启动相应的Activity。 如果有多个Activity可以处理Intent,则用户可以选择要使用哪一个。 例如,如果您想允许用户发送电子邮件,可以创建以下Intent对象:

Intent intent = new Intent(Intent.ACTION_SEND);
intent.putExtra(Intent.EXTRA_EMAIL, recipientArray);
startActivity(intent); 

添加到Intent中的EXTRA_EMAIL extra是一个字符串数组,其中包含应将电子邮件发送到的电子邮件地址。 当电子邮件应用响应此Intent时,它会读取extra中提供的字符串数组,并将它们放入电子邮件撰写窗体的“收件人”字段。 在这种情况下,电子邮件应用的Activity启动,并且当用户完成操作时,您的Activity会恢复执行。
(2)调用 [startActivityForResult()](https://developer.android.com/reference/android/app/Activity.html#startActivityForResult(android.content.Intent, int)),启动 Activity 以获得结果,重写 [onActivityResult()](https://developer.android.com/reference/android/app/Activity.html#onActivityResult(int, int, android.content.Intent))方法,就可以得到被启动Activity的返回结果。
干货:彻底搞懂 startActivityForResult 在 FragmentActivity和 Fragment中的异同
例:您可能希望用户选取其中一位联系人,以便您的Activity对该联系人中的信息执行某项操作。 代码实例如下:

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...
        }
    }
} 

上例中在处理Activity结果时应该在onActivityResult() 方法中使用的基本逻辑。第一个条件检查请求是否成功(如果成功,则resultCode 将为 RESULT_OK)以及此结果响应的请求是否已知 — 在此情况下,requestCode与随startActivityForResult() 发送的第二个参数匹配。 代码通过查询 Intent 中返回的数据(data 参数)从该处开始处理Activity结果。
实际情况是,ContentResolver 对一个内容提供程序执行查询,后者返回一个 Cursor,让查询的数据能够被读取。如需了解详细信息,参阅内容提供程序
(3)由以上两种方式可看到启动Activity时都会传入相应的Itent,根据Intent的不同又可以将Activity的启动方式分为显示启动和隐式启动

  • 显示启动:按名称(完全限定类名)指定要启动的组件。通常在自己的应用中使用显式Intent来启动组件,这是因为此时知道要启动的 Activity 或服务的类名。例如,启动新Activity以响应用户操作,或者启动服务以在后台下载文件。如果您没有为Activity声明任何Intent过滤器,则Activity只能通过显式Intent启动。
  • 隐式启动:不会指定特定的组件,而是声明要执行的常规操作,配置Intent的action、data、category等,从而允许其他应用中的组件来处理它。例如,如需在地图上向用户显示位置,则可以使用隐式Intent,请求另一具有此功能的应用在地图上显示指定的位置。
    隐式Intent相对于显示Intent具有以下优势:
  • 可以通过url传web数据(存在数据泄漏)
  • 可以实现解耦(如Activity之前的依赖)
  • 可以在一个Application启动另一个Application
  • 可以通过配置Intent过滤器,使多个应用响应,然后根据用户选择启动具体的应用
4.结束 Activity

调用Activity的finish()方法来结束该Activity,还可以通过调用finishActivity()结束在之前启动的另一个Activity。
  注意:在大多数情况下,不应使用这些方法显式结束 Activity,Android系统会为您管理Activity的生命周期,因此您无需完成自己的 Activity。 调用这些方法可能对预期的用户体验产生不良影响,因此只应在您确实不想让用户返回此Activity实例时使用。

Activity生命周期

1.Activity的三种存在状态
  • 已继续:此Activity位于屏幕前台并具有用户焦点。(有时也将此状态称作“运行中”)
  • 已暂停:此Activity失去焦点,另一个Activity位于屏幕前台并具有用户焦点,但此Activity仍可见。也就是说,另一个Activity显示在此Activity上方,该Activity部分透明或未覆盖整个屏幕(例如跳转到一个Dialog Activity,非Dialog)。已暂停的Activity处于完全Activity 状态(Activity 对象保留在内存中,它保留了所有状态和成员信息,并与窗口管理器保持连接),但在内存极度不足的情况下,可能会被系统终止。
  • 已停止:该 Activity被另一个Activity完全遮盖(该Activity目前位于“后台”)。 已停止的Activity同样仍处于Activity状态(Activity对象保留在内存中,它保留了所有状态和成员信息,但未与窗口管理器连接)。 不过,它对用户不再可见,在他处需要内存时可能会被系统终止。


    Activity 的存在状态

    如果Activity处于暂停或停止状态,系统可调用其 finish() 方法或直接终止其进程,将其从内存中删除。(将其结束或终止后)再次打开Activity时,必须重建。

2.Activity生命周期图
Activity的生命周期

对 Activity生命周期图中的主要方法介绍如下:
(1)onCreate()

  • 初始化,准备数据,创建view setContentView、findViewById
  • 一生一次
  • 不可见
  • 不适合动画,不适合耗时,影响用户看到界面的时间

(2)onStart()

  • 初始化或恢复中,onCreate或onRestart之后,和onStop是一对儿
  • 多次调用,Activity即将可见

(3)onResume()

  • 初始化或恢复中,恢复activity时一定会调用,和onPause是一对儿
  • 多次调用,可以交互,Activitty 进入active 状态
  • 执行动画、唤起相机、刷新数据

(4)onPause()

  • 失去焦点、不可触摸,所以和onResume是一对儿
  • 可见
  • 下一个Activity可以进行初始化工作

(5)onStop()

  • 完全不可见,进入后台

(6)onDestory()

  • go die

(7)onPause() vs onStop()

  • 不可操作 vs 不可见

其中,onCreate()、onStart()、onResume()可用于初始化,onPause()、onStop()、onDestory()不可用于初始化。

(8)Activity存在状态与生命周期各个方法对应关系如图3所示:


图3 Activity存在状态与生命周期各方法对应关系

例:当一个 Activity A启动另一个 ActivityB时,各自的生命周期转变情况

  • Activity A的onPause()方法执行
  • Activity B的onCreate()、onStart() 和 onResume()方法依次执行(Activity B现在具有用户焦点)
  • 然后,如果Activity A在屏幕上不再可见,则其onStop()方法执行Activity A暂停并停止(但如果它在后台仍然可见,则不会停止)时,系统会创建 ActivityB。 如果这些Activity共用保存到磁盘或其他地方的数据,必须了解的是,在创建第Activity B前,Activity A不会完全停止。更确切地说,启动Activity B的过程与停止Activity A的过程存在重叠。

Activity A暂停并停止(但如果它在后台仍然可见,则不会停止)时,系统会创建Activity B。 如果这些Activity共用保存到磁盘或其他地方的数据,必须了解的是,在创建第Activity B前,Activity A不会完全停止。更确切地说,启动 Activity B的过程与停止 Activity A的过程存在重叠。

Activity状态保存与数据保存

1.Activity状态保存

当Activity暂停或停止时,Activity的状态会得到保留。 因为当Activity暂停或停止时,Activity对象仍保留在内存中 — 有关其成员和当前状态的所有信息仍处于Activity状态。 因此,用户在Activity内所做的任何更改都会得到保留,这样一来,当Activity返回前台(当它“继续”)时,这些更改仍然存在。不过,当系统为了恢复内存而销毁某项Activity时,Activity对象也会被销毁,因此系统在继续Activity时根本无法让其状态保持完好,而是必须在用户返回Activity时重建Activity对象。但用户并不知道系统销毁 Activity 后又对其进行了重建,因此他们很可能认为Activity状态毫无变化。
  在这种情况下,您可以使用onSaveInstanceState()回调方法对有关 Activity 状态的信息进行保存,以确保有关 Activity 状态的重要信息得到保留。系统会先调用 onSaveInstanceState(),然后再使 Activity 变得易于销毁,系统会向该方法传递一个 Bundle,您可以在其中使用 putString() 和putInt() 等方法以名称-值对形式保存有关 Activity 状态的信息。然后,如果系统终止您的应用进程,并且用户返回您的 Activity,则系统会重建该 Activity,并将 Bundle 同时传递给 onCreate() 和 onRestoreInstanceState()。您可以使用上述任一方法从 Bundle 提取您保存的状态并恢复该 Activity 状态。如果没有状态信息需要恢复,则传递给您的 Bundle 是空值(如果是首次创建该 Activity,就会出现这种情况)。
  由于onSaveInstanceState 的默认实现有助于保存 UI 的状态, 因此如果您为了保存更多状态信息而重写该方法,应始终先调用 onSaveInstanceState 的超类实现,然后再执行任何操作。同样,如果您替代onRestoreInstanceState 方法,也应调用它的超类实现,以便默认实现能够恢复视图状态。
例:模拟调用onSaveInstanceState()、onRestoreInstanceState()场景
(1)运行你的程序,当程序打开时,按HOME键,这时系统会调用onSaveInstanceState方法,注意:这个方法的调用是系统决定的,不是软件或其他什么因素,系统觉得有可能在某个时间因内存不足等因素而Kill掉你,所以给你个机会让你现在先利用这个方法保存下数据,所以调用onSaveInstanceState()。
(2)一般情况下,即使你在onSaveInstanceState保存了数据,在系统没Kill掉程序的情况下,你再回到刚关闭的界面,你也会感觉刚才调用onSaveInstanceState方法保存的数据没什么作用,只有在系统kill掉程序的情况下,再回到刚关闭的界面,回调了onRestoreInstanceState方法,这时onSaveInstanceState方法保存的数据,才发挥真正的作用,如何重现这种场景呢,利用DDMS替系统干这件坏事,kill掉你的程序:在按下HOME键后,系统已经调用你的onSaveInstanceState方法,打开DDMS找到你的程序进程,stop你的进程,再打开程序!
注意:无法保证系统会在销毁您的Activity前调用 onSaveInstanceState(),因为存在不需要保存状态的情况(例如用户使用“返回” 按钮离开您的Activity时,因为用户的行为是在显式关闭 Activity)。 如果系统调用 onSaveInstanceState(),它会在调用 onStop() 之前,并且可能会在调用onPause() 之前进行调用。

2.Activity数据保存问题

(1)由于无法保证系统会调用 onSaveInstanceState(),因此您只应利用它来记录Activity的瞬态(UI 的状态)—切勿使用它来存储持久性数据,而应使用onPause()在用户离开Activity后保存持久性数据(如应保存到数据库的数据)。如果您必须在第一个Activity停止时向数据库写入数据,以便下一个 Activity 能够读取该数据,则应在onPause()而不是onStop() 执行期间向数据库写入数据。
(2)如果从Activity A通过Itent携带数据打开Activity B,Activity B界面被系统kill后,重新创建Activity B之后,之前携带的数据能被还原,但该界面被kill之前对传递过来的数据作任何修改都作废;
(3)B界面→C界面,C界面 finish后,系统重建B界面,依然能得到C界面回传的数据。例如Activity B打开Activity C,用 startActivityForResult()方法要求Activity C finish时回传数据到Activity B,跳转到Activity C后Activity B被kill了,当系统在Activity C finish后重建Activity B,onActivityResult()方法依然能收到Activity C传回的数据;
(4)从A界面-->B界面-->C界面,用A界面通过Intent传过来的数据,即使B界面到C界面后B界面被杀了,再回到B界面,B界面还是拿得到A界面传过来的数据,但还是原始Intent的数据,如果B界面在被杀之前对Intent数据加工,通过onSaveInstanceState存储,通过onRestoreInstanceState统一处理了,那么就要绕过之前A界面通过Intent传过来的原始数据的干扰。

Activity处理配置变更等问题

程序在运行时,一些设备的配置可能会改变,如:横竖屏的切换、键盘的可用性或语言的切换等,这样的事情已发生,Activity会重新启动。其中的过程是:在销毁之前会先调用onSaveInstancestate()去保存应用中的一些数据,然后调用 onDestory(),最后才会去调用onCreate()或者onRestoreInstanceState方法重新启动Activiy。当在Android的Manifest.xml定义了android:configchange属性之后就不会去重新启动Activity,而是通知程序去调用onConfigurationChange()函数。例如,在切换语言之后会重新启动Activity,定义这个属性之后就不会重新启动Activity。其可以设置多个属性,中间用“|”隔开。
对android:configChanges属性,一般认为有以下几点(横竖屏切换):

  • 不设置Activity的android:configChanges时,切屏会重新调用各个生命周期,切横屏时会执行一次,切竖屏时会执行两次;
  • 设置Activity的android:configChanges="orientation"时,切屏还是会重新调用各个生命周期,切横、竖屏时只会执行一次;
  • 设置Activity的android:configChanges="orientation|keyboardHidden"时,切屏不会重新调用各个生命周期,只会执行onConfigurationChanged方法,在其中可获取切换后的横竖屏参数或者进行一些其他操作。

参考资料:
http://blog.csdn.net/liuhe688/article/details/6754323
http://droidyue.com/blog/2015/08/16/dive-into-android-activity-launchmode/index.html

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 199,830评论 5 468
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 83,992评论 2 376
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 146,875评论 0 331
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,837评论 1 271
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,734评论 5 360
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,091评论 1 277
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,550评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,217评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,368评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,298评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,350评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,027评论 3 315
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,623评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,706评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,940评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,349评论 2 346
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 41,936评论 2 341

推荐阅读更多精彩内容

  • Activity https://developer.android.com/guide/components/a...
    XLsn0w阅读 695评论 0 4
  • Activity是一个应用组件,用户可与其提供的屏幕进行交互。以执行拨打电话,拍摄照片,发送电子邮件或查看地图等操...
    DanieX阅读 1,087评论 0 4
  • Activity 是一个应用组件,用户可与其提供的屏幕进行交互,以执行拨打电话、拍摄照片、发送电子邮件或查看地图等...
    岳小川阅读 480评论 0 3
  • 读《超级符号就是超级创意》的十点感悟: 01 什么是决定营销成本的关键 营销做出去之后,消费者对营销内容的记忆成本...
    程晓晓阅读 248评论 2 2
  • 最近莫名的感觉无力,事无所事事的无力感。 世界离了谁都会转,但是最痛苦的是,你依赖的人,根本不依赖你。 归家,家里...
    左眼倾斜阅读 134评论 0 0