Microsoft Word - 第3章 Activity.doc

Similar documents
教案模板4-2

多媒體應用 13 新增專案並完成版面配置 <ExMusic01> <activity_main.xml> ImageView ID imgplay ImageView ID imgstop ImageView ID imgfront TextView ID txtsong TextView ID t

res/layout 目录下的 main.xml 源码 : <?xml version="1.0" encoding="utf 8"?> <TabHost android:layout_height="fill_parent" xml

主程式 : public class Main3Activity extends AppCompatActivity { ListView listview; // 先整理資料來源,listitem.xml 需要傳入三種資料 : 圖片 狗狗名字 狗狗生日 // 狗狗圖片 int[] pic =new

预览图 : (2) 在 SelectCity.java 中增加控件, 用于绑定 select_city 文件的 ListView, TextView,EditTest 等控件 代码和注释如下 :

Android Service

01_Service

Android Fragment

RecyclerView and CardVew

图 6-1 主界面 MainActivity 界面对应的布局文件 (activity_main.xml) 如下所示 : <?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="

Dynamic Layout in Android

Android 编程基础 Android 开发教程 & 笔记 1

エスポラージュ株式会社 住所 : 東京都江東区大島 東急ドエルアルス大島 HP: ******************* * 关于 Java 测试试题 ******

第 6 章 BroadcastReceiver( 广播接收者 ) 学习目标 掌握广播接收者的创建, 以及如何自定义广播 ; 掌握有序广播和无序广播的使用, 能够对有序广播进行拦截 在 Android 系统中, 广播是一种运用在应用程序之间传递消息的机制, 例如电池电量低时会发送一条提示广播 要过滤并

單步除錯 (1/10) 打開 Android Studio, 點選 Start a new Android Studio project 建立專案 Application name 輸入 BMI 點下 Next 2 P a g e

Android + NFC

SDK 概要 使用 Maven 的用户可以从 Maven 库中搜索 "odps-sdk" 获取不同版本的 Java SDK: 包名 odps-sdk-core odps-sdk-commons odps-sdk-udf odps-sdk-mapred odps-sdk-graph 描述 ODPS 基

内文-2.indd

任务实施 (1) 创建项目 图 3-1 欢迎界面 首先创建一个工程, 将其命名为 BoXueGu, 指定包名为 com.boxuegu (2) 导入界面图片将欢迎界面所需要的背景图片 launch_bg.png 导入到 drawable 文件夹中, 项目的 icon 图标 app_icon.png

OOP with Java 通知 Project 4: 4 月 18 日晚 9 点 关于抄袭 没有分数

为什么引入 Intent Android 应 用程序的四 大组件 Activities Services Content Providers Broadcast Receivers 解决 Android 应用的各项组件之间的通讯 Activity Service Intent Broadcast R

幻灯片 1

0511-Android程式之GPS應用_專題週記4

建模与图形思考

Microsoft Word 杨超-spinner实现省市县的三级联动.docx

OOP with Java 通知 Project 4: 4 月 19 日晚 9 点

掌盟 SoEasy SDK 开发者帮助文档 1. 接入前项目检查 根据游戏接入后出现的问题, 对游戏项目做以下几点要求 : a) AndroidManifest.xml 中 android:targetsdkversion="19" b) 如果 AndroidManifest.xml 有 insta

用手機直接傳值不透過網頁連接, 來當作搖控器控制家電 ( 電視遙控器 ) 按下按鍵發送同時會回傳值來確定是否有送出 問題 :1. 應該是使用了太多 thread 導致在傳值上有問題 2. 一次按很多次按鈕沒辦法即時反應

Android 开发教程

Microsoft Word - 第4章 3D相册.doc

Android Robert C.C. Huang Oscar F.Y. Liu Peter C.L. Hsieh 2011/03/21

詞 彙 表 編 號 詞 彙 描 述 1 預 約 人 資 料 中 文 姓 名 英 文 姓 名 身 份 證 字 號 預 約 人 電 話 性 別 2 付 款 資 料 信 用 卡 別 信 用 卡 號 信 用 卡 有 效 日 期 3 住 房 條 件 入 住 日 期 退 房 日 期 人 數 房 間 數 量 入

一 登录 crm Mobile 系统 : 输入 ShijiCare 用户名和密码, 登录系统, 如图所示 : 第 2 页共 32 页

Android线程和进程

1 1 大概思路 创建 WebAPI 创建 CrossMainController 并编写 Nuget 安装 microsoft.aspnet.webapi.cors 跨域设置路由 编写 Jquery EasyUI 界面 运行效果 2 创建 WebAPI 创建 WebAPI, 新建 -> 项目 ->

移动终端开发与应用

本章学习目标 小风 Java 实战系列教程 SpringMVC 简介 SpringMVC 的入门案例 SpringMVC 流程分析 配置注解映射器和适配器 注解的使用 使用不同方式的跳转页面 1. SpringMVC 简介 Spring web mvc

Microsoft Word - 第3章.doc

软件工程文档编制

ShareText

第一章 Android 简介与开发环境搭建

Guava学习之Resources

Microsoft Word - 第4章 Android生命周期.docx

小应用 Magic8

DU Ad Platform_SDK 安卓接入指南 DU Ad Platform_SDK for Android 接入手册 ( 触发式广告 ) DUAd_SDK_Trigger v1.0 百度在线网络技术 ( 北京 ) 有限公司 百度在线网络技术 ( 北京 ) 有限公司 - 1 -

建模与图形思考

Microsoft Word - 第3章.doc

教案模板4-2

C++ 程序设计 告别 OJ1 - 参考答案 MASTER 2019 年 5 月 3 日 1

新・解きながら学ぶJava

获取 Access Token access_token 是接口的全局唯一票据, 接入方调用各接口时都需使用 access_token 开发者需要进行妥善保存 access_token 的存储至少要保留 512 个字符空间 access_token 的有效期目前为 2 个小时, 需定时刷新, 重复

2 从列表选择在添加黑名单界面中, 点击 从联系人中添加 按钮时, 会跳转到联系人列表界面, 点击其中的任意一个联系人, 此时该联系人的电话号码和姓名会显示在添加黑名单界面的编辑框中, 点击下方的 添加 按钮, 此时会将该号码添加到黑名单中, 并在主界面中展示, 如图 3-2 所示 图 3-2 从联

Microsoft Word - weather12 刷新按钮动画+搜索框+bug处理.docx

建立Android新專案

PowerPoint 演示文稿

腾讯社交广告转化追踪 Android SDK 接入说明文档 V1.2

_banneradview.settest(true); _banneradview.setuserkeywords("swimming"); _banneradview.setusercategories("1,3,4"); _banneradview.setusergender(jdbanner

untitled

移动终端开发与应用

OOP with Java 通知 Project 4: 5 月 2 日晚 9 点

TVS厂商接入流程API文档

Struts2自定义类型转换.doc

题目

Android 开发教程

<4D F736F F D20B5DA36D5C220D7E9BCFEBCE4CDA8D0C52E646F6378>

无类继承.key

Microsoft PowerPoint - 05.Android 介面元件-RelativeLayout、Button、TextVeiw、EditText

单击以编辑母片 Content 标题样式 LinearLayout 排版模式 TableLayout 排版模式 RelativeLayout 排版模式 AbsoluteLayout 排版模式 FrameLayout 排版模式 GridLayout 排版模式 TabWidget 切換卡 Lab 5 2

LEFT, RIGHT // 左 // 右 (2) 当图片移动后, 按钮的坐标发生改变, 此操作通过 setloca tion() 方法实现 setlocation() 方法是从 Component 类继承的, 其定义如下 : public void setlocation(int x, int y

移动平台期末展示

Microsoft Word - 新1-12.doc

前言 C# C# C# C C# C# C# C# C# microservices C# More Effective C# More Effective C# C# C# C# Effective C# 50 C# C# 7 Effective vii

Android + WebService

Microsoft Word - 01.DOC

手说TTS开发指南

OOP with Java 通知 Project 3: 3 月 29 日晚 9 点 4 月 1 日上课

// HDevelopTemplateWPF projects located under %HALCONEXAMPLES%\c# using System; using HalconDotNet; public partial class HDevelopExport public HTuple

Microsoft Word - 第3章.doc

untitled

<4D F736F F F696E74202D20332D322E432B2BC3E6CFF2B6D4CFF3B3CCD0F2C9E8BCC6A1AAD6D8D4D8A1A2BCCCB3D0A1A2B6E0CCACBACDBEDBBACF2E707074>

F515_CS_Book.book

Microsoft Word - QTP测试Flex.doc

第 2 節 介面佈局檔 第 1 項 說明 第 2 項 原始碼 第 3 節 主程式開發 第 1 項 主程式 - 基本設定 第 2 項 主程式 - 產生亂數 第 3 項 主程式 - 數字靠邊 數字加總 第 4 節 加入手

03 开发入门.key

Microsoft Word - Android 7.x.doc

Microsoft Word - 1 扉页

拉卡拉云POS终端收单支付应用组件调用接口说明

使用Cassandra和Spark 2.0实现Rest API服务

Microsoft Word - Hibernate与Struts2和Spring组合指导.doc

Android Android Android SDK iv

教育部補助資訊軟體人才培育先導計畫 100 年度課程發展專案計畫 實驗課程名稱 : IPC(Inter-Process Communication) 開發教師 : 張晉源老師 開發學生 : 林政揚 學校系所 : 樹德科技大學資訊工程學系

帝国CMS下在PHP文件中调用数据库类执行SQL语句实例

在Spring中使用Kafka:Producer篇

Chapter 10

EJB-Programming-3.PDF

Microsoft Word - 扉页.doc

拦截器(Interceptor)的学习

XXX说明书

ChinaBI企业会员服务- BI企业

Transcription:

第 3 章 Activity 学习目标 u 掌握 Activity 的生命周期 u 掌握 Activity 的四种启动模式 u 掌握显式意图和隐式意图的使用 u 学会使用 Intent 传递数据在现实生活中, 经常会使用手机进行打电话 发短信 玩游戏等, 这就需要与手机界面进行交互 在 Android 系统中, 用户与程序的交互是通过 Activity 完成的 同时 Activity 也是 Android 四大组件中最常用的一个, 本章将针对 Activity 的相关知识进行详细地讲解 3.1 Activity 入门 3.1.1 Activity 简介 Activity 是 Android 应用程序的四大组件之一, 它负责管理 Android 应用程序的用户界面 一个应用程序一般会包含若干个 Activity, 每一个 Activity 组件负责一个用户界面的展现 同时,Activity 是通过调用 setcontentview() 方法来显示指定组件的 需要注意的是,setContentView() 方法既可以接收 View 对象为参数, 也可以接收布局文件对应的资源 id 为参数 在应用程序中,Activity 就像一个界面管理员, 用户在界面上的操作是通过 Activity 来管理的, 下面列举几个 Activity 的常用事件, 具体如下 : l onkeydown(int keycode,keyevent event): 对应按键按下事件 l onkeyup(int keycode,keyevent event): 对应按键松开事件 l ontouchevent(motionevent event): 对应点击屏幕事件当用户在手机界面上点击按键时, 就会触发 Activity 中对应的事件 onkeydown() 来响应用户的操作 接下来通过应用程序 ActivityBasic 演示上述三个事件的使用 首先, 需要在 MainActivity 中重写相应的方法, 具体代码如下所示 : 1 public class MainActivity extends Activity { 2 protected void oncreate(bundle savedinstancestate) { 3 super.oncreate(savedinstancestate); 4 setcontentview(r.layout.activity_main); 5 } 6 // 响应按键按下事件 7 public boolean onkeydown(int keycode, KeyEvent event) { 8 Toast.makeText(this, " 按键按下!", 0).show();

9 return super.onkeydown(keycode, event); 10 } 11 // 响应按键松开事件 12 public boolean onkeyup(int keycode, KeyEvent event) { 13 Toast.makeText(this, " 按键弹起!", 0).show(); 14 return super.onkeyup(keycode, event); 15 } 16 // 响应屏幕触摸事件 17 public boolean ontouchevent(motionevent event) { 18 float x=event.getx(); // 获取触摸点的 X 坐标 19 float y=event.gety(); // 获取触摸点的 Y 坐标 20 Toast.makeText(this, " 点击的坐标为 ("+x+":"+y+")", 0).show(); 21 return super.ontouchevent(event); 22 } 23 } 运行 ActivityBasic 程序, 并做相应的操作, 能看到屏幕中显示的效果如图 3-1 所示 图 3-1 Activity 常用事件 在图 3-1 中, 展示了按键按下事件和点击屏幕的事件 当按键松开时, 也会自动执行 onkeyup 事件, 弹出 Toast 显示 按键弹起 此处省略截图, 初学者可以自己进行测试 3.1.2 Activity 的创建 在 Android 应用中, 可以创建一个或多个 Activity, 创建 Activity 步骤如下所示 : 1) 定义一个类继承自 android.app.activity 或者其子类 ; 2) 在 res/layout 目录中创建一个 xml 文件, 用于创建 Activity 的布局 ; 3) 在 AndroidManifest.xml 文件中注册 Activity; 4) 重写 Activity 的 oncreate() 方法, 并在该方法中使用 setcontentview() 加载指定的布局文件 ; 为了初学者掌握 Activity 的创建, 接下来在 ActivityBasic 程序中添加一个 Activity 名为 ActivityExample, 右键包名选择 New à Class 此时会弹出 New Java Class 窗口, 然后在该

窗中的 Name 中输入名称, 并设置 Superclass 为 android.app.activity, 如图 3-2 所示 图 3-2 创建 Activity 点击图 3-2 中的 finish 按钮, 此时 Activity 便创建成功了 接下来在 res/layout 目录下创建 Activity 的布局文件 activity_example.xml, 具体代码如下所示 : <?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" > <TextView android:layout_width="wrap_content" android:layout_centerhorizontal="true" android:layout_centervertical="true" android:textsize="25dp" android:textcolor="#005522" android:text=" 我是新创建的 Activity" /> </RelativeLayout> 在上述布局文件中, 采用了相对布局的方式, 在布局文件中添加了一个 TextView 控件用于展示信息 接下来在 AndroidManifest.xml 文件中, 对 ActivityExample 进行注册, 具体代码如下所示 : <activity android:name="cn.itcast.activitybasic.activityexample" android:label="activityexample" > <intent-filter> <action android:name="android.intent.action.main" /> <category android:name="android.intent.category.launcher" /> </intent-filter>

</activity> 要把 ActivityExample 设置为应用程序默认启动的界面, 需要在 <acitvity> 节点中配置 <intent-filter> 节点 该节点中的 <action android:name="android.intent.action.main" /> 表示将当前 Activity 设置为程序最先启动的 Activity <category ndroid:name="android.intent.category.launcher" /> 表示让当前 Activity 在桌面上创建图标 最后, 在 ActivityExample 中, 重写 oncreate() 方法, 并设置要加载的布局文件, 具体代码如下所示 : public class ActivityExample extends Activity { protected void oncreate(bundle savedinstancestate) { super.oncreate(savedinstancestate); setcontentview(r.layout.activity_example); } } 运行程序, 能看到如图 3-3 所示的结果 图 3-3 ActivityExample 界面 从图 3-3 可以看出, 应用一启动就显示 ActivityExample 界面, 说明 ActivityExample 在清单文件 中配置生效并创建成功 3.1.3 Activity 生命周期 生命周期就是一个对象从创建到销毁的过程, 每一个对象都有自己的生命周期 同样,Activity 也具有相应的生命周期,Activity 的生命周期中分为三种状态, 分别是运行状态 暂停状态和停止状态 接下来将针对 Activity 生命周期的三种状态进行详细地讲解 1 运行状态当 Activity 在屏幕的最前端时, 它是可见的 有焦点的 可以用来处理用户的常见操作, 如点击 双击 长按事件等, 这种状态称为运行状态 2 暂停状态在某些情况下,Activity 对用户来说仍然是可见的, 但它不再拥有焦点, 即用户对它的操作是没

有实际意义的 例如, 当最上面的 Activity 没有完全覆盖屏幕或者是透明的, 被覆盖的 Activity 仍然对用户可见, 并且存活 ( 它保留着所有的状态和成员信息并保持与 Activity 管理器的连接 ) 但当内存不足时, 这个暂停状态的 Activity 可能会被杀死 3 停止状态当 Activity 完全不可见时, 它就处于停止状态, 但仍然保留着当前状态和成员信息 然而这些对用户来说都是不可见的, 如果当系统内存不足时, 这个 Activity 很容易被杀死 值得一提的是, 当 Activity 处于运行状态时,Android 会尽可能地保持它的运行, 即使出现内存不足的情况,Android 也会先杀死栈底部的 Activity, 来确保可见的 Activity 正常运行 Activity 从一种状态转变到另一种状态时会触发一些事件, 执行一些回调方法来通知状态的变化, 具体方法如下所示 : l void oncreate(bundle savedinstancestate): 创建时执行 l void onstart(): 可见时执行 l void onrestart(): 回到前台, 再次可见时执行 l void onresume(): 获取焦点时执行 l void onpause(): 失去焦点时执行 l void onstop(): 用户不可见进入后台时执行 l void ondestroy(): 销毁时执行为了让初学者更好理解 Activity 的三种状态以及不同状态时使用的方法,Google 公司专门提供了一个 Activity 生命周期模型的图例, 具体如图 3-4 所示 图 3-4 Activity 的生命周期 从图 3-4 可以看出, 当 Activity 从启动到关闭时, 会依次执行 oncreate() à onstart() à

onresume() à onpause() à onstop() à ondestroy() 方法 当 Activity 执行到 onpause() 方法失去焦点时, 重新调用回到前台会执行 onresume() 方法, 如果此时进程被杀死 Activity 重新执行时会先执行 oncreate() 方法 当执行到 onstop() 方法 Activity 不可见时, 再次回到前台会执行 onrestart() 方法, 如果此时进程被杀死 Activity 会重新执行 oncreate() 方法 3.1.4 案例 Activity 的存活 为了让初学者掌握 Activity 生命周期, 接下来通过案例 Activity 的存活 来演示 本案例实现了两个 Activity 之间的跳转时生命周期方法变化的过程, 具体步骤如下 : 1 创建程序首先创建一个名为 Activity 的存活 的应用程序, 将包名修改为 cn.itcast.activity, 设计用户交互界面, 具体如图 3-5 所示 图 3-5 第一个 Activity 界面对应布局文件 (activity01.xml) 的代码如下所示 : <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".activity01" > <Button android:layout_width="wrap_content" android:layout_centerhorizontal="true" android:layout_centervertical="true" android:onclick="click" android:text=" 开启 Activity02" /> </RelativeLayout> 2 创建第一个 Activity 界面

在当前项目中创建一个类 Activity01 继承自 Activity, 该类主要用于重写 Activity 的生命周期方 法, 并在每个方法中打印出 Log 以便观察, 具体代码如下所示 : 1 public class Activity01 extends Activity { 2 // 当 activity 被创建的时候调用的方法. 3 public void oncreate(bundle savedinstancestate) { 4 super.oncreate(savedinstancestate); 5 setcontentview(r.layout.activity_life01); 6 Log.i("Activity01", "oncreate()"); 7 } 8 // 当这个 activity 变成用户可见的时候调用的方法. 9 protected void onstart() { 10 super.onstart(); 11 Log.i("Activity01", "onstart()"); 12 } 13 protected void onrestart() { 14 super.onrestart(); 15 Log.i("Activity01", "onrestart()"); 16 } 17 // 当 activity 获取到焦点的时候调用的方法. 18 protected void onresume() { 19 super.onresume(); 20 Log.i("Activity01", "onresume()"); 21 } 22 // 当 activity 失去焦点的时候调用的方法 23 protected void onpause() { 24 super.onpause(); 25 Log.i("Activity01", "onpause()"); 26 } 27 // 当 activity 用户不可见的时候调用的方法. 28 protected void onstop() { 29 super.onstop(); 30 Log.i("Activity01", "onstop()"); 31 } 32 // 当 activity 被销毁的时候掉用的方法. 33 protected void ondestroy() { 34 super.ondestroy(); 35 Log.i("Activity01", "ondestroy()"); 36 } 37 // 界面中按钮的点击事件 38 public void click(view view) { 39 // 创建一个 Intent 对象, 通过该对象开启第 2 个 Activity 40 Intent intent = new Intent(this, Activity02.class); 41 startactivity(intent); 42 }

43 } 上述代码中, 首先重写了 Activity 生命周期中的回调方法, 通过回调方法中输出的日志来观察 Activity 生命周期的过程, 接着在 click() 方法中定义了一个 Intent 对象, 该对象用于开启另一个新的 Activity, 关于 Intent 的具体知识会在后面讲解, 在这里大家了解即可 当点击按钮时会自动触发 click(view view) 方法, 因为之前在布局文件中为 Button 定义了 onclick 属性, 它的作用就是为按钮设置点击事件, 以 onclick 属性的值为方法名创建一个方法, 在参数中传入 View 对象, 这样当点击按钮时就会触发该方法, 可以在方法中写入点击事件的逻辑 需要注意的是, 只有当布局文件中 onclick 的值与方法名一致, 并且参数中传入了 View 对象, 系统才会认为该方法是控件的点击事件方法 3 创建第二个 Activity 界面为了观察 Activity01 停止状态时的生命周期, 需要在当前项目中创建第二个 Activity, 由于不需要对第 2 个 Activity 进行界面操作, 因此新添加一个 activity02.xml 文件即可 在第 2 个 Activity 中同样实现 Activity 生命周期中的方法, 在每个方法中打印 Log 信息 1 public class Activity02 extends Activity { 2 protected void oncreate(bundle savedinstancestate) { 3 super.oncreate(savedinstancestate); 4 setcontentview(r.layout.activity02); 5 Log.i("Activity02", "oncreate()"); 6 } 7 protected void onstart() { 8 super.onstart(); 9 Log.i("Activity02", "onstart()"); 10 } 11 protected void onrestart() { 12 super.onrestart(); 13 Log.i("Activity02", "onrestart()"); 14 } 15 protected void onresume() { 16 super.onresume(); 17 Log.i("Activity02", "onresume()"); 18 } 19 protected void onpause() { 20 super.onpause(); 21 Log.i("Activity02", "onpause()"); 22 } 23 protected void onstop() { 24 super.onstop(); 25 Log.i("Activity02", "onstop()"); 26 } 27 protected void ondestroy() { 28 super.ondestroy(); 29 Log.i("Activity02", "ondestroy()"); 30 } 31 }

4 在清单文件中配置 Activity 在 AndroidManifest.xml 文件中注册已经创建好的 Activity, 即在清单文件中添加一个 <activity> 节点, 指定 Activity 全路径名 <application android:allowbackup="true" android:icon="@drawable/ic_launcher" android:label="@string/app_name" android:theme="@style/apptheme" > <activity android:name="cn.itcast.activitybasic.activitylife01" android:label="@string/app_name" > <intent-filter> <action android:name="android.intent.action.main" /> <category android:name="android.intent.category.launcher" /> </intent-filter> </activity> <activity android:name="cn.itcast.activitybasic.activity02" android:label=" 我是 Activity02" > </activity> </application> 需要注意的是, 在配置 Activity01 时, 需要添加一个 <intent-filter> 节点, 指定 action 和 category 让 Activity01 作为应用程序的入口 5 观察 Activity 生命周期上述操作完成后运行程序, 首先会显示第一个 Activity 界面, 如图 3-6 所示 图 3-6 第一个 Activity 界面 当图 3-6 所示的界面显示时,Log 窗口会打印 Activity01 生命周期中的执行方法, 如图 3-7 所示

图 3-7 第一个 Activity 生命周期从图 3-7 可以看到, 应用程序启动 Activity01 依次输出了 oncreate() onstart() onresume(), 这个顺序是第一个 Activity 从创建到显示在前台到用户可点击的过程 接下来点击图 3-6 中的 Button 按钮, 开启第二个 Activity, 如图 3-8 所示 图 3-8 第二个 Activity 界面 当第一个界面跳转到第二个界面时,Log 窗口会打印 Activity01 和 Activity02 生命周期中的执行 方法, 对应的 Log 信息, 如图 3-9 所示 图 3-9 跳转时 Activity 生命周期从图 3-9 可以看到, 当跳转到第二个界面时,Activity01 首先失去焦点执行了 onpause() 方法, 然后 Activity02 依次执行了 oncreate() onstart() onresume() 方法从创建到前台可见, 这时 Activity01 执行了 onstop() 方法 现在再观察一下从第二个 Activity 按返回键回到第一个 Activity 生命周期的 Log, 如图 3-10 所示

图 3-10 返回第一个 Activity 从图 3-10 可以看到, 点击返回键之后,Activity02 同样先执行了 onpause() 方法, 然后 Activity01 执行了 onrestart() onstart() onresume() 方法, 随后 Activity02 才彻底关闭, 执行了 onstop() ondestory() 在 Activity01 打开 Activity02 时,Activity01 并没有执行 finish() 方法而是执行了 onstop() 方法 因此从 Activity02 返回到 Activity01 时,Activity01 执行了 onrestart() 方法 从 Log 窗口打印的日志可以看出,Activity 失去焦点时, 首先必然会执行 onpause() 方法, 因此 项目中需要保存数据时, 可以在 onpause() 方法中保存 同时当两个 Activity 跳转时,Activity01 会先 失去焦点让 Activity02 得到焦点, 等到 Activity02 完全显示在前台时 Activity01 才会切换到后台 M 脚下留心 : 横竖屏切换时的生命周期 现实生活中, 使用手机时会根据不同情况进行横竖屏切换 当手机横竖屏切换时,Activity 会销 毁重建 ( 模拟器中横竖屏切换可以使用 ctrl+f11) 这种情况对的实际开发肯定会有影响, 如果不希望在横竖屏切换时 Activity 被销毁重建, 可以 在 AndroidManifest.xml 文件中设置 Activity 的 android:configchanges 的属性, 这样无论怎样切换 Activity 都不会销毁重新创建, 具体代码如下所示 : android:configchanges="orientation keyboardhidden screensize" 如果希望某一个界面一直处于竖屏或者横屏状态, 不随手机的晃动而改变, 同样可以在清单文 件中通过设置 Activity 的参数来完成, 具体代码如下所示 : 竖屏 :android: screenorientation="portrait" 横屏 :android: screenorientation="landscape" & 多学一招 :View 的点击事件 Android 程序中 View 的点击事件共有四种, 除了上述讲解的在布局文件中为按钮设置 onclick 属性指定点击方法名之外, 还有三种方式用于设置 View 的点击事件, 这三种方式都用到了 OnClickListener 接口, 只不过是不同形式而已 OnClickListener 是监听 View 点击事件的接口, 接口中定义控件被点击时的回调方法 onclick() View 需要在 setonclicklistener(onclicklistener listener) 方法的参数中传入 OnClickListener 接口监听 View 的点击事件 下面针对这三种形式以及 OnClickListener 接口的使用进行讲解 1 创建内部类 创建一个内部类实现 OnClickListener 接口并重写 onclick() 方法, 在方法中写入点击事件的逻辑 内部类写完之后需要为按钮设置 setonclicklistener(listener listener) 属性, 在参数中传入之前创建 好的内部类对象即可, 这样当点击按钮时就会自动触发内部类中的 onclick() 方法调用事件逻辑 这里比较重要的一点, 要为按钮设置点击事件前要先获取到该控件的引用, 需要在布局文件中 为按钮设置 id 属性, 在代码中使用 findviewbyid(r.id) 方法得到该控件的 View 对象, 最后通过强制 类型转换得到该控件, 具体代码如下 : 为控件设置 id 属性 <Button

andorid:id="@+id/button1"// 为控件设置 id 属性 /> 得到控件引用, 创建内部类实现 OnClickListener 接口 protected void oncreate(bundle savedinstancestate) { super.oncreate(savedinstancestate); setcontentview(r.layout.activity_main); Button button1 = (Button) findviewbyid(r.id.button1); Button button2 = (Button) findviewbyid(r.id.button2); // 传入实现了 OnClickListener 接口的类的对象 button1.setonclicklistener(new MyButton()); button2.setonclicklistener(new MyButton()); } private class MyButton implements OnClickListener { @Override public void onclick(view v) { switch(v.getid()) { case R.id.button: Log.i(" 定义属性响应按钮点击事件 "); break; case R.id.button1: Log.i(" 定义属性响应按钮点击事件 "); break; } } } 使用这种点击事件的好处是, 当按钮较多时可以在 onclick(view v) 方法中使用 switch 语句 case 属性设置各自不同的点击事件逻辑 2 主类中实现 OnClickListener 接口除了创建内部类实现 OnClickListener 接口之外, 还可以在主类中实现该接口然后重写 onclick() 方法, 并通过 switch 语句判断是哪个按钮的被点击, 然后执行相应操作, 具体代码如下 : public class MainActivity extends Activity implements OnClickListener { protected void oncreate(bundle savedinstancestate) { super.oncreate(savedinstancestate); setcontentview(r.layout.activity_main); Button button1 = (Button) findviewbyid(r.id.button1); Button button2 = (Button) findviewbyid(r.id.button2); // 按钮绑定接口 button1.setonclicklistener(this); button2.setonclicklistener(this); } // 在重载的方法中实现点击设置 @Override public void onclick(view v) {

switch (v.getid()) { case R.id.button: Log.i(" 定义属性响应按钮点击事件 "); break; case R.id.button1: Log.i(" 定义属性响应按钮点击事件 "); break; } } } 需要注意的是,button.setOnClickListener(this); 方法中接收了一个参数 this, 这个 this 代表的是该 Activity 的引用, 由于 Activity 实现了 OnClickListener 接口, 所以在这里 this 代表了 OnClickListener 的引用, 在方法中传入 this 就代表该控件绑定了点击事件的接口 3 匿名内部类当按钮较少或者只有一个按钮时, 就不需要再单独创建一个类实现 OnclickListener 接口了, 可以直接创建 OnClickListener 的匿名内部类传入按钮的 setonclicklistener() 参数中, 具体代码如下 : Button button1 = (Button) findviewbyid(r.id.button1); button1.setonclicklistener(new OnClickListener() { @Override public void onclick(view v) { Log.i(" 定义属性响应按钮点击事件 "); } }); 按钮的点击事件学完了, 这里需要注意的是, 在实现 OnClickListener 接口时该接口在 Android 的两个包下面都有, 分别是 android.view.view 和 andriod.content.dialoginteface 要为按钮设置点击事件要导入 android.view.view 包 3.2 Activity 的启动模式 Android 采用任务栈 (Task) 的方式来管理 Activity 的实例, 当启动一个应用时,Android 就会 为之创建一个任务栈 先启动的 Activity 压在栈底, 后启动的 Activity 放在栈顶, 通过启动模式可以 控制 Activity 在任务栈中的加载情况, 本节将针对 Activity 的启动模式进行详细地讲解 3.2.1 Android 下的任务栈 在开发 Android 应用时, 经常会涉及一些消耗大量系统内存的情况, 例如视频播放 大量图片或者程序中开启多个 Activity 没有及时关闭等, 会导致程序出现错误 为了避免这种问题,Google 提供了一套完整的机制让开发人员控制 Android 中的任务栈 Android 系统中的任务栈, 类似于一个容器, 用于管理所有的 Activity 实例 在存放 Activity 时, 满足 先进后出 (First-In/Last-Out) 的原则 接下来通过一个图例来说明任务栈中如何存放 Activity, 如图 3-11 所示

进栈 出栈 Top Activity n... Base Activity1 图 3-11 Android 中的任务栈 从图 3-11 可以看出, 先加入任务栈中的 Activity 会处于容器下面, 后加入的处于容器上面, 而 从任务栈中取出 Activity 是从最顶端先取出, 最后取出的是最底端的 Activity 3.2.2 Activity 的四种启动模式 在实际开发中, 应根据特定的需求为每个 Activity 指定恰当的启动模式 Activity 的启动模式有四种, 分别是 standard singletop singletask 和 singleinstance 在 AndroidManifest.xml 中, 通过 <activity> 标签的 android:launchmode 属性可以设置启动模式 下面针对这四种启动模式分别进行详细地讲解 1 standard 标准模式 standard 是 Activity 默认的启动模式, 在不指定 Activity 启动模式的情况下, 所有 Activity 使用的都是 standard 这种模式 因此, 前面使用的 Activity 都是 standard 启动模式 在 standard 模式下, 每当启动一个新的 Activity, 它就会进入任务栈, 并处于栈顶的位置, 对于使用 standard 模式的 Activity, 系统不会判断该 Activity 在栈中是否存在, 每次启动都会创建一个新的实例 接下来通过一个图例向大家展示 standard 模式下 Activity 在栈中的存放情况, 如图 3-12 所示 第 3 个进栈 第 2 个进栈 第 1 个进栈 第三个启动界面 Activity03 第二个启动界面 Activity02 第一个启动界面 Activity01 第 1 个出栈 第 2 个出栈 第 3 个出栈 图 3-12 standard 模式启动从图 3-12 中可以看出, 在 standard 启动模式下 Activity01 最先进栈, 其次是 Activity02, 最后是 Activity03, 出栈时,Activity03 最先出栈, 其次是 Activity02, 最后是 Activity01, 满足 先进后出 的原则 2 singletop 模式 singletop 启动模式与 standard 类似, 不同的是, 当启动的 Activity 已经位于栈顶时, 则直接使用它不创建新的实例 如果启动的 Activity 没有位于栈顶时, 则创建一个新的实例位于栈顶

接下来通过一个图例为大家展示 singletop 模式下 Activity 在栈中的存放情况, 如图 3-13 所示 当再次启动的界面位于栈顶, 则复用 Activity03 当再次启动的界面不位于栈顶, 则重新创建实例 Activity04 第 3 个进栈 第 2 个进栈 第 1 个进栈 第三个启动界面 Activity03 第二个启动界面 Activity02 第一个启动界面 Activity01 图 3-13 singletop 启动模式从图 3-13 中可以看出, 当前栈顶中的元素是 Activity03, 如果再次启动的界面还是 Activity03, 则复用当前栈顶的 Activity 实例, 如果再次启动的界面没有位于栈顶, 则会重新创建一个实例 3 singletask 模式如果希望 Activity 在整个应用程序中只存在一个实例, 可以使用 singletask 模式, 当 Activity 的启动模式指定为 singletask, 每次启动该 Activity 时, 系统首先会检查栈中是否存在该活动的实例, 如果发现已经存在则直接使用该实例, 并将当前 Activity 之上的所有 Activity 出栈, 如果没有发现则创建一个新的实例 接下来通过一个图例为大家展示 singletask 模式下 Activity 在栈中的存放情况, 如图 3-14 所示 启动 Activity02, 移除 Activity02 之前的实例, 复用 Activity02 Activity02 第 3 个进栈 第 2 个进栈 第 1 个进栈 第三个启动界面 Activity03 第二个启动界面 Activity02 第一个启动界面 Activity01 移除 Activity03 图 3-14 singletask 模式从图 3-14 可以看出, 当再次启动 Activity02 时, 并没有新创建实例, 而是将 Activity03 实例移除, 复用 Activity02 实例, 这就是 singletask 模式, 让某个 Activity 在当前栈中只存在一个实例 4 singleinstance 模式在程序开发中, 如果需要 Activity 在整个系统中都只有一个实例, 这时就需要用到 singleinstance 模式, 不同于上述三种模式, 指定为 singleinstance 模式的 Activity 会启动一个新的任务栈来管理这个 Activity

singleinstance 模式加载 Activity 时, 无论从哪个任务栈中启动该 Activity, 只会创建一个 Activity 实例, 并且会使用一个全新的任务栈来装载该 Activity 实例 采用这种模式启动 Activity 会分为以下两种情况, 具体如下 : 第一种 : 如果要启动的 Activity 不存在, 系统会先创建一个新的任务栈, 再创建该 Activity 的实例, 并把该 Activity 加入栈顶, 如图 3-15 所示 任务栈 A 任务栈 B 第一次打开 Activity01 Activity01 第二次打开 Activity02 开启的任务栈 Activity02 图 3-15 第一种情况第二种 : 如果要启动的 Activity 已经存在, 无论位于哪个应用程序或者哪个任务栈中 系统都会把该 Activity 所在的任务栈转到前台, 从而使该 Activity 显示出来 至此,Activity 的四种启动模式已经讲解完成, 在实际开发中, 需要根据实际情况来选择合适的启动模式即可 3.3 在 Activity 中使用 Intent 3.3.1 Intent 介绍 通信技术不发达时, 人们通过信件的方式互相通信, 其中邮递员就起到了传递信息的作用 在 Android 系统中, 组件之间也可以完成通信功能, 此时就需要使用 Intent Intent 中文翻译为 意图,Intent 最常见的用途是绑定应用程序组件, 并在应用程序之间进行通信 Intent 一般用于启动 Activity 启动服务 发送广播等, 承担了 Android 应用程序三大核心组件相互间的通信功能 接下来通过一个表来列举 Intent 启动组件的常用的方法, 具体如表 3-1 所示 表 3-1 Intent 开启的三个组件方法声明功能描述 startactivity(intent intent) Activity startactivityforresult(intent intent) ComponentName startservice(intent intent) Service boolean bindservice(intent service,serviceconnection conn,int flags) sendbroadcast(intent intent) BroadcastReceiver sendbroadcast(intent intent,string receiverpermission) sendorderedbroadcast(intent intent,string receiverpermission) 在表 3-1 中, 列举了通过 Intent 来开启不同组件的常用方法, 需要注意的是, 使用 Intent 开启 Activity 和开启 Service 只有两个方法, 而开启 BroadcastReceiver 有多个方法, 在此只列举了三个常用的方法, 初学者感兴趣可以自己查阅相关 API 进行学习

3.3.2 显式意图和隐式意图 Android 中 Intent 寻找目标组件的方式分为两种, 一种是显式意图和一种是隐式意图 接下来分别针对这两种意图进行详细地讲解 1 显式意图显式意图, 即在通过 Intent 启动 Activity 时, 需要明确指定激活组件的名称 在程序中, 如果需要在本应用中启动其他的 Activity 时, 可以使用显式意图来启动 Activity, 其示例代码具体如下 : Intent intent = new Intent(this, Activity02.class);// 创建 Intent 对象 startactivity(intent); // 开启 Activity 在上述示例代码中, 通过 Intent 的构造方法来创建 Intent 对象 构造方法接收两个参数, 第一个参数 Context 要求提供一个启动 Activity 的上下文, 第二个参数 Class 则是指定要启动的目标 Activity, 通过构造方法就可以构建出 Intent 对象 除了通过指定类名开启组件外, 显式意图还可以根据目标组件的包名 全路径名来指定开启组件, 代码如下所示 : intent.setclassname("cn.itcast.xxx","cn.itcast.xxx.xxxx"); startactivity(intent); 在上述实例代码中, 通过 setclassname( 包名, 类全路径名 ) 函数指定要开启组件的包名和全路径名来启动另一个组件 Activity 类中提供了一个 startactivity(intent intent) 方法, 该方法专门用于开启 Activity, 它接收一个 Intent 参数, 这里将构建好的 Intent 传入该方法即可启动目标 Activity 使用这种方式开启的 Activity, 意图 非常明显, 因此称之为显式意图 2 隐式意图没有明确指定组件名的 Intent 称为隐式意图 Android 系统会根据隐式意图中设置的动作 (action) 类别 ( category) 数据 ( Uri 和数据类型 ) 找到最合适的组件 具体代码如下所示 : <activity android:name="com.itcast.intent.activity02"> <intent-filter> <!-- 设置 action 属性, 需要在代码中根据所设置的 name 打开指定的组件 --> <action android:name="cn.itscast.xxx"/> <category android:name="android.intent.category.default"/> </intent-filter> </activity> 在上述代码中,<action> 标签指明了当前 Activity 可以响应的动作为 "cn.itscast.xxx", 而 <category> 标签则包含了一些类别信息, 只有当 <action> 和 <category> 中的内容同时匹配时,Activity 才会被开启 使用隐示意图开启 Activity 的示例代码如下所示 : Intent intent = new Intent(); // 设置动作和清单文件一样 intent.setaction("cn.itscast.xxx"); startactivity(intent); 在上述代码中,intent 指定了 setaction( cn.itscast.xxx ); 这个动作, 但是并没有指定 category, 这是因为清单文件中配置的 "android.intent.category.default" 是一种默认的 category, 在调用 startactivity() 方法时, 会自动将这个 category 添加到 Intent 中

在上述两种意图中, 显式意图开启组件时必须要指定组件的名称, 一般只在本应用程序切换组 件时使用 而隐式意图的功能要比显式意图更加强大, 不仅可以开启本应用的组件还可以开启其他 应用的组件, 例如打开系统自带的照相机 浏览器等 3.3.3 案例 打开系统照相机 在实际开发中, 避免不了要调用其他应用程序的组件 例如, 在开发新浪微博时, 需要启动系统的相机功能 通过前面的讲解可知, 使用隐式意图可启动其他应用程序的组件 接下来通过案例 打开系统照相机 向大家演示如何使用隐式意图, 具体步骤如下 : 1 创建程序创建一个名为 打开系统照相机 的 Android 工程, 将包名修改为 cn.itcast.opencamera 设计用户交互界面, 具体如图 3-16 所示 图 3-16 程序主界面程序对应布局文件 (activity_main.xml) 的代码如下所示 : <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".mainactivity" > <Button android:id="@+id/opencamera" android:layout_width="wrap_content" android:layout_centerhorizontal="true" android:layout_centervertical="true" android:text=" 打开照相机 " /> </RelativeLayout> 2 清单文件中的配置

由于模拟器打开系统相机会直接报错, 为了能让初学者在模拟器上看到效果, 因此在这里创建 一个 Activity02 用来模拟系统相机 具体代码如下所示 : <activity android:name="cn.itcast.opencamera.activity02" > <intent-filter> <action android:name="android.media.action.image_capture" /> <category android:name="android.intent.category.default" /> </intent-filter> </activity> 需要注意的是, 这里配置的 action 和 category 与系统相机的 action 和 category 一致 当使用隐 式意图来开启 Activity 时, 系统会找到两个符合条件的 Activity, 因此会弹出一个选择的对话框, 让 用户来选择要打开的页面 3 隐式意图开启照相机 在 MainActivity 中, 通过隐式意图开启系统中的照相机, 具体代码如下所示 : 1 public class MainActivity extends Activity { 2 protected void oncreate(bundle savedinstancestate) { 3 super.oncreate(savedinstancestate); 4 setcontentview(r.layout.activity_main); 5 // 获取界面上的按钮 6 Button button = (Button) findviewbyid(r.id.opencamera); 7 // 给 Button 按钮添加点击事件 8 button.setonclicklistener(new OnClickListener() { 9 public void onclick(view v) { 10 Intent intent = new Intent(); 11 intent.setaction("android.media.action.image_capture"); 12 intent.addcategory("android.intent.category.default"); 13 startactivity(intent); 14 } 15 }); 16 } 17 } 上述代码中, 实现了通过隐式意图开启照相机的功能 通过 setaction 设置需要开启 Activity 的 动 作 为 "android.media.action.image_capture", addcategory 设 置 类 别 "android.intent.category.default" 4 运行程序打开系统相机 接下来运行程序, 点击屏幕中的 打开照相机 按钮, 如图 3-17 所示

图 3-17 打开照相机在图 3-17 中, 当点击屏幕中的按钮后出现了一个选择界面, 左侧是系统照相机, 而右侧是自己创建的 Activity, 出现这种情况的原因是,Activity02 在清单文件中注册的 action 和 addcategory 是和系统中照相机一样 因此, 当用隐式意图找目标组件时, 会将自己创建的照相机和系统自带的照相机都显示在界面中 3.4 Activity 中的数据传递 3.4.1 数据传递方式 在 Android 开发中, 经常要在 Activity 之间传递数据 通过前面的讲解可知,Intent 可以用来开启 Activity, 同样它也可以用来在 Activity 之间传递数据 使用 Intent 传递数据只需调用 putextra() 方法将想要存储的数据存在 Intent 中即可 当启动了另一个 Activity 后, 再把这些数据从 Intent 中取出即可 例如 Activity01 中存储了一个字符串, 现在要将这个字符串传递到 Activity02 中, 可以使用如下代码 : String data = "Hello Activity02" Intent intent = new Intent(this,Activity02.class); intent.putextra("extra_data",data); startactivity(intent); 在上述代码中, 通过显式意图开启的 Activity02, 并通过 putextra() 方法传递了一个字符串 data putextra() 方法中第一个参数接收的是 key, 第二个参数接收的是 value 如果想要在 Activity02 中取出传递过来的数据, 可以使用如下代码 : Intent intent = getintent(); String data = = intent.getstringextra("extra_data"); Log.i("Activity02", data); 上述这种数据传递方式是最简单的一种数据传递方式, 还有一种传递数据的方式是调用 putextras() 方法传递数据, 该方法传递的是 Bundle 对象 调用 putextras() 方法传递数据可以使用如下代码 :

Bundle bundle = new Bundle(); bundle.putstring("name", "Linda"); bundle.putint("age", 20); Intent intent = new Intent(this,Activity02.class); intent.putextras(bundle); startactivity(intent); 如果想要在 Activity02 中取出上述方式传递的数据, 可以使用如下代码 : Intent intent = getintent(); Bundle bundle = intent.getextras(); String stuname = bundle.getstring("name"); int stuage = bundle.getstring("age"); 在上述代码中, 在接收 Bundle 对象封装的数据时, 需要先创建对应的 Bundle 对象, 然后再根据存入的 key 值取出 value 其实用 Intent 传递数据以及对象时, 它的内部也是调用了 Bundle 对象相应的 put() 方法, 也就是说 Intent 内部也是用 Bundle 来实现数据传递的, 只是封装了一层而已 3.4.2 案例 用户注册 为了让初学者掌握 Activity 中的数据传递, 接下来通过 用户注册 的案例来演示 Activity 中的数据传递, 案例实现的步骤如下 : 1 创建程序创建一个名为 用户注册 的应用程序, 将包名修改为 cn.itcast.passdata, 设计用户交互界面, 具体如图 3-18 所示 图 3-18 第一个 Activity 界面第一个 Activity 对应布局文件 (activity01.xml) 的代码如下所示 : <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" >

<LinearLayout android:id="@+id/regist_username" android:layout_width="match_parent" android:layout_centerhorizontal="true" android:layout_marginleft="10dp" android:layout_marginright="10dp" android:layout_margintop="22dp" android:orientation="horizontal" > <TextView android:layout_width="80dp" android:gravity="right" android:paddingright="5dp" android:text=" 用户名 :" /> <EditText android:id="@+id/et_name" android:layout_width="match_parent" android:hint=" 请输入您的用户名 " android:textsize="14dp" /> </LinearLayout> <LinearLayout android:id="@+id/regist_password" android:layout_width="match_parent" android:layout_below="@+id/regist_username" android:layout_centerhorizontal="true" android:layout_marginleft="10dp" android:layout_marginright="10dp" android:layout_margintop="5dp" android:orientation="horizontal" > <TextView android:layout_width="80dp" android:gravity="right" android:paddingright="5dp" android:text=" 密码 :" /> <EditText android:id="@+id/et_password" android:layout_width="match_parent" android:hint=" 请输入您的密码 " android:inputtype="textpassword"

android:textsize="14dp" /> </LinearLayout> <RadioGroup android:id="@+id/radiogroup" android:layout_width="wrap_content" android:layout_below="@+id/regist_password" android:layout_marginleft="30dp" android:contentdescription=" 性别 " android:orientation="horizontal" > <RadioButton android:id="@+id/radiomale" android:layout_width="wrap_content" android:checked="true" android:text=" 男 " > </RadioButton> <RadioButton android:id="@+id/radiofemale" android:layout_width="wrap_content" android:text=" 女 " /> </RadioGroup> <Button android:id="@+id/btn_send" android:layout_width="wrap_content" android:layout_below="@+id/radiogroup" android:layout_centerhorizontal="true" android:layout_margintop="24dp" android:text=" 提交用户信息 " /> </RelativeLayout> 在上述代码中, 定义了一个相对布局 RelativeLayout, 该布局中创建了一个 EditText 和一个 Button 按钮, 分别用于输入内容和点击发送按钮进行数据传递 2 创建接收数据 Activity 界面接下来在 PassData 程序中创建一个用于数据接收的界面 activity02.xml, 该界面的布局比较简单, 只添加了三个 TextView 用来展示用户信息, 因此不展示界面效果,activity02.xml 界面代码如下所示 : <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> <TextView android:id="@+id/tv_name"

android:layout_width="wrap_content" android:gravity="center" android:layout_margintop="10dp" android:textsize="20dp" /> <TextView android:id="@+id/tv_password" android:layout_width="wrap_content" android:gravity="center" android:layout_margintop="10dp" android:textsize="20dp" /> <TextView android:id="@+id/tv_sex" android:layout_width="wrap_content" android:gravity="center" android:layout_margintop="10dp" android:textsize="20dp" /> </LinearLayout> 2 编写界面交互代码(MainActivity) 当界面创建好之后, 需要在 Activity01 中编写与页面交互的代码, 用于实现数据传递, 具体代码如下所示 : 1 public class Activity01 extends Activity{ 2 private RadioButton manradio; 3 private RadioButton womanradio; 4 private EditText et_password; 5 private Button btn_send; 6 private EditText et_name; 7 protected void oncreate(bundle savedinstancestate) { 8 super.oncreate(savedinstancestate); 9 setcontentview(r.layout.activity01); 10 et_name = (EditText) findviewbyid(r.id.et_name); 11 et_password = (EditText) findviewbyid(r.id.et_password); 12 btn_send = (Button) findviewbyid(r.id.btn_send); 13 manradio = (RadioButton) findviewbyid(r.id.radiomale); 14 womanradio = (RadioButton) findviewbyid(r.id.radiofemale); 15 btn_send = (Button) findviewbyid(r.id.btn_send); 16 // 点击发送按钮进行数据传递 17 btn_send.setonclicklistener(new OnClickListener() { 18 public void onclick(view v) { 19 passdate(); 20 } 21 });

22 } 23 // 传递数据 24 public void passdate() { 25 // 创建 Intent 对象, 启动 Activity02 26 Intent intent = new Intent(this, Activity02.class); 27 // 将数据存入 Intent 对象 28 intent.putextra("name", et_name.gettext().tostring().trim()); 29 intent.putextra("password", et_password.gettext().tostring().trim()); 30 String str = ""; 31 if(manradio.ischecked()){ 32 str = " 男 "; 33 }else if(womanradio.ischecked()){ 34 str = " 女 "; 35 } 36 intent.putextra("sex", str); 37 startactivity(intent); 38 } 39 } 在上述代码中,passDate() 方法实现了获取用户输入数据, 并且将 Intent 作为载体进行数据传递 为了让初学者看到数据传递效果, 接下来再创建一个 Activity02, 用于接收数据并展示, 具体代码如 下所示 : 1 public class Activity02 extends Activity { 2 private TextView tv_name; 3 protected void oncreate(bundle savedinstancestate) { 4 super.oncreate(savedinstancestate); 5 setcontentview(r.layout.activity02); 6 // 拿到 Intent 对象 7 Intent intent=getintent(); 8 // 取出 key 对应的 value 值 9 String name = intent.getstringextra("name"); 10 String password = intent.getstringextra("password"); 11 String sex = intent.getstringextra("sex"); 12 tv_name =(TextView) findviewbyid(r.id.tv_name); 13 tv_password = (TextView) findviewbyid(r.id.tv_password); 14 tv_sex = (TextView) findviewbyid(r.id.tv_sex); 15 tv_name.settext(" 用户名 :"+name); 16 tv_password.settext(" 密 码 :"+password); 17 tv_sex.settext(" 性 别 :"+sex); 18 } 19 } 在上述代码中, 第 7-17 行代码通过 getintent() 方法获取到 Intent 对象, 然后通过该对象的 getstringextra() 方法拿到输入的用户名, 并将得到的用户名绑定在 TextView 控件中进行显示 需要 注意的是,getStringExtra(String str) 方法传入的参数必须是 Activity01 中 intent.putextra() 方法中传入 的 key, 否则会返回 null

3 清单文件的配置接下来在清单文件中, 配置 Activity, 具体代码如下所示 : <application android:allowbackup="true" android:icon="@drawable/ic_launcher" android:label="@string/app_name" android:theme="@style/apptheme" > <activity android:name="cn.itcast.passdata.activity01" android:label=" 填写用户信息 " > <intent-filter> <action android:name="android.intent.action.main" /> <category android:name="android.intent.category.launcher" /> </intent-filter> </activity> <activity android:name="cn.itcast.passdata.activity02" android:label=" 展示用户信息 " > </activity> </application> 需要注意的是,android:label 属性使用来指定显示在标题栏上的名称的, 如果 Activity 设置了该属性, 则跳到该 Activity 页面时标题栏会显示在 Activity 中配置的名称, 否则显示在 Application 中配置的名称 3 运行程序注册信息程序编写完成后, 接下来运行程序进行测试, 首先在 Activity01 的文本框中输入 Linda, 点击 发送数据 按钮, 此时会跳转到 Activity02 界面, 显示输入的信息, 如图 3-19 所示 图 3-19 注册用户运行界面 从图 3-19 中可以看出,Activity01 中输入的数据 Linda 成功的传递给 Activity02, 这就是使

用 Intent 进行不同界面传递数据的用法 3.4.3 回传数据 在使用新浪微博 APP 时, 能发现在微博发布页面进入图库选择图片后, 会回到微博发布页面并带回了图片选择页面的图片信息 由于这种需求十分常见, 因此 Andorid 提供了一个 startactivityforresult() 方法, 来实现回传数据 接下来通过一段示例代码来显示如何使用 startactivityforresult(),activity01 具体代码如下所示 : Intent intent = new Intent(this,Activity02.class); startactivityforresult(intent,1); 上述示例代码中,startActivityForResult() 方法接收两个参数, 第一个参数是 Intent, 第二个参数是请求码, 用于在判断数据的来源 接下来在 Activity02 中添加数据返回的示例代码, 具体如下所示 : Intent intent = new Intent(); intent.putextra("extra_data","hello Activity01"); setresult(1,intent); finish(); 上述代码中, 实现了回传数据的功能 其中 setresult() 方法接收两个参数, 第一个参数 resultcode 结果码, 一般使用 0 或 1 第二个参数则是把带有数据的 Intent 传递回去, 最后调用 finish() 方法销毁当前 Activity 由于使用了 startactivityforresult() 方法启动 Activity02, 因此会在 Actiivity01 页面回调 onactivityresult() 方法, 需要在 Activity01 中重写该方法来获取返回的数据, 具体代码如下所示 : protected void onactivityresult(int requestcode, int resultcode, Intent data) { super.onactivityresult(requestcode, resultcode, data); if (resultcode == 1) { String data = data.getstringextra("extra_data"); Log.i("Activity01",data); } } 在上述代码中, 实现了获取返回数据的功能 onactivityresult() 方法有三个参数, 第一个参数 requestcode, 表示在启动 Activity 时传递的请求码 ; 第二个参数 resultcode, 表示在返回数据时传入结果码 ; 第三个参数 data, 表示携带返回数据的 Intent 需要注意的是, 在一个 Activity 中很可能调用 startactivityforresult() 方法启动多个 Activity, 每一个 Activity 返回的数据都会回调到 onactivityresult() 这个方法中, 因此, 首先要做的就是通过检查 requestcode 的值来判断数据来源, 确定数据是从 Activity02 返回的, 然后再通过 resultcode 的值来判断数据处理结果是否成功, 最后从 data 中取出数据并打印, 这样就完成了 Activity 中数据返回的功能 3.4.4 案例 装备选择 为了让初学者掌握 Activity 回传数据, 接下来通过案例装备选择来演示 Activity 回传数据 本案 例实现了购买装备增加生命值的功能, 实现案例的具体步骤如下 : 1 创建程序

创建一个名为 装备选择 的工程, 将包名修改为 cn.itcast.select 设计用户交互界面, 具体如 图 3-20 所示 图 3-20 装备选择主界面装备选择程序对应的布局文件 (activity_main.xml) 如下所示 : <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" android:gravity="center" tools:context=".mainactivity" > <ImageView android:id="@+id/pet_imgv" android:layout_width="wrap_content" android:layout_gravity="center_horizontal" android:layout_marginbottom="5dp" android:layout_margintop="30dp" android:src="@drawable/baby" /> <TextView android:id="@+id/pet_dialog_tv" android:layout_width="wrap_content" android:layout_gravity="center_horizontal" android:layout_marginbottom="25dp" android:gravity="center" android:text=" 主人, 快给小宝宝购买装备吧 " /> <TableLayout android:layout_width="fill_parent"

android:layout_gravity="center" android:layout_marginbottom="20dp" > <TableRow android:layout_width="fill_parent" > <TextView android:layout_width="0dip" android:layout_weight="1" android:text=" 生命值 :" android:textcolor="@android:color/black" android:textsize="14sp" /> <ProgressBar android:id="@+id/progressbar1" style="?android:attr/progressbarstylehorizontal" android:layout_width="0dip" android:layout_gravity="center" android:layout_weight="2" /> <TextView android:id="@+id/tv_life_progress" android:layout_width="0dip" android:layout_weight="1" android:text="0" android:gravity="center" android:textcolor="#000000" /> </TableRow> <TableRow android:layout_width="fill_parent" > <TextView android:layout_width="0dip" android:layout_weight="1" android:text=" 攻击力 :" android:textcolor="@android:color/black" android:textsize="14sp" /> <ProgressBar android:id="@+id/progressbar2" style="?android:attr/progressbarstylehorizontal" android:layout_width="0dip"

android:layout_weight="2" /> <TextView android:id="@+id/tv_attack_progress" android:layout_width="0dip" android:layout_weight="1" android:text="0" android:gravity="center" android:textcolor="#000000" /> </TableRow> <TableRow android:layout_width="fill_parent" > <TextView android:layout_width="0dip" android:layout_weight="1" android:text=" 敏捷 :" android:textcolor="@android:color/black" android:textsize="14sp" /> <ProgressBar android:id="@+id/progressbar3" style="?android:attr/progressbarstylehorizontal" android:layout_width="0dip" android:layout_weight="2" /> <TextView android:id="@+id/tv_speed_progress" android:layout_width="0dip" android:layout_weight="1" android:text="0" android:gravity="center" android:textcolor="#000000" /> </TableRow> </TableLayout> <RelativeLayout android:layout_width="match_parent" > <Button android:id="@+id/btn_master" android:layout_width="wrap_content" android:layout_alignparentleft="true"

android:layout_alignparenttop="true" android:drawableright="@android:drawable/ic_menu_add" android:onclick="click" android:drawablepadding="3dp" android:text=" 主人购买装备 " android:textsize="14sp" /> <Button android:id="@+id/btn_baby" android:layout_width="wrap_content" android:layout_alignparentright="true" android:layout_alignparenttop="true" android:drawablepadding="3dp" android:drawableright="@android:drawable/ic_menu_add" android:onclick="click2" android:text=" 小宝宝购买装备 " android:textsize="14sp" /> </RelativeLayout> </LinearLayout> 上述布局代码使用到了控件 ProgressBar( 进度条 ), 它是用来显示小宝宝的生命值 攻击力和敏捷度的 ProgressBar 通常用于访问网络展示 loading 对话框以及下载文件时显示的进度 它有两种表现形式, 一种是水平的 ( 即本案例用到的 ), 另一种是环形的 它的表现形式是由 style 属性控制的,ProgressBar 几个常用方法属性如下所示 : l style 属性 : 控制 ProgressBar 的表现形式, 水平进度条需设置 style 的属性值为 "?android:attr/progressbarstylehorizontal", 环形进度条需设置 style 的属性值为 "?android:attr/progressbarstylelarge"; l setmax() 方法 : 设置进度条的最大值 ; l setprogress() 方法 : 设置当前进度 ; l getprogress() 方法 : 拿到当前进度 ; 2 创建装备界面创建装备界面 activity_shop.xml, 该界面是用来展示装备的, 界面编写完成后, 运行效果如图 3-21 所示

图 3-21 购买装备页面购买装备界面 (activity_shop.xml) 对应的布局文件如下所示 : <?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/rl" android:layout_width="match_parent" android:orientation="vertical" > <View android:layout_width="30dp" android:layout_height="30dp" android:background="@android:drawable/ic_menu_info_details" android:layout_centervertical="true" android:layout_alignparentleft="true"/> <TextView android:id="@+id/tv_name" android:layout_width="wrap_content" android:layout_centervertical="true" android:layout_marginleft="60dp" android:text=" 商品名称 "/> <LinearLayout android:layout_width="wrap_content" android:layout_centerinparent="true" android:orientation="vertical"> <TextView android:id="@+id/tv_life" android:layout_width="wrap_content"

android:textsize="13sp" android:text=" 生命值 "/> <TextView android:id="@+id/tv_attack" android:layout_width="wrap_content" android:textsize="13sp" android:text=" 攻击力 "/> <TextView android:id="@+id/tv_speed" android:layout_width="wrap_content" android:textsize="13sp" android:text=" 速度 "/> </LinearLayout> </RelativeLayout> 3 创建 ItemInfo 类在程序中创建一个 cn.itcast.domain 包, 在该包中创建一个 ItemInfo 类, 用于封装装备信息, 具体代码如下所示 : 1 public class ItemInfo implements Serializable{ 2 private String name; 3 private int acctack; 4 private int life; 5 private int speed; 6 public ItemInfo(String name, int acctack, int life, int speed) { 7 this.name = name; 8 this.acctack = acctack; 9 this.life = life; 10 this.speed = speed; 11 } 12 public String getname() { 13 return name; 14 } 15 public void setname(string name) { 16 this.name = name; 17 } 18 public int getacctack() { 19 return acctack; 20 } 21 public void setacctack(int acctack) { 22 this.acctack = acctack; 23 } 24 public int getlife() {

25 return life; 26 } 27 public void setlife(int life) { 28 this.life = life; 29 } 30 public int getspeed() { 31 return speed; 32 } 33 public void setspeed(int speed) { 34 this.speed = speed; 35 } 36 public String tostring() { 37 return " [name=" + name + ", acctack=" + acctack + ", life=" + life 38 + ", speed=" + speed + "]"; 39 } 40 } 需要注意的是,Intent 除了传递基本类型之外, 只能传递 Serializable 或 Parcelable 类型的数据 为了方便数据传递, 在这里让 ItemInfo 类实现 Serializable 接口 4 创建 ShopActivity ShopActivity 是用来展示装备信息的, 当点击 ShopActivity 的装备时, 会调回 MainActivity 并将 装备信息回传给 MainActivity,ShopActivity 的具体代码如下所示 : 1 public class ShopActivity extends Activity implements OnClickListener { 2 private ItemInfo iteminfo; 3 protected void oncreate(bundle savedinstancestate) { 4 super.oncreate(savedinstancestate); 5 setcontentview(r.layout.activity_shop); 6 iteminfo = new ItemInfo(" 金剑 ", 100, 20, 20); 7 findviewbyid(r.id.rl).setonclicklistener(this); 8 TextView mlifetv = (TextView)findViewById(R.id.tv_life); 9 TextView mnametv = (TextView)findViewById(R.id.tv_name); 10 TextView mspeedtv = (TextView)findViewById(R.id.tv_speed); 11 TextView mattacktv = (TextView) findviewbyid(r.id.tv_attack); 12 //TextView 显示字符串, 这里传入 int 值编译不会报错, 运行会出错 13 mlifetv.settext(" 生命值 +"+iteminfo.getlife() ); 14 mnametv.settext(iteminfo.getname() + ""); 15 mspeedtv.settext(" 敏捷度 +"+iteminfo.getspeed()); 16 mattacktv.settext(" 攻击力 +"+iteminfo.getacctack()); 17 } 18 @Override 19 public void onclick(view v) { 20 // TODO Auto-generated method stub 21 switch (v.getid()) { 22 case R.id.rl: 23 Intent intent = new Intent();

24 intent.putextra("equipment", iteminfo); 25 setresult(1, intent); 26 finish(); 27 break; 28 } 29 } 30 } 上述代码中的重点代码是第 23-26 行, 从这段代码中可以看出, 使用 setresult() 方法跳转 Activity 不需要指定要跳转的 Activity setreult() 方法的作用是让当前 Activity 返回到它的调用者, 在这里可 以理解为让 ShopActivity 返回到 MainActivity 5 编写界面交互代码(MainActivity) 接下来编写 MainActivity,MainActivity 主要用于响应按钮的点击事件, 并将返回的装备信息显 示到指定的 ListView 控件中, 具体代码如下所示 : 1 public class MainActivity extends Activity { 2 private ProgressBar mprogressbar1; 3 private ProgressBar mprogressbar2; 4 private ProgressBar mprogressbar3; 5 private TextView mlifetv; 6 private TextView mattacktv; 7 private TextView mspeedtv; 8 protected void oncreate(bundle savedinstancestate) { 9 super.oncreate(savedinstancestate); 10 setcontentview(r.layout.activity_main); 11 mlifetv = (TextView) findviewbyid(r.id.tv_life_progress); 12 mattacktv = (TextView) findviewbyid(r.id.tv_attack_progress); 13 mspeedtv = (TextView) findviewbyid(r.id.tv_speed_progress); 14 initprogress(); // 初始化进度条 15 } 16 private void initprogress() { 17 mprogressbar1 = (ProgressBar) findviewbyid(r.id.progressbar1); 18 mprogressbar2 = (ProgressBar) findviewbyid(r.id.progressbar2); 19 mprogressbar3 = (ProgressBar) findviewbyid(r.id.progressbar3); 20 mprogressbar1.setmax(1000); // 设置最大值 1000 21 mprogressbar2.setmax(1000); 22 mprogressbar3.setmax(1000); 23 } 24 // 开启新的 activity 并且想获取他的返回值 25 public void click(view view) { 26 Intent intent = new Intent(this, ShopActivity.class); 27 startactivityforresult(intent, 1); // 返回请求结果, 请求码为 1 28 } 29 public void click2(view view) { 30 Intent intent = new Intent(this, ShopActivity.class); 31 startactivityforresult(intent, 1);

32 } 33 @Override 34 protected void onactivityresult(int requestcode, 35 int resultcode, Intent data) { 36 super.onactivityresult(requestcode, resultcode, data); 37 if (data!= null) { 38 // 判断结果码是否等于 1, 等于 1 为主人添加装备, 等于 2 为宝宝添加装备 39 if (resultcode == 1) { 40 if (requestcode == 1) { 41 ItemInfo info= 42 (ItemInfo) data.getserializableextra("equipment"); 43 // 更新 ProgressBar 的值 44 updateprogress(info); 45 } 46 } 47 } 48 } 49 // 更新 ProgressBar 的值 50 private void updateprogress(iteminfo info) { 51 int progress1 = mprogressbar1.getprogress(); 52 int progress2 = mprogressbar2.getprogress(); 53 int progress3 = mprogressbar3.getprogress(); 54 mprogressbar1.setprogress(progress1+info.getlife()); 55 mprogressbar2.setprogress(progress2+info.getacctack()); 56 mprogressbar3.setprogress(progress3+info.getspeed()); 57 mlifetv.settext(mprogressbar1.getprogress()+""); 58 mattacktv.settext(mprogressbar2.getprogress()+""); 59 mspeedtv.settext(mprogressbar3.getprogress()+""); 60 } 61 } 上述代码中第 34-48 行, 实现了获取 ShopActivity 的装备信息, 根据装备信息更新 ProgressBar 6 清单文件的配置 使用 Activity 时需要在清单文件中配置, 具体代码如下所示 : <activity android:name="cn.itcast.select.mainactivity" android:label="@string/app_name" > <intent-filter> <action android:name="android.intent.action.main" /> <category android:name="android.intent.category.launcher" /> </intent-filter> </activity> <activity android:name="cn.itcast.select.shopactivity" > </activity> 7 运行程序选择装备

运行程序, 在主界面中分别点击 主人购买装备 小宝宝购买装备 按钮, 此时会跳转至装 备展示界面, 装备购买成功后会看到如图 3-22 所示的界面 图 3-22 选择装备从图 3-22 可以看出, 主人购买装备或小宝宝购买装备都完成了, 购买的装备会显示在界面的 ListView 中, 并且进度条的值会随着装备的购买而增加 至此,Activity 数据传递的功能就讲解完了 3.5 本章小结 本章主要讲解了 Activity 的相关知识, 包括 Activity 入门 Activity 启动模式 Intent 的使用以及 Activity 中的数据传递, 并在讲解各个知识点时都编写了实用的案例用来巩固知识点 由于凡是有界 面的 Android 程序都会使用到 Activity, 因此, 要求初学者必须熟练掌握该组件的使用 3.6 习题 一 填空题 1 Activity 生命周期的三种状态分别是 和 2 Activity 的四种启动模式是 和 3 Android 中 Intent 寻找目标组件的方式有两种 和 4 Activity 生命周期中 回到前台, 再次可见时执行 时调用的方法是 5 Andorid 提供了一个 方法来实现回传数据 二 判断题 1 Activity 是 Android 应用程序的四大组件之一 ( ) 2 Intent 一般只用于启动 Activity 不能开启广播和服务 ( ) 3 Intent 可以用来开启 Activity, 同样它也可以用来在 Activity 之间传递数据 ( ) 4 Activity 默认的启动模式是 singletop 模式 ( ) 5 在数据传递时, 如果需要获取返回的数据, 需要使用 onactivityresult() 方法 ( )

三 选择题 1 一个应用程序默认会包含( ) 个 Activity A 1 个 B 5 个 C 10 个 D 若干个 2 下列方法中,Activity 从启动到关闭不会执行的是 ( ) A oncreate() B onstart() C onresume() D onrestart() 3 下列组件中, 不能使用 Intent 启动的是 ( ) A Activity B 启动服务 C 广播 D 内容提供者 4 startactivityforresult() 方法接收两个参数, 第一个是 Intent, 第二个是 ( ) A resultcode B requestcode C 请求码 D data 5 下列关于 Activity 的描述, 错误的是 ( ) A Activity 是 Android 的四大组件之一 B Activity 有四种启动模式 C Activity 通常用于开启一个广播事件 D Activity 就像一个界面管理员, 用户在界面上的操作是通过 Activity 来管理 四 简答题 1 请简要说明 Activity 四种启动模式的区别 2 请简要说明 Activity 的三种状态以及不同状态使用的方法 五 编程题 1 请编写一个程序, 通过隐式意图打开系统中的浏览器 2 请编写一个数据传递的小程序, 要求在第一个界面输入姓名 年龄, 第二个界面上面显示 恭喜您! 来到这个世界 n 年!