《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(意为风景),这大概是肖像图多呈纵向(高大于宽),而风景图多呈横向(宽大于高)的缘故。——译者注

相关文章
|
7天前
|
搜索推荐 前端开发 API
探索安卓开发中的自定义视图:打造个性化用户界面
在安卓应用开发的广阔天地中,自定义视图是一块神奇的画布,让开发者能够突破标准控件的限制,绘制出独一无二的用户界面。本文将带你走进自定义视图的世界,从基础概念到实战技巧,逐步揭示如何在安卓平台上创建和运用自定义视图来提升用户体验。无论你是初学者还是有一定经验的开发者,这篇文章都将为你打开新的视野,让你的应用在众多同质化产品中脱颖而出。
34 19
|
7天前
|
JSON Java API
探索安卓开发:打造你的首个天气应用
在这篇技术指南中,我们将一起潜入安卓开发的海洋,学习如何从零开始构建一个简单的天气应用。通过这个实践项目,你将掌握安卓开发的核心概念、界面设计、网络编程以及数据解析等技能。无论你是初学者还是有一定基础的开发者,这篇文章都将为你提供一个清晰的路线图和实用的代码示例,帮助你在安卓开发的道路上迈出坚实的一步。让我们一起开始这段旅程,打造属于你自己的第一个安卓应用吧!
31 14
|
10天前
|
Java Linux 数据库
探索安卓开发:打造你的第一款应用
在数字时代的浪潮中,每个人都有机会成为创意的实现者。本文将带你走进安卓开发的奇妙世界,通过浅显易懂的语言和实际代码示例,引导你从零开始构建自己的第一款安卓应用。无论你是编程新手还是希望拓展技术的开发者,这篇文章都将为你打开一扇门,让你的创意和技术一起飞扬。
|
8天前
|
XML 存储 Java
探索安卓开发之旅:从新手到专家
在数字时代,掌握安卓应用开发技能是进入IT行业的关键。本文将引导读者从零基础开始,逐步深入安卓开发的世界,通过实际案例和代码示例,展示如何构建自己的第一个安卓应用。我们将探讨基本概念、开发工具设置、用户界面设计、数据处理以及发布应用的全过程。无论你是编程新手还是有一定基础的开发者,这篇文章都将为你提供宝贵的知识和技能,帮助你在安卓开发的道路上迈出坚实的步伐。
18 5
|
7天前
|
开发框架 Android开发 iOS开发
安卓与iOS开发中的跨平台策略:一次编码,多平台部署
在移动应用开发的广阔天地中,安卓和iOS两大阵营各占一方。随着技术的发展,跨平台开发框架应运而生,它们承诺着“一次编码,到处运行”的便捷。本文将深入探讨跨平台开发的现状、挑战以及未来趋势,同时通过代码示例揭示跨平台工具的实际运用。
|
8天前
|
XML 搜索推荐 前端开发
安卓开发中的自定义视图:打造个性化UI组件
在安卓应用开发中,自定义视图是一种强大的工具,它允许开发者创造独一无二的用户界面元素,从而提升应用的外观和用户体验。本文将通过一个简单的自定义视图示例,引导你了解如何在安卓项目中实现自定义组件,并探讨其背后的技术原理。我们将从基础的View类讲起,逐步深入到绘图、事件处理以及性能优化等方面。无论你是初学者还是有经验的开发者,这篇文章都将为你提供有价值的见解和技巧。
|
8天前
|
搜索推荐 前端开发 测试技术
打造个性化安卓应用:从设计到开发的全面指南
在这个数字时代,拥有一个定制的移动应用不仅是一种趋势,更是个人或企业品牌的重要延伸。本文将引导你通过一系列简单易懂的步骤,从构思你的应用理念开始,直至实现一个功能齐全的安卓应用。无论你是编程新手还是希望拓展技能的开发者,这篇文章都将为你提供必要的工具和知识,帮助你将创意转化为现实。
|
11天前
|
Java 调度 Android开发
安卓与iOS开发中的线程管理差异解析
在移动应用开发的广阔天地中,安卓和iOS两大平台各自拥有独特的魅力。如同东西方文化的差异,它们在处理多线程任务时也展现出不同的哲学。本文将带你穿梭于这两个平台之间,比较它们在线程管理上的核心理念、实现方式及性能考量,助你成为跨平台的编程高手。
|
8天前
|
Java Android开发 开发者
探索安卓开发:构建你的第一个“Hello World”应用
在安卓开发的浩瀚海洋中,每个新手都渴望扬帆起航。本文将作为你的指南针,引领你通过创建一个简单的“Hello World”应用,迈出安卓开发的第一步。我们将一起搭建开发环境、了解基本概念,并编写第一行代码。就像印度圣雄甘地所说:“你必须成为你希望在世界上看到的改变。”让我们一起开始这段旅程,成为我们想要见到的开发者吧!
16 0
|
11天前
|
存储 监控 Java
探索安卓开发:从基础到进阶的旅程
在这个数字时代,移动应用已成为我们日常生活的一部分。对于开发者来说,掌握安卓开发不仅是技能的提升,更是通往创新世界的钥匙。本文将带你了解安卓开发的核心概念,从搭建开发环境到实现复杂功能,逐步深入安卓开发的奥秘。无论你是初学者还是有经验的开发者,这篇文章都将为你提供新的见解和技巧,帮助你在安卓开发的道路上更进一步。
14 0