《Android开发秘籍(第2版)》——第2.2节Activity的生命周期

简介:

本节书摘来自异步社区《Android开发秘籍(第2版)》一书中的第2章,第2.2节Android的演化,作者 【美】Ronan Schwarz , Phil Dutson , James Steele , Nelson To,更多章节内容可以访问云栖社区“异步社区”公众号查看

2.2 Activity的生命周期
Android开发秘籍(第2版)
应用程序中的每个Activity都要经历自己的生命周期。Activity于onCreate()函数执行时被创建,该创建过程仅会执行一次。退出Activity时,则会执行onDestroy()函数。在此二者之间,各种各样的事件可以使Activity进入各种不同状态,如图2-2所示。下一个技巧将对这些函数一一举例。


96fe45c60b0671341f4a1c69eea5e1c401117d68

技巧4:使用Activity生命周期函数
本技巧提供了一种在Activity工作时查看其生命周期的简单方法。为清楚起见,对每个被重写的函数都予以显式声明,并在其中加入一条Toast命令,这样在执行某个函数时,在屏幕上能有所反映(关于Toast微件的更多细节将在第3章中给出)。代码清单2-7给出了Activity的内容。在Android设备上运行它,并尝试各种情况。特别注意以下几点。

改变屏幕方向将会销毁并重建Activity。
按下Home键会使Activity暂停,但不会销毁它。
点击应用程序图标可能会启动一个Activity的新实例,甚至在旧的Activity并未销毁的情况下也会如此。
让屏幕休眠将会暂停Activity,而在唤醒时会恢复它(与接电话时的状况类似)。
代码清单2-7 src/com/cookbook/activity_lifecycle/ActivityLifecycle.java

package com.cookbook.activity_lifecycle;
import android.app.Activity;
import android.os.Bundle;
import android.widget.Toast;
public class ActivityLifecycle extends Activity {
  @Override
  public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);
    Toast.makeText(this, "onCreate", Toast.LENGTH_SHORT).show();
  }
  @Override
  protected void onStart() {
    super.onStart();
    Toast.makeText(this, "onStart", Toast.LENGTH_SHORT).show();
  }
  @Override
  protected void onResume() {
    super.onResume();
    Toast.makeText(this, "onResume", Toast.LENGTH_SHORT).show();
  }
  @Override
  protected void onRestart() {
    super.onRestart();
    Toast.makeText(this, "onRestart", Toast.LENGTH_SHORT).show();
  }
  @Override
  protected void onPause() {
    Toast.makeText(this, "onPause", Toast.LENGTH_SHORT).show();
    super.onPause();
  }
  @Override
  protected void onStop() {
    Toast.makeText(this, "onStop", Toast.LENGTH_SHORT).show();
    super.onStop();
  }
  @Override
  protected void onDestroy() {
    Toast.makeText(this, "onDestroy", Toast.LENGTH_SHORT).show();
    super.onDestroy();
  }
}

由此可见,不少用户操作会导致Activity暂停或杀死,甚至可能启动应用程序的多个版本。在开始新内容之前,有必要提一下另外两个可以控制这种行为的简单技巧。

技巧5:强制采用单任务模式
当跳出一个应用程序然后再次启动它时,可能在设备上产生同一Activity的多个实例。最终多余的实例会被杀死以释放内存,但期间可能引发莫名其妙的情况。为避免这种情况发生,开发者可以在AndroidManifest.xml文件中对每个Activity的此类行为进行控制。

要确保Activity只有一个实例在设备上运行,为拥有MAIN和LAUNCHER两个Intent过滤器的Activity元素内添加如下代码:

android:launchMode="singleInstance"
这样就使任务中的每个Activity始终只有一个实例。此外,任何子Activity都会作为一个单独的任务来启动。为进一步确保应用中的所有Activity都运行在同一个任务中,使用如下代码:

android:launchMode="singleTask"
这样就使多个Activity可以作为同一个任务来轻松地共享信息。

此外,有时我们会希望无论用户以何种方式进入Activity时,都能保持任务状态。例如,如果用户离开了应用,一段时间后又重新启动它,默认的做法通常是将任务重置为初始状态。为保证任务在用户返回时总是被还原到关闭之前的状态,可为任务的根Activity的activity元素指定如下属性:

android:alwaysRetainTaskState="true"

技巧6:强制规定屏幕方向
每个拥有加速度计的Android设备都可以判定哪个方向是向下。当设备从纵向(portrait)模式切换到横向(landscape)模式1 **时,默认的动作是让应用程序的视图也随之旋转。然而,在技巧4中我们看到,Activity会随着屏幕方向的改变而销毁和重启,一旦发生这种事,Activity的当前状态可能丢失,以致干扰用户体验。

处理屏幕变向的办法之一是在改变前保存状态信息,并在改变后予以恢复。更为简单且有用的一种办法是强制屏幕方向保持恒定。可以为AndroidManifest.xml文件中的每一个Activity指定screenOrientation属性。例如,要让Activity始终保持纵向模式,可以在Activity标签内添加如下属性:

android:screenOrientation="portrait"
类似地,若要保持横向模式,则使用下面的代码:

android:screenOrientation="landscape"
然而,光有这样的代码,在硬键盘滑出时仍会引发Activity的销毁和重启。此时,可以采用第三种办法,告诉Android系统:应用程序会处理屏幕变向和键盘滑出事件。可以通过在activity元素中增添如下属性来实现这一点:

android:configChanges="orientation|keyboardHidden"

该属性可以单独使用,也可与screenOrientation属性一起使用,从而向应用程序规定我们想要的行为。

技巧7:保存和恢复Activity信息
当Activity将被杀死时,会调用onSaveInstanceState()函数。可重写该函数以保存有关信息。当Activity被重建时,会调用onRestoreInstanceState()函数,重写它可以恢复保存的信息。这样可以在应用经历生命周期变化时,让用户获得无缝的体验。注意,多数UI状态不需要我们亲自处理,因为默认状况下系统会关照它们。

onSaveInstanceState()有别于onPause(),例如,如果另一组件被启动并置于现有Activity的前端,就会调用onPause()函数。随后,如果当操作系统要回收资源时该Activity仍处于暂停状态,就在结束它之前调用onSaveInstanceState()。

代码清单2-8给出一个保存和恢复实例状态的例子,该状态包含一个字符串和一个float型数组。

代码清单2-8 onSaveInstanceState()和onRestoreInstanceState()的示例

float[] localFloatArray = {3.14f, 2.718f, 0.577f};
String localUserName = "Euler";
@Override
protected void onSaveInstanceState(Bundle outState) {
     super.onSaveInstanceState(outState);
     //Save the relevant information
     outState.putString("name", localUserName);
     outState.putFloatArray("array", localFloatArray);
}
@Override
public void onRestoreInstanceState(Bundle savedInstanceState) {
     super.onRestoreInstanceState(savedInstanceState);
     //Restore the relevant information
     localUserName = savedInstanceState.getString("name");
     localFloatArray = savedInstanceState.getFloatArray("array");
}

注意,onCreate()方法同样包含Bundle savedInstanceState对象。当Activity关闭后又被重新初始化时,在onSaveInstanceState()中被保存的bundle也会被传递到onCreate()方法中。在任何情况下,被保存的bundle都要传递给onSaveInstanceState()函数,所以用它来恢复状态更为自然。

技巧8:使用Fragment
Fragment是新近被加入Android基本构建模块行列的新鲜事物,它们是Activity下属的小部件,用于为视图与功能分组。对Fragment的一个形象类比是把它们想成小的积木块,可以堆在一起从而对更大的积木块进行填充。对小组块的需求源于平板电脑和电视屏幕的引入。

Fragment使得视图可以被捆绑在一起,并按需要被混合并匹配到一个或两个(甚至更多)Activity中去。对Fragment的经典应用是将屏幕从带有一个列表及一个详细视图的横向模式切换到带有一个单列表及一个详细视图的纵向模式。事实上,该模式已变得如此流行,以至于现在可以通过Create New Project对话框直接创建这一模式的应用骨架。

创建的步骤与前面技巧里描述过的类似。

(1)在Eclipse下,选择File → New → Android Application Project。

(2)填写项目名称,比如SimpleFragmentExample。

(3)填写应用程序的名称,比如Example of Basic Fragments。

(4)填写包名称,例如com.cookbook.simplefragments。

(5)将SDK的最低要求选为API Level 11或Android Honeycomb。只有机器上安装了额外的支持库的情况下,Fragment才能在更低的API版本下使用。

(6)在Create Activity界面中选择MasterDetailFlow作为起始点。

(7)为用于演示的项起名,例如叫做f ruits。

(8)点击Finfish按钮完成创建。

进一步探索这一范例功用的工作就留给读者完成。在此我们强调与 Fragment 有关的几点重要事项。

Fragment有它们自己的生命周期,该周期依赖于宿主Activity。由于Fragment可以在Activity生命周期的任意时间点被添加、显示、隐藏和移除,它们比其他组件要更短命一些。与Activity类似,Fragment拥有onPause()、onResume()、onDestroy()和onCreate()方法。

但需要注意的是,对于Fragment,onCreate(Bundle)方法是第二个被调用的方法,第一个调用是onAttach(Activity),它产生信号,表明已存在与宿主Activity的连接。可以在onAttach中调用Activity上的方法,但此时并不能保证Activity已经将自己初始化完毕。只有当调用了onActivityCreated()方法之后,Activity才算是通过了它自己的onCreate()方法。

鉴于Fragment可以在很晚时才被实例化和添加,我们不应依赖Activity在onAttach()中的状态。用于初始化视图并开始大部分工作的乃是onCreateView(LayoutInflater, ViewGroup, Bundle)方法。如果Fragment被是重建的,那么其中的Bundle类为事先保存的实例状态。

Fragment还使用bundle来序列化参数。Fragment所需的每一种属于可打包类型的外部信息,都可以通过调用setArguments()方法从宿主Activity获取。并且总能在Fragment中调用getArguments()方法读取它们。这使得从Activity的起始Intent来的信息能够被直接传递到Fragment中显示。

1在显示方向的英文术语中,纵向被称为portrait(意为肖像),而横向被称为landscape(意为风景),这大概是肖像图多呈纵向(高大于宽),而风景图多呈横向(宽大于高)的缘故。——译者注

相关文章
|
4天前
|
Linux 编译器 Android开发
FFmpeg开发笔记(九)Linux交叉编译Android的x265库
在Linux环境下,本文指导如何交叉编译x265的so库以适应Android。首先,需安装cmake和下载android-ndk-r21e。接着,下载x265源码,修改crosscompile.cmake的编译器设置。配置x265源码,使用指定的NDK路径,并在配置界面修改相关选项。随后,修改编译规则,编译并安装x265,调整pc描述文件并更新PKG_CONFIG_PATH。最后,修改FFmpeg配置脚本启用x265支持,编译安装FFmpeg,将生成的so文件导入Android工程,调整gradle配置以确保顺利运行。
24 1
FFmpeg开发笔记(九)Linux交叉编译Android的x265库
|
26天前
|
Java Android开发
Android 开发获取通知栏权限时会出现两个应用图标
Android 开发获取通知栏权限时会出现两个应用图标
12 0
|
1月前
|
XML 缓存 Android开发
Android开发,使用kotlin学习多媒体功能(详细)
Android开发,使用kotlin学习多媒体功能(详细)
102 0
|
1月前
|
设计模式 人工智能 开发工具
安卓应用开发:构建未来移动体验
【2月更文挑战第17天】 随着智能手机的普及和移动互联网技术的不断进步,安卓应用开发已成为一个热门领域。本文将深入探讨安卓平台的应用开发流程、关键技术以及未来发展趋势。通过分析安卓系统的架构、开发工具和框架,本文旨在为开发者提供全面的技术指导,帮助他们构建高效、创新的移动应用,以满足不断变化的市场需求。
18 1
|
1月前
|
机器学习/深度学习 调度 Android开发
安卓应用开发:打造高效通知管理系统
【2月更文挑战第14天】 在移动操作系统中,通知管理是影响用户体验的关键因素之一。本文将探讨如何在安卓平台上构建一个高效的通知管理系统,包括服务、频道和通知的优化策略。我们将讨论最新的安卓开发工具和技术,以及如何通过这些工具提高通知的可见性和用户互动性,同时确保不会对用户造成干扰。
33 1
|
1天前
|
数据库 Android开发 开发者
安卓应用开发:构建高效用户界面的策略
【4月更文挑战第24天】 在竞争激烈的移动应用市场中,一个流畅且响应迅速的用户界面(UI)是吸引和保留用户的关键。针对安卓平台,开发者面临着多样化的设备和系统版本,这增加了构建高效UI的复杂性。本文将深入分析安卓平台上构建高效用户界面的最佳实践,包括布局优化、资源管理和绘制性能的考量,旨在为开发者提供实用的技术指南,帮助他们创建更流畅的用户体验。
|
17天前
|
XML 开发工具 Android开发
构建高效的安卓应用:使用Jetpack Compose优化UI开发
【4月更文挑战第7天】 随着Android开发不断进化,开发者面临着提高应用性能与简化UI构建流程的双重挑战。本文将探讨如何使用Jetpack Compose这一现代UI工具包来优化安卓应用的开发流程,并提升用户界面的流畅性与一致性。通过介绍Jetpack Compose的核心概念、与传统方法的区别以及实际集成步骤,我们旨在提供一种高效且可靠的解决方案,以帮助开发者构建响应迅速且用户体验优良的安卓应用。
|
20天前
|
监控 算法 Android开发
安卓应用开发:打造高效启动流程
【4月更文挑战第5天】 在移动应用的世界中,用户的第一印象至关重要。特别是对于安卓应用而言,启动时间是用户体验的关键指标之一。本文将深入探讨如何优化安卓应用的启动流程,从而减少启动时间,提升用户满意度。我们将从分析应用启动流程的各个阶段入手,提出一系列实用的技术策略,包括代码层面的优化、资源加载的管理以及异步初始化等,帮助开发者构建快速响应的安卓应用。
|
20天前
|
Java Android开发
Android开发之使用OpenGL实现翻书动画
本文讲述了如何使用OpenGL实现更平滑、逼真的电子书翻页动画,以解决传统贝塞尔曲线方法存在的卡顿和阴影问题。作者分享了一个改造后的外国代码示例,提供了从前往后和从后往前的翻页效果动图。文章附带了`GlTurnActivity`的Java代码片段,展示如何加载和显示书籍图片。完整工程代码可在作者的GitHub找到:https://github.com/aqi00/note/tree/master/ExmOpenGL。
22 1
Android开发之使用OpenGL实现翻书动画
|
20天前
|
Android开发 开发者
Android开发之OpenGL的画笔工具GL10
这篇文章简述了OpenGL通过GL10进行三维图形绘制,强调颜色取值范围为0.0到1.0,背景和画笔颜色设置方法;介绍了三维坐标系及与之相关的旋转、平移和缩放操作;最后探讨了坐标矩阵变换,包括设置绘图区域、调整镜头参数和改变观测方位。示例代码展示了如何使用这些方法创建简单的三维立方体。
17 1
Android开发之OpenGL的画笔工具GL10