Android_Activity(活动)
官方文档:https://developer.android.google.cn/guide/components/activities
官方API:https://developer.android.google.cn/reference/android/app/Activity
Activity 是4大基本组件之一,用户可与其提供的屏幕进行交互,以执行拨打电话、拍摄照片、发送电子邮件或查看地图等操作。 每个 Activity 都会获得一个用于绘制其用户界面的窗口。窗口通常会充满屏幕,但也可小于屏幕并浮动在其他窗口之上。
一个应用通常由多个彼此松散联系的 Activity 组成。 一般会指定应用中的某个 Activity 为“主”Activity,即首次启动应用时呈现给用户的那个 Activity。 而且每个 Activity 均可启动另一个 Activity,以便执行不同的操作。 每次新 Activity 启动时,前一 Activity 便会停止,但系统会在堆栈(“返回栈”)中保留该 Activity。 当新 Activity 启动时,系统会将其推送到返回栈上,并取得用户焦点。 返回栈遵循基本的“后进先出”堆栈机制,因此,当用户完成当前 Activity 并按“返回”按钮时,系统会从堆栈中将其弹出(并销毁),然后恢复前一 Activity。 (任务和返回栈文档中对返回栈有更详细的阐述。)
当一个 Activity 因某个新 Activity 启动而停止时,系统会通过该 Activity 的生命周期回调方法通知其这一状态变化。Activity 因状态变化而收到的回调方法可能有若干种,每一种回调都会为您提供执行与该状态变化相应的特定操作的机会。 例如,停止时,您的 Activity 应释放任何大型对象,例如网络或数据库连接。 当 Activity 恢复时,您可以重新获取所需资源,并恢复执行中断的操作。 这些状态转变都是 Activity 生命周期的一部分。
创建 Activity
创建 Activity 的子类(或使用其现有子类,如:BaseActivity )。您需要在子类中实现 Activity 在其生命周期的各种状态之间转变时系统调用的回调方法。 两个最重要的回调方法是:
必须实现此方法。系统会在创建您的 Activity 时调用此方法。您应该在实现内初始化 Activity 的必需组件。 您必须在此方法内调用 setContentView(),以定义 Activity 用户界面的布局。
用户离开 Activity 时第一个调用的方法(但并不意味着 Activity 会被销毁)。 应在此方法内释放任何大型对象,并酌情更改其他对象的有效性,因为用户可能不会返回。
您还应使用几种其他生命周期回调方法,以便提供流畅的 Activity 间用户体验,以及处理导致您的 Activity 停止甚至被销毁的意外中断。 后文的管理 Activity 生命周期部分对所有生命周期回调方法进行了阐述。
实现用户界面
如需了解有关创建用户界面的信息,请参阅用户界面文档。
我的博客:https://www.cnblogs.com/zhaolanqi/p/9907646.html
声明 Activity
您必须在清单文件中声明您的 Activity,这样系统才能访问它。将 <activity> 元素添加为 <application> 元素的子项。例如:
<manifest ... > <application ... > <activity android:name=".ExampleActivity" /> ... </application ... > ... </manifest >
您还可以在此元素中加入几个其他特性,以定义 Activity 标签、Activity 图标或风格主题等用于设置 Activity UI 风格的属性。 android:name 属性是唯一必需的属性,它指定 Activity 的类名。应用一旦发布,即不应更改此类名,否则,可能会破坏诸如应用快捷方式等一些功能(请阅读博客文章 Things That Cannot Change [不能更改的内容])。
请参阅 <activity> 元素参考文档,了解有关在清单文件中声明 Activity 的详细信息。
使用 Intent 过滤器
<activity> 元素还可指定各种 Intent 过滤器,使用 <intent-filter> 元素以声明其他应用组件激活它的方法。
当您使用 Android SDK 工具创建新应用时,系统自动为您创建的存根 Activity 包含一个 Intent 过滤器,其中声明了该 Activity 响应“主”操作且应置于“launcher”类别内。 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 具有“主”操作和“launcher”类别。
如果打算让应用成为独立应用,不允许其他应用激活此 Activity,则不需要任何 Intent 过滤器,可以利用显式 Intent 自行启动它们。
如果想让 Activity 对衍生自其他应用(以及您的自有应用)的隐式 Intent 作出响应,则必须为 Activity 定义其他 Intent 过滤器。 对于您想要作出响应的每一个 Intent 类型,您都必须加入相应的 <intent-filter>,其中包括一个<action> 元素,还可选择性地包括一个 <category> 元素或一个 <data> 元素。这些元素指定您的 Activity 可以响应的 Intent 类型。
如需了解有关您的 Activity 如何响应 Intent 的详细信息,请参阅 Intent 和 Intent 过滤器文档
启动 Activity
调用 startActivity(),并传递一个 Intent 来启动另一个 Activity。Intent 对象会指定想要启动的具体 Activity 或描述想要执行的操作类型(系统会选择合适的 Activity,甚至是来自其他应用的 Activity)。 Intent 对象还可以携带少量供启动 Activity 使用的数据。
在自有应用内工作时,经常只需要启动某个已知 Activity,可以通过使用类名创建一个显式 的 Intent 对象:
Intent intent = new Intent(this, LoginActivity.class); startActivity(intent);
不过,应用可能还需要利用 Activity 数据执行某项操作,例如发送电子邮件、短信或状态更新。 您的应用自身可能不具有执行此类操作所需的 Activity,因此您可以改为利用设备上其他应用提供的 Activity 为您执行这些操作。 这便是 Intent 对象的真正价值所在——创建一个 Intent 对象,对执行的操作进行描述,系统会从其他应用启动相应的 Activity。 如果有多个 Activity 可以处理 Intent,则用户可以选择要使用哪一个。 例如,如果您想拨打电话,可以创建以下 Intent:
// public Intent(String action) { setAction(action); } // <uses-permission android:name="android.permission.CALL_PHONE" /> // 直接拨打电话,需要申请权限 Intent intent = new Intent(Intent.ACTION_CALL); Uri uri = Uri.parse("tel:" + "187****5523"); intent.setData(uri); startActivity(intent); // 跳转到拨号界面,用户手动拨打,不需要申请权限 Intent intent = new Intent(Intent.ACTION_DIAL); Uri uri = Uri.parse("tel:" + "187****5523"); intent.setData(uri); startActivity(intent);
启动 Activity 以获得结果
有时,可能需要从启动的 Activity 获得结果。调用 startActivityForResult() 来启动 Activity。 实现 onActivityResult() 回调方法(方法内一般对 resultCode 和 requestCode 做判断),以收到后续 Activity 的结果。
在后续 Activity 结束前,会使用 setResult() 方法通过 Intent 向您的 onActivityResult() 方法返回结果。后续 activity 需先调用 setResult(int resultCode, Intent data) 方法,后结束活动(用 finish() 方法,或按返回键等其他操作)。
resultCode 最好不要用 0 ,因为没有执行 setResult() 方法时,默认的 resultCode 是0,如果在 onActivityResult() 回调方法中做出 resultCode == 0 的判断,我们无法知晓是不是想要获得的结果。
private void pickContact() { // 按照内容提供程序 URI 的定义,创建一个 "pick" 联系人的意图 Intent intent = new Intent(Intent.ACTION_PICK, ContactsContract.Contacts.CONTENT_URI); startActivityForResult(intent, 3); } @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { // 第一个条件检查请求是否成功(如果成功,则 resultCode 将为 RESULT_OK) // 第二个条件检查此结果响应的请求是否已知,在此情况下,requestCode与 startActivityForResult() 发送的第二个参数匹配 // 代码通过查询 Intent 中返回的数据(data 参数)处理 Activity 结果。 if (resultCode == Activity.RESULT_OK && requestCode == 3) { // Perform a query to the contact's content provider for the contact's name Cursor cursor = getContentResolver().query(data.getData(), new String[] {ContactsContract.Contacts.DISPLAY_NAME}, null, null, null); if (cursor.moveToFirst()) { // True if the cursor is not empty int columnIndex = cursor.getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME); String name = cursor.getString(columnIndex); Logger.d(name); // 输出联系人名字 } } }
ContentResolver 对一个内容提供程序执行查询,后者返回一个 Cursor,让查询的数据能够被读取。如需了解详细信息,请参阅内容提供程序文档。
如需了解有关 Intent 用法的详细信息,请参阅 Intent 和 Intent 过滤器文档。
结束 Activity
调用 Activity 的 finish() 方法来结束该 Activity,系统会从堆栈中将其弹出(并销毁)。您还可以通过调用 finishActivity() 结束您之前启动的另一个 Activity。
注:在大多数情况下,不应使用这些方法显式结束 Activity。 正如下文有关 Activity 生命周期的部分所述,Android 系统会为您管理 Activity 的生命周期,因此您无需结束自己的 Activity。 调用这些方法可能对预期的用户体验产生不良影响,因此只应在您确实不想让用户返回此 Activity 实例时使用。
管理 Activity 生命周期

Activity 基本上以三种状态存在:
- 运行状态
- 此 Activity 位于返回栈顶,取得用户焦点,对用户可见。
- 暂停状态
- 部分透明或未覆盖整个屏幕的另一个 Activity 显示在此 Activity 上方并取得用户焦点,此 Activity 失去焦点 ,但仍可见。暂停的 Activity 处于完全活动状态(
Activity对象保留在内存中,它保留了所有状态和成员信息,并与窗口管理器保持连接),但在内存极度不足的情况下,可能会被系统 killed (终止)。 - 停止状态
- 该 Activity 被另一个 Activity 完全遮盖(该 Activity 目前位于“后台”),不可见。 已停止的 Activity 同样仍处于活动状态(
Activity对象保留在内存中,它保留了所有状态和成员信息,但未与窗口管理器连接),但在内存极度不足的情况下,可能会被系统 killed (终止)。
如果 Activity 处于暂停或停止状态,系统可以将其从内存中删除(通过调用 finish() 方法或直接终止进程的方式)。(将其结束或终止后)再次打开 Activity 时,必须重建。
实现生命周期回调
在实现这些生命周期方法时必须始终先调用超类实现,然后再执行其他操作。
这些方法共同定义 Activity 的整个生命周期。通过实现这些方法监控 Activity 生命周期中的三个嵌套循环: 1. Activity 的整个生命周期发生在 onCreate() 调用与 onDestroy() 调用之间。
Activity 应在 onCreate() 中执行“全局”状态设置(例如定义布局),并在 onDestroy() 中释放所有其余资源。
例如,如果 Activity 有一个在后台运行的线程,用于从网络上下载数据,它可能会在 onCreate() 中创建线程,然后在 onDestroy() 中停止线程。
2. Activity 的可见生命周期发生在 onStart() 调用与 onStop() 调用之间。
在这段时间,用户可以在屏幕上看到 Activity 并与其交互。例如,当一个新 Activity 启动,并且此 Activity 不再可见时,系统会调用 onStop()。可以在调用这两个方法之间保留向用户显示 Activity 所需的资源。
例如,您可以在 onStart() 中注册一个 BroadcastReceiver 以监控影响 UI 的变化,并在用户无法再看到您显示的内容时在 onStop() 中将其取消注册。
在 Activity 的整个生命周期,当 Activity 在对用户可见和隐藏两种状态中交替变化时,系统可能会多次调用 onStart() 和 onStop()。
3. Activity 的前台生命周期发生在 onResume() 调用与 onPause() 调用之间。
在这段时间,Activity 位于屏幕上的所有其他 Activity 之前,并具有用户输入焦点。 Activity 可频繁转入和转出前台 。
例如,当设备转入休眠状态或出现对话框时,系统会调用 onPause()。 由于此状态可能经常发生转变,因此这两个方法中应采用适度轻量级的代码,以避免因转变速度慢而让用户等待。
Activity 生命周期回调方法汇总表。
| 方法 |
说明 |
是否能事后终止? |
后接 |
||
|
首次创建 Activity 时调用。 您应该在此方法中执行所有正常的静态设置 — 创建视图、将数据绑定到列表等等。 系统向此方法传递一个 Bundle 对象,其中包含 Activity 的上一状态,不过前提是捕获了该状态(请参阅后文的保存 Activity 状态)。 始终后接 onStart()。 |
否 |
onStart() |
|||
|
|
在 Activity 已停止并即将再次启动前调用。 始终后接 onStart() |
否 |
onStart() |
||
|
在 Activity 即将对用户可见之前调用。 如果 Activity 转入前台,则后接 onResume(),如果 Activity 转入隐藏状态,则后接 onStop()。 |
否 |
onResume() 或 onStop() |
|||
|
|
在 Activity 即将开始与用户进行交互之前调用。 此时,Activity 处于 Activity 堆栈的顶层,并具有用户输入焦点。 始终后接 onPause()。 |
否 |
onPause() |
||
|
当系统即将开始继续另一个 Activity 时调用。 此方法通常用于确认对持久性数据的未保存更改、停止动画以及其他可能消耗 CPU 的内容,诸如此类。 它应该非常迅速地执行所需操作,因为它返回后,下一个 Activity 才能继续执行。 如果 Activity 返回前台,则后接 onResume(),如果 Activity 转入对用户不可见状态,则后接 onStop()。 |
是 |
onResume() 或 onStop() |
|||
|
在 Activity 对用户不再可见时调用。如果 Activity 被销毁,或另一个 Activity(一个现有 Activity 或新 Activity)继续执行并将其覆盖,就可能发生这种情况。 如果 Activity 恢复与用户的交互,则后接 onRestart(),如果 Activity 被销毁,则后接 onDestroy()。 |
是 |
onRestart() 或 onDestroy() |
|||
|
在 Activity 被销毁前调用。这是 Activity 将收到的最后调用。 当 Activity 结束(有人对 Activity 调用了 finish()),或系统为节省空间而暂时销毁该 Activity 实例时,可能会调用它。 您可以通过 isFinishing() 方法区分这两种情形。 |
是 |
无 |
|||
名为“是否能事后终止?”的列表示:系统是否能在不执行另一行 Activity 代码的情况下,在方法返回后随时终止承载 Activity 的进程。
三个标记为“是”的方法:(onPause()、onStop() 和 onDestroy()):Activity 创建后,onPause() 方法必定会被调用,然后才可以终止进程。如果系统在紧急情况下必须恢复内存,则可能不会调用 onStop() 和 onDestroy()。因此,应使用 onPause() 向存储设备写入至关重要的持久性数据(例如用户编辑)。不过,对 onPause() 调用期间必须保留的信息要有所选择,因为该方法中的任何阻止过程都会妨碍向下一个 Activity 的转变并拖慢用户体验。标记为"否"的方法:从系统调用它们的一刻起防止承载 Activity 的进程被终止。
注:进程和线程处理文档对可能会终止 Activity 的情况做了更详尽的阐述。
保存 Activity 状态
管理 Activity 生命周期中简要提及,当 Activity 暂停或停止时,Activity 的状态会得到保留。 因为当 Activity 暂停或停止时,Activity 对象仍保留在内存中,有关其成员和当前状态的所有信息仍处于活动状态。 因此,用户在 Activity 内所做的任何更改都会得到保留,这样一来,当 Activity 返回前台(当它“继续”)时,这些更改仍然存在。
不过,当系统为了恢复内存而销毁某项 Activity 时,Activity 对象也会被销毁,因此系统在继续 Activity 时根本无法让其状态保持完好,而是必须在用户返回 Activity 时重建 Activity 对象。但用户并不知道系统销毁 Activity 后又对其进行了重建,因此他们很可能认为 Activity 状态毫无变化。 在这种情况下,您可以实现另一个回调方法对有关 Activity 状态的信息进行保存,以确保有关 Activity 状态的重要信息得到保留:onSaveInstanceState()。
系统会先调用 onSaveInstanceState(),然后再使 Activity 变得易于销毁。系统会向该方法传递一个 Bundle,您可以在其中使用 putString() 和 putInt() 等方法以名称-值对形式保存有关 Activity 状态的信息。然后,如果系统终止您的应用进程,并且用户返回您的 Activity,则系统会重建该 Activity,并将 Bundle 同时传递给 onCreate() 和 onRestoreInstanceState()。您可以使用上述任一方法从 Bundle 提取您保存的状态并恢复该 Activity 状态。如果没有状态信息需要恢复,则传递给您的 Bundle 是空值(如果是首次创建该 Activity,就会出现这种情况)。

如图,在两种情况下,Activity 重获用户焦点时可保持状态完好:
系统在销毁 Activity 后重建 Activity,Activity 必须恢复之前保存的状态;
系统停止 Activity 后继续执行 Activity,并且 Activity 状态保持完好。
Activity 类的 onSaveInstanceState() 默认实现会恢复部分 Activity 状态。Android 框架中几乎每个 View 都会根据需要实现此方法,让每个视图都能提供有关自身的应保存信息,以便在重建 Activity 时自动保存和恢复对 UI 所做的任何可见更改。例如,EditText 小部件保存用户输入的任何文本,CheckBox 小部件保存复选框的选中或未选中状态。您只需为想要保存其状态的每个小部件提供一个唯一的 ID(通过 android:id 属性)。如果小部件没有 ID,则系统无法保存其状态。
通过将 android:saveEnabled 属性设置为 "false" 或通过调用 setSaveEnabled() 方法显式阻止布局内的视图保存其状态。通常不应将该属性停用,但如果想以不同方式恢复 Activity UI 的状态,就可能需要这样做。
如果为了保存更多状态信息而替换该方法,必须先调用 onSaveInstanceState() 的超类实现(默认实现有助于保存 UI 的状态),然后再执行任何操作。
如果替换 onRestoreInstanceState() 方法,也应调用它的超类实现(但不是必须),以便默认实现能够恢复视图状态。
注:
无法保证系统会在销毁 Activity 前调用 onSaveInstanceState(),因为存在不需要保存状态的情况(例如用户使用“返回”按钮离开您的 Activity 时,因为用户的行为是在显式关闭 Activity)。
如果系统调用 onSaveInstanceState(),它会在调用 onStop() 之前,并且可能会在调用 onPause() 之前进行调用。
由于无法保证系统会调用 onSaveInstanceState(),因此只应利用它来记录 Activity 的瞬态(UI 的状态),切勿使用它来存储持久性数据,而应使用 onPause() 在用户离开 Activity 后存储持久性数据(例如应保存到数据库的数据)。
总结:
一、onSaveInstanceState(Bundle outState) 会在以下情况被调用:
1、当用户按下HOME键时。
2、从最近应用中选择运行其他的程序时。
3、按下电源按键(关闭屏幕显示)时。
4、从当前activity启动一个新的activity时。
5、屏幕方向切换时(无论竖屏切横屏还是横屏切竖屏都会调用)。
在前4种情况下,当前activity的生命周期为:
onPause -> onSaveInstanceState -> onStop。官方文档中说到,onSaveInstanceState() 可能会在 onPause() 之前调用。
二、onRestoreInstanceState(Bundle saveInstanceState) 什么时机被调用?
只有在 activity 被系统回收,重新创建 activity 的情况下才会被调用。比如第5种情况屏幕方向切换时,activity生命周期如下:
onPause -> onSaveInstanceState -> onStop -> onDestroy -> onCreate -> onStart -> onRestoreInstanceState -> onResume
在这里onRestoreInstanceState被调用,是因为屏幕切换时原来的activity确实被系统回收了,又重新创建了一个新的activity。
如果onRestoreInstanceState被调用了,则页面必然被回收过,则 onSaveInstanceState 必然被调用过。
三、onCreate() 里也有 Bundle 参数,可以用来恢复数据,它和 onRestoreInstanceState 有什么区别?
1、因为 onSaveInstanceState 不一定会被调用,所以 onCreate() 里的 Bundle 参数可能为空,如果使用 onCreate() 来恢复数据,一定要做非空判断。而 onRestoreInstanceState 的 Bundle 参数一定不会是空值,因为它只有在上次 activity 被回收了才会调用。
2、onRestoreInstanceState 是在 onStart() 之后被调用的。有时候我们需要 onCreate() 中做的一些初始化完成之后再恢复数据,用 onRestoreInstanceState会比较方便。
3、用 onRestoreInstanceState 方法恢复数据,可以决定是否在方法里调用父类的方法;而用 onCreate() 恢复数据,你必须调用。
处理配置变更
官网:处理运行时变更 https://developer.android.google.cn/guide/topics/resources/runtime-changes
有些设备配置可能会在运行时发生变化(例如屏幕方向、键盘可用性及语言),此时 Android 会重启正在运行的 Activity。
onSaveInstanceState(),以便您保存有关应用状态的数据。 然后,您可以在 onCreate() 或 onRestoreInstanceState() 期间恢复 Activity 状态。Activity 应该在保持应用状态完好的情况下自行重启,这就要求在应用中执行各种任务时处理配置变更(例如,更改屏幕方向)。应用应该能够在不丢失用户数据或状态的情况下随时重启,以便处理如下事件:配置发生变化,或者用户收到来电并在应用进程被销毁很久之后返回到应用。
重启应用并恢复大量数据不仅成本高昂,而且给用户留下糟糕的使用体验。 在这种情况下,有两个其他选择:
1、 在配置变更期间保留对象
允许 Activity 在配置变更时重启,但是要将有状态对象传递给 Activity 的新实例。
例如:保留 Fragment 来减轻重新初始化 Activity 的负担
2、 自行处理配置变更
阻止系统在某些配置变更期间重启 Activity,但要在配置确实发生变化时接收回调,这样,您就能够根据需要手动更新 Activity。
例如:以下清单文件代码声明的 Activity 可同时处理屏幕方向变更和键盘可用性变更:
<activity android:name=".MyActivity" android:configChanges="orientation|keyboardHidden" android:label="@string/app_name">
当其中一个配置发生变化时,MyActivity 不会重启,而是收到对 onConfigurationChanged() 的调用。以下实现检查当前设备方向:
@Override public void onConfigurationChanged(Configuration newConfig) { super.onConfigurationChanged(newConfig); // Checks the orientation of the screen if (newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE) { Toast.makeText(this, "landscape", Toast.LENGTH_SHORT).show(); } else if (newConfig.orientation == Configuration.ORIENTATION_PORTRAIT){ Toast.makeText(this, "portrait", Toast.LENGTH_SHORT).show(); } }
协调 Activity
当 Activity A 启动 Activity B 时一系列操作的发生顺序:
- Activity A 的
onPause()方法执行。 - Activity B 的
onCreate()、onStart()和onResume()方法依次执行。(Activity B 现在具有用户焦点。) - 然后,如果 Activity A 在屏幕上不再可见,则其
onStop()方法执行。
可以利用这种可预测的生命周期回调顺序管理从一个 Activity 到另一个 Activity 的信息转变。
例如,多个 Activity 共用保存到磁盘或其他地方的数据。如果您必须在第一个 Activity 停止时向数据库写入数据,以便下一个 Activity 能够读取该数据,则应在 onPause() 而不是 onStop() 执行期间向数据库写入数据。
浙公网安备 33010602011771号