Android Activity 详解

阿里云产品限时红包,最高 ¥1888 元,立即领取

概览

  1. Activity 是一个提供屏幕的应用程序组件,用户通过它与机器产生交互。
  2. 每个 Activity 包含一个窗口( window ),大部分情况下窗口是全屏的,也有可能窗口比屏幕小且在其他窗口的顶部。
  3. 一个应用程序由一个或者多个 Activity 组成,这些 Activity 之间是松散的组织在一起的。
  4. 每一个 Activity 可以启动其他的 Activity,不同的 Activity 可以执行不同的动作。
  5. 新的 Activity 启动以后,原来的 Activity 会被保留到后退栈中,后退栈遵循基本的后进先出的堆栈机制。在当前 Activity 中按返回键退出,当前 Activity 将被从堆栈中弹出、销毁,之前的 Activity 则被恢复。
  6. 当 Activity 被启动,或者被停止时,都会通过生命周期回调的方式来通知自己的状态变化。这些状态包括被创建、停止、恢复、销毁,每个回调都提供了在特定状态下执行特定任务的时机。

如何创建 Activity

  1. 创建 Activity 可以通过创建 Activity 的子类,或者一个已经存在的 Activity 子类来实现。
  2. 在创建的子类中实现生命周期的回调方法。其中最重要的是 onCreate 和 onPause。
    • 必须实现 onCreate 方法,并且在其中调用 setContentView() 来定义用户布局。
    • 在 onPause 中提交当前会话中需要被持久化的更改,以避免用户可能不再回来导致的数据丢失。

实现用户界面

  1. Activity 的用户界面是由一系列的视图层级来提供的。
  2. 视图源自于 View 类的对象。每个视图控制 Activity 的窗口上的特定矩形空间,并响应用户交互。
  3. 用户提供了一系列内置的视图,包括”控件”和”布局”。
    • 控件指的是在屏幕上提供的可见、可交互的元素的视图。
    • 布局源自 ViewGroup, 为它的子类提供唯一的布局模型。
  4. 可以实现 View 或者 ViewGroup 的子类来创建自己的控件和布局。
  5. 常用的视图布局定义方式包括:
    • 通过资源文件中的 XML 布局,并在 setContentView() 方法中传递资源ID。可以使界面设计的维护和逻辑代码分离。
    • 通过代码创建 View, 并插入到 ViewGroup 来构建视图层级,然后传递根 ViewGroup 给 setContentView()。

在清单中声明 Activity

  1. 使用 Activity 前,需要在应用清单文件中对其进行声明。在 <application> 元素中添加 <activity> 子元素。
  2. <activity> 元素中还有许多属性用来定义Activity 的标签、图标、主题等, android:name 是唯一必须的属性,用于定义 Activity 的名称。
  3. Activity 的名称定义以后,不要随便改动。如果改动,可能造成某些功能无法正常使用。

使用意图过滤器

  1. <activity> 元素通过 <intent-filter> 元素来定义不同的意图过滤器,用来声明其他应用程序如何激活它。
  2. Android SDK 工具在创建应用程序时自动生成的 Activity 中包含的意图过滤器,声明了 Activity 响应 main 动作,并放在 launcher 类别中。
    • <action android:name="android.intent.action.MAIN" /> 指定这是应用程序的主入口。
    • <category android:name="android.intent.category.LAUNCHER" /> 指定 Activity 被列在系统的应用程序启动器中,这样用户可以启动它。
  3. 如果不允许其他的应用程序来启动 Activity,则不要声明任何的意图过滤器。
  4. 在应用程序内部,可以通过显式的意图来启动想要的 Activity。
  5. 如果定义了意图过滤器,则可以让其他应用程序通过隐式意图来激活 Activity。
  6. <intent-filter> 元素中包含有 <action> 元素及可选的 <category> 或者 <data>,这些元素一同指定了 Activity 能响应的意图类型。

启动一个 Activity

  1. 通过 startActivity() 方法来启动 Activity, 并传递一个 Intent 意图对象。
  2. Intent 对象通过两种方式描述想要启动的 Activity:
    • 准确的 Activity 对象。
    • 想要执行的动作类型。系统会自动选择合适的 Activity, 可能来自其他的应用程序。
  3. Intent 还可以传递少量的数据给即将启动的 Activity。
  4. 使用类名来启动已知的 Activity:
1
2
Intent intent = new Intent(this, SignInActivity.class);
startActivity(intent);
  1. 使用 Intent 来描述要执行的动作,系统从其他应用程序中选择打开合适的 Activity, 如果有多个 Activity, 则由用户来选择:
1
2
3
Intent intent = new Intent(Intent.ACTION_SEND);
intent.putExtra(Intent.EXTRA_EMAIL, recipientArray);
startActivity(intent);

为结果启动 Activity

  1. 如果启动一个 Activity, 并期望从新的 Activity 上接收一个结果,则使用 startActivityForResult()。
  2. 要接收新 Activity 上的结果,需要在原 Activity 上实现 onActivityResult() 方法,从其中的 Intent 参数中获取返回结果。
  3. onActivityResult() 方法处理 Activity 返回结果:
    • 处理成功,则 resultCode 为 RESULT_OK。
    • 需要检查 requestCode 是否与 startActivityForResult() 的第二个参数匹配。
    • 返回的结果以 Intent 带回。

关闭 Activity

通过 finish() 和 finishActivity() 来关闭 Activity。实际上由于 Android 系统自己管理 Activity 的生命,你不应该显示的调用这些方法。

管理 Activity 生命周期

  1. 通过实现回调方法来管理 Activity 的生命周期,可以开发一个健壮且灵活的应用程序。 Activity 的生命周期则直接影响到它所关联的其他 Activity, 任务以及后退栈。
  2. Activity 的主要状态:
    • Resumed: Activity 处于前台屏幕,且拥有用户焦点。
    • Paused:其他 Activity 位于前台,但这个 Activity 还是可见的。其他 Activity 位于顶部且没有覆盖整个屏幕。这时候, Activity 还在内存中,与窗口管理器关联,但在内存极低的情况下将被系统杀掉。
    • Stopped: Activity 被其他 Activity 完全覆盖,位于后台。这时候, Activity 还在内存中,与窗口管理器分离,当需要内存时将被系统杀掉。
  3. 当 Activity 被暂停或者被停止,系统可以通过调用 finish() 或者直接删掉进程的方式丢弃它。重新打开时需要重建。

基础的生命周期方法

生命周期方法 说明
onCreate() Activity 将被创建。
onStart() Activity 即将可见。
onResume() Activity 已经可见,处于 resumed 状态。
onPause() 其他 Activity 可见,自己则即将处于 paused 状态。
onStop() Activity 不在可见,处于 stopped 状态。
onDestroy() Activity 即将被销毁。
  1. 在实现生命周期方法时,需要调用父类的实现。
  2. 实现这些生命周期方法,你可以监控 3 个嵌套的循环。
    • 完整生命:从 onCreate() 到 onDestroy() 。在 onCreate() 中建立全局状态,并在 onDestroy() 中释放资源。
    • 可见生命:从 onStart() 到 onStop() 。这个过程中,用户可以看到 Activity 并与之交互。
    • 前台生命:从 onResume() 到 onPause()。

Activity 生命周期

保存 Activity 状态

  1. Activity 处于 paused, stopped 时依然存在内存中,所有的数据及状态都存在,因此当被恢复时依然保持退出时的状态。
  2. 但处于 paused, stopped 状态的 Activity 可能会被系统杀掉,从而用户重新打开时,与当时提出时不一样了。为了保证能够还原现场,则需要实现 onSaveInstanceState() 回调方法。
  3. 系统在 Activity 被销毁之前调用 onSaveInstance() ,通过将需要记住的状态通过键值对的形式保存到 Bundle 参数中。当应用程序被系统杀死,并再次被启动时,会将保存的 Bundle 传递到 onCreate() 和 onRestoreInstanceState() 。从这些方法的 Bundle 参数中,就可以获取到 Activity 被销毁前的状态,并据此恢复 Activity。

Activity 恢复实例

  1. onSaveInstanceState() 并不是在 Activity 被销毁之前一定会被调用。该方法在 onStop() 之前被调用,是否在 onPause() 前则不确定。
  2. 即使你没有实现 onSaveInstanceState() ,在 Activity 的 onSaveInstanceState() 的默认实现中也可以恢复一些状态。由于 onSaveInstanceState() 的默认实现中保存了 UI 的状态,因此,在自己实现 onSaveInstanceState() 时,需要调用父类的 onSaveInstanceState()。
  3. 由于 onSaveInstanceState() 不保证一定会被调用,因此不能在这个回调中记录 Activity 状态的变换,也不应该使用它来持久化数据,而应该使用 onPause()。
  4. 一个好的,用来测试应用程序恢复状态能力的方法是简单地旋转设备的屏幕方向。

处理配置改变

某些设备配置在运行时会发生改变,如屏幕方向、键盘可用性和语言。当这些改变发生时, Android 重建运行中的 Activity (系统调用 onDestroy() 后马上调用 onCreate() )。这个行为被设计用来帮助应用程序适应新的配置,自动为应用程序重新加载已提供的可替换资源,如为不同屏幕方向和尺寸使用的不同布局。

处理重启的最好方法是使用 onSaveInstanceState() 和 onRestoreInstanceState() (或者 onCreate()) 来保存和恢复 Activity 的状态。

协调多个 Activity

当一个 Activity 启动另外一个时,两个 Activity 都会经历生命周期的变换。当另一个 Activity 被创建时,第一个 Activity 将暂停,乃至停止(如果它在后台且可见,则不会停止)。如果两个 Activity 之间共享保存在磁盘上的数据,对于理解在第二个 Activity 创建完成之前,第一个 Activity 不会完全停止是非常重要的。第二个 Activity 的启动过程和第一个 Activity 的停止过程重叠。

生命周期回调的顺序是被良好定义的,特别是当两个 Activity 在相同的进程中,且一个启动另外一个。下面是当 Activity A 启动 Activity B 时的操作顺序:

  1. 执行 Activity A 的 onPause() 方法。
  2. Activity B 的 onCreate() , onStart() 和 onResume() 方法按顺序执行。(这是 Activity 获取了用户焦点)。
  3. 如果 Activity A 不再屏幕上可见, onStop() 方法被执行。

可预期的生命周期回调顺序使得你可以管理一个 Activity 到另一个的变换信息。例如,你必须在第一个 Activity 停止时对数据库进行写入,这样接下来的 Activity 可以读取,那么你需要在 onPause() 中写入数据库,而不是在 onStop() 中。

参考

https://developer.android.com/guide/components/activities.html