描述
开 本: 16开纸 张: 胶版纸包 装: 平装-胶订是否套装: 否国际标准书号ISBN: 9787302466598
本书是作者近几年来从事嵌入式教学与研究的成果结晶,重点阐述了Android应用程序设计的理论与方法,适合作为普通高等院校软件工程、物联网、电子通信和智能控制等专业讲授Android移动开发技术的本科生教材或参考书。
目录
第1章概述
1.1Android操作系统
1.2Android系统结构
1.3Java开发环境
1.4Android开发环境
1.5本章小结
第2章Java语言
2.1Java程序语法与控制
2.1.1顺序方式
2.1.2分支方式
2.1.3循环方式
2.1.4异常处理
2.2Java基本数据类型
2.2.1数值
2.2.2字符
2.2.3字符串
2.2.4布尔数
2.2.5数组
2.3Java类
2.3.1类与对象
2.3.2继承与多态
2.3.3接口
2.4Java文件操作
2.5在命令行窗口中运行Java程序
2.6Java图形界面
2.6.1事件响应方法
2.6.2内部类
2.6.3匿名内部类
2.7本章小结
第3章Android应用程序框架
3.1Hello World工程
3.2Hello World应用工作原理
3.3应用程序框架
3.3.1应用程序框架基本组成
3.3.2Android配置文件AndroidManifest.xml
3.3.3Android资源文件
3.3.4Android源程序文件
3.4Activity生命周期
3.5本章小结
第4章单用户界面应用设计
4.1Activity概念
4.2布局与控件
4.2.1布局软件DroidDraw
4.2.2控件事件响应方法
4.2.3Android常用控件
4.2.4线性布局LinearLayout
4.2.5相对布局RelativeLayout
4.2.6框架布局FrameLayout
4.2.7表格布局TableLayout和TableRow
4.2.8约束布局ConstraintLayout
4.3“计算器”工程
4.4本章小结
第5章多用户界面应用设计
5.1Intent概念
5.2对话框
5.2.1AlertDialog对话框
5.2.2自定义对话框
5.2.3Dialog类
5.2.4ProgressDialog对话框
5.3菜单
5.3.1XML布局菜单
5.3.2动态菜单
5.3.3上下文菜单
5.4多用户界面设计
5.4.1简单多用户界面显示
5.4.2多用户界面数据传递
5.4.3活动界面间双向数据通信
5.5本章小结
第6章数据访问技术
6.1SharedPreferences文件访问
6.2流文件操作
6.3SQLite关系数据库
6.3.1SQLite数据库访问方法
6.3.2SQLiteOpenHelper类
6.4内容提供者
6.5本章小结
第7章图形与动画
7.1绘图
7.1.1View类绘图程序框架
7.1.2SurfaceView类绘图程序框架
7.1.3基本图形与字符串
7.2动画
7.2.1定时器动画
7.2.2渐变动画
7.2.3帧切换动画
7.3本章小结
第8章多媒体技术
8.1音频文件播放
8.2服务
8.3视频文件播放
8.4本章小结
第9章通信应用技术
9.1短信息发送
9.2短信息接收
9.3短信息加密
9.4本章小结
参考文献
江西财经大学枫林园
2017年2月
图31创建新工程对话框
图32配置应用SDK
在图32中为新创建的应用MyHelloApp选择其工作的平台和所需要的SDK库,这里选择了Android 4.4 (KitKat)。从图32可知,全球大约有73.9%的Android智能手机或智能平板上可运行应用MyHelloApp。在图32中单击Next按钮进入图33所示的界面。
图33选择Activity类型
在图33中,为应用MyHelloApp选择一个空的Activity。可根据应用需要选择合适的Activity。在图33中,单击Next按钮进入图34所示的界面。
图34命名Activity对话框
在图34中,输入Activity名称为“MyHelloMainAct”,Activity译为活动,Android中一个Activity就是一个可视界面,建议使用“活动界面”这一译法或者直接使用“Activity”。Activity名MyHelloMainAct将作为应用程序的类名和其对应的Java文件名(MyHelloMainAct.java)。本书中命名Activity时使用后缀“Act”。在命名Activity时,自动为其创建界面布局文件(Layout)名,默认为activity “Activity名称中的英文单词,各个英文单词间用下画线分开”,例如,Activity名为MyHelloMainAct时,布局文件名为activity_my_hello_main,布局文件扩展名为.xml。在图34中单击Finish按钮,进入图35所示的界面。
图35MyHelloApp应用
图35是按照Android Studio新建工程向导生成的应用MyHelloApp,左边为工程浏览器,显示了应用MyHelloApp的目录和文件结构(后面结合图39说明); 右边显示了MyHelloMainAct.java文件的内容。在图35中单击AVD Manager快捷按钮,启动Android SDK模拟器Galaxy_Nexus_API_19:5554,如图153所示。等模拟器Galaxy_Nexus_API_19启动就绪后,在图35中选中工程浏览器中的app,然后,单击菜单Run|Run ‘app’,将弹出图36所示的界面。在图36中,Samsung GTN7100为笔者的智能手机(已连接),而Galaxy Nexus API 19为模拟器,可见智能手机与模拟器的API版本号相同,均为19。如果选择Samsung GTN7100,则应用将在智能手机上运行; 如果选择Galaxy Nexus API 19,则应用将在模拟器上运行,运行结果如图37所示。在智能手机上的运行结果与图37相同。
图36选择目标运行平台
在图37中,模拟器Galaxy Nexus API 19中央显示一行文字“Hello World!”,显示窗口标题名为MyHelloApp,即应用名。因此,只需要按照Android新建工程向导就可以生成一个显示“Hello World!”的工程,无须程序员输入一句代码。在图35中,Build菜单如图38所示。
图37应用MyHelloApp运行结果
图38Build菜单结构
在图38中,常用Make Project编译整个工程,用Clean Project清除生成的目标文件和中间目标文件,用Build APK生成将应用安装到智能手机上的.apk文件。应用MyHelloApp生成的.apk文件位于目录“D:\MyAndroidWorkSpace\MyHelloApp\app\build \outputs\apk”下,文件名为appdebug.apk,这里的debug表示调试版本。 .apk文件实际上是压缩包文件,可以使用WinRAR等软件解压,解压后可以看到classes.dex可执行文件。执行Android Studio新建工程向导创建应用MyHelloApp后,将在工作目录“D:\MyAndroidWorkSpace”下创建一个新目录,即MyHelloApp,如图39所示。目录MyHelloApp下有子目录.gradle、.idea、app、build、gradle,其中,除app之外的子目录与工程编译信息和版本信息有关。app子目录下有三个子目录,即build、libs和src,分别用于保存应用的生成目标文件信息、库和用户编写的代码文件。src子目录下包括三个子目录,即androidTest、test和main,前两个目录中包含了自动生成的测试源文件,main子目录结构如图39所示,包括java和res两个子目录,分别用于保存Java代码文件和资源文件,其中res资源文件包括各种分辨率大小的位图图像文件和常量文件。Java代码文件MyHelloMainAct.java位于目录“D:\MyAndroidWorkSpace\MyHelloApp\app\src\main\java\cn\edu\jxufe\zhangyong\myhelloapp”下,可见包名被用作子目录树的目录名。
图39工程ex03_01目录结构
3.2Hello World应用工作原理对于传统的面向过程C语言程序,其程序执行入口为main函数,程序的运行就是main函数中各条语句按语法规则依次执行。对汇编语言程序设计熟悉的程序员,还有那些做过DSP或单片机开发的程序员,对程序的运行有着更深刻的认识。CPU(中央处理单元)总是执行其PC(程序计数器寄存器)指针指向的程序空间地址处的指令代码,对于分支和跳转程序,需要修改PC的值。对于汇编语言程序设计而言,程序的执行过程非常清晰,程序员负责所有的资源调用,并安排程序指令的执行。汇编语言与程序实现的算法和功能的细节直接相关,开发这类程序需要专业开发人员,难度相对较大。高级语言是接近自然语言的一种程序设计语言,当基于这种高级语言的应用程序设计越简单,那么这类应用程序的执行过程越不容易理解。Android应用程序基于Java高级语言和Dalvik虚拟机,它的执行过程比传统的Java程序(例如第2章的程序)更难理解,这时往往需要按Android应用程序设计的规定方法进行程序设计,即按照Android框架进行程序设计,并理解其程序的执行过程。事实上,不可能做到像理解汇编语言程序的执行过程一样理解Android应用程序的执行过程。网址android.xsoftlab.net是Android开发者的镜像网址,可以不用代理服务器直接访问,登录到网址“http://android.xsoftlab.net/reference/android/app/Application.html”,如图310所示(在Android SDK安装目录的docs子目录下,这里为D:\Android\SDK\docs下,打开index.html,也可进入Android开发者参考手册,这些内容需要在Android Studio环境下下载Documentation for Android SDK)。
图310Android开发者参考手册
从图310中找到所使用的API版本号,这里为19,找到包android.app,再定位到Application类,后定位到Application类的公有方法onCreate,该方法是应用程序启动时首先执行的方法,即“Called when the application is starting, before any activity, service, or receiver objects (excluding content providers) have been created.”(当应用程序要执行时被调用,其他的应用程序对象都还没有创建)。从第2章的学习知道,一个类的公有方法的调用有两种途径,即被该类的实例调用或被该类中的方法调用,因此,可以推断该方法将被Application类中的某个静态方法(可能就是mian方法)调用。所以,从Android开发者手册可知,Android程序的执行入口是Application类的onCreate方法。需要强调指出的是,只有熟练地检索Android开发者手册,才能成为真正的Android应用程序员。对于显示“Hello World”的Android应用程序工程MyHelloApp来说,其程序执行入口也是Application类的OnCreate方法。在MyHelloApp应用中有一个文件AndroidManifest.xml,该文件内容是XML语言的程序。XML是eXtensible Markup Language的缩写,译为可扩充标记语言,这类语言不像C或Java语言等可执行高级语言,XML语言是不可执行的,它的优点在格式统一且固定,用于为其他高级语言指定(或标记、配置)其数据或资源的位置和相互关系,例如,Java语言界面中需要使用一个按钮,可以使用XML语言为按钮指定名称、大小和字体等属性,Java程序在执行时按XML提供的信息要求调用或显示该按钮。应用MyHelloApp的文件AndroidManifest.xml中通过以下语句指定应用程序启动后执行的Activity:
12android:allowBackup=”true”
3android:icon=”@mipmap/ic_launcher”
4android:label=”@string/app_name”
5android:supportsRtl=”true”
6android:theme=”@style/AppTheme”>
7
8
9
10
11
12
13
这段代码还将在第3.3节中详细介绍,这里第1和第13行说明这两行中间的内容属于应用application,第7~12行说明了应用中包含了一个名为MyHelloMainAct的活动界面(Activity),第9行说明该活动界面是主界面(MAIN)。因此,应用类Application的onCreate启动后,将转到类MyHelloMainAct去执行,该类位于MyHelloMainAct.java文件中。MyHelloMainAct.java文件的代码如下:
1package cn.edu.jxufe.zhangyong.myhelloapp;
2
3import android.support.v7.app.AppCompatActivity;
4import android.os.Bundle;
5
6public class MyHelloMainAct extends AppCompatActivity {
7@Override
8protected void onCreate(Bundle savedInstanceState) {
9super.onCreate(savedInstanceState);
10setContentView(R.layout.activity_my_hello_main);
11}
12}
上述代码中,第6行定义了MyHelloMainAct类,该类继承了类AppCompatActivity,类MyHelloMainAct中仅有一个方法,即onCreate方法,该方法覆盖了其父类AppCompatActivity的同名方法。由于类MyHelloMainAct的onCreate方法是公有方法,因此,要想调用该方法,必须先创建MyHelloMainAct类的实例(对象),但是,这一步工作由Android框架帮程序员完成了,即Android框架帮程序员定义了类MyHelloMainAct的实例(对象)并通过其对象调用了onCreate方法。所以,应用MyHelloApp从开始执行到执行到类MyHelloMainAct的onCreate方法之前所做的工作都被Android框架隐藏了,程序员会误认为应用MyHelloApp开始执行的是第8行的onCreate方法。根据上面的解释可知,应用MyHelloApp启动后,Android操作系统框架层会引导它执行到类MyHelloMainAct的onCreate方法。假设Android框架层为类MyHelloMainAct创建的对象名为myHelloMainObj,整个应用MyHelloApp启动后成为Android系统的一个进程(Android系统中每个应用程序对应着一个进程),该进程通过对象myHelloMainObj执行其onCreate方法,第9行执行其父类的方法onCreate初始化对象myHelloMainObj继承的父类AppCompatActivity中的公有和保护数据。第10行调用setContentView方法使用布局R.layout.activity_my_hello_main设置活动界面内容,这里方法setContentView是类AppCompatActivity的公有方法,可以直接被其子类MyHelloMainAct的对象调用。类AppCompatActivity中有三种重载形式的setContentView方法,这里调用的方法原型为
public void setContentView(int layoutResID);
参数layoutResID被设置为R.layout.activity_my_hello_main(第10行),这里R表示资源类,layout为R的一个内部数,activity_my_hello_main为layout类的公有静态整型常量,指向同名的布局文件activity_my_hello_main.xml,例如:
1public static final class layout {
2public static final int activity_my_hello_main=0x7f030000;
3}
类layout为公有静态类,且用final修饰,表示该类不能派生新类,该类中有一个公有静态整型常量activity_my_hello_main(第2行),这里的activity_my_hello_main对应于图311中资源res中的activity_my_hello_main.xml文件,即这里的R.layout. activity_my_hello_main是activity_my_hello_main.xml的标识符,所以语句setContentView(R.layout. activity_my_hello_main)将设置活动界面的内容为activity_my_hello_main.xml。在图311中,文件activity_my_hello_main.xml的内容如下:
1
23xmlns:app=”http://schemas.android.com/apk/res-auto”
4xmlns:tools=”http://schemas.android.com/tools”
5android:id=”@ id/activity_my_hello_main”
6android:layout_width=”match_parent”
7android:layout_height=”match_parent”
8tools:context=”cn.edu.jxufe.zhangyong.myhelloapp.MyHelloMainAct”>
9
1011android:layout_width=”wrap_content”
12android:layout_height=”wrap_content”
13android:text=”Hello World!”
14app:layout_constraintBottom_toBottomOf=”@ id/activity_my_hello_main”
15app:layout_constraintLeft_toLeftOf=”@ id/activity_my_hello_main”
16app:layout_constraintRight_toRightOf=”@ id/activity_my_hello_main”
17app:layout_constraintTop_toTopOf=”@ id/activity_my_hello_main” />
18
19
图311MyHelloApp应用
上述代码是XML格式,第2行说明布局为ConstraintLayout布局(该布局是Android 2.3后续版本才支持的布局),第4章将深入介绍ConstraintLayout布局,而且将重点使用这种布方式。第5行为布局文件名称对应的标识号; 第6、7行表示布局页面的宽和高均匹配其父视图的大小。第10~17行表示这是一个静态文本框(或文本视图,TextView),其宽度与高度由其包含的文本决定,第13行表示静态文本框的文本字符串内容为“Hello World!”,即显示在图37中央的文字; 第14~17行为静态文本框的位置,表示居中显示。需要说明的是,第5行指定layout的标识符为activity_my_hello_main,而第14~17行中引用该标识符,表示静态文本框的位置居中。现在通过执行对象myHelloMainObj的方法onCreate已经把显示内容准备好了,但是该活动界面还没有显示出来,Android框架还会自动通过对象myHelloMainObj调用onStart方法,该方法在应用MyHelloApp中没有体现,调用onStart方法后,应用MyHelloApp的界面就显示出来了; 然后,Android框架还要自动通过对象myHelloMainObj调用onResume方法,该方法调用后,应用MyHelloApp的活动界面将得到焦点,成为显示界面的“前台”界面。这些方法onStart、onResume还有onCreate方法,都是类Activity的保护方法,将被其子类(这里是MyHelloMainAct类,即AppCompatActivity是Activity的子类,而MyHelloMainAct类是AppCompatActivity的子类)继承到,因此,可被其子类对象myHelloMainObj调用。
图312应用程序图标
经过上述的过程之后,才能得到图37所示的界面。一旦该程序运行,将无法被人工关闭,用户可以通过单击模拟器的Home按钮回到欢迎界面,或者在图312中单击MyHelloApp应用程序图标重新进入“Hello World”界面。总之,该应用程序无法关闭。Android系统会自动管理那些没有显示(或没有使用)的应用程序,根据内存和应用程序的使用情况自动关闭那些不再被使用的应用程序,同时释放它们占用的内存空间。综上所述,对于Android程序员来说,只需要明白创建的用户活动界面类继承了类AppCompatActivity,当应用程序开始执行时,将自动执行其onCreate方法,程序员需要在onCreate方法中添加界面初始化的代码,然后将应用程序交给Android系统管理。对于应用MyHelloApp而言,在类MyHelloMainAct的onCreate方法中启动了包含字符串“Hello World!”的显示界面,即完成了显示“Hello World”的任务。同时,Android应用程序中需要的各种显示元素均以资源的形式保存,并借助XML语言进行管理,而且,整个Android应用都需要借助AndroidManifest.xml进行配置。结合图311,应用MyHelloApp中整个工程的配置文件为AndroidManifest.xml,这个文件只能有一个。位于资源res的layout下的XML文件均为布局文件,应用MyHelloApp中只有一个布局文件,即activity_my_hello_main.xml,如果有多个Activity,则对应地有多个布局文件。在资源res的values下的文件为常量定义文件,可以有多个这类文件,例如,应用MyHelloApp中含有一个字符串资源文件,即strings.xml。所有XML文件内容均可以图形化地创建,例如,可借助图形化方式创建常量字符串资源strings.xml文件。strings.xml文件的内容如下:
1
2MyHelloApp
3
这里,第1行与第3行为资源标识符,第2行表示字符串常量名为app_name,字符串内容为MyHelloApp。当应用MyHelloApp中没有文件strings.xml和activity_my_hello_main.xml等资源文件时,完全依赖Java语言代码也可以实现显示“Hello World”的程序功能。只是因为Android系统支持国际化语言,使用资源文件可以方便程序工作在各种语言环境下,所以,建议与显示界面相关的元素全部使用资源描述。实际上,这是这些资源文件的价值所在。3.3应用程序框架Android应用程序框架是指借助Android Studio进行Android应用程序设计时,自动生成的应用程序目录及文件结构,大约有1100个文件和500个子目录,程序员基于应用程序框架,添加文件和代码可实现相应的功能。可以把“Hello World!”工程视为Android应用程序框架,更广义的应用程序框架是指当用户应用程序设计完成后,所有Android自动生成的代码、文件和目录均被视为Android应用程序框架,或者说,除去用户输入的Java代码程序文件,其他所有文件都属于Android应用程序框架。在第3.1节、3.2节的应用MyHelloApp中,阐述了Hello World工程的创建过程和执行情况,这里将详细介绍应用程序框架中各个文件的内容及其作用。3.3.1应用程序框架基本组成例32应用程序框架实例。新建应用MyFrameApp,即应用名为MyFrameApp,公司域名为zhangyong.jxufe.edu.cn,即包名为cn.edu.jxufe.zhangyong.myframeapp,保存目录为D:\MyAndroidWorkSpace \MyFrameApp,使用SDK版本号为KitKat,API版本号为19,选择空的Activity,活动界面(Activity)名为MyFrameMainAct,对应的布局为activity_my_frame_main。应用MyFrameApp的结构如图313所示。
图313应用MyFrameApp工程结构
图313中,程序员只需要关注被圈住的内容,而在圈外面的Gradle Scripts是调试、优化、库和编译配置信息,位于java分组下的带有“(androidTest)”和“(test)”后缀的cn.edu.jxufe.zhangyong.myframeapp分组下的文件是测试文件,这些文件均为自动生成的ASCII文件,可以打开浏览其内容,但一般不需要程序员干预。AndroidManifest.xml是Android工程的全局配置文件。java分组下的cn.edu.jxufe.zhangyong.myframeapp用于存放程序员编写的Java源程序,目前只有一个源文件MyFrameMainAct.java。res分组下包含了项目所有可能使用的资源文件,例如图形文件、布局文件、常量文件等。图313中的工程浏览器中,分组树(或称目录树)中的小图标各具含义,例如,包用图标表示,类用图标表示,方法用图标表示,资源用图标表示,目录用图标表示等等,认识这些图标对应的文件类型对了解工程结构有很大帮助。3.3.2Android配置文件AndroidManifest.xml在图313中双击AndroidManifest.xml文件,弹出图314所示的界面。AndroidManifest.xml有两种显示方式,即文本显示方式和合并同类属性的显示方式,如图314状态栏中所示,其中标签Text为文本显示方式。由于应用MyFrameApp中只有一个活动界面,故图314中只有一个Activity,即MyFrameMainAct,当需要显示多个界面时,必须将新的Activity添加到AndroidManifest.xml文件中。AndroidManifest.xml文件的内容如下:
1
23package=”cn.edu.jxufe.zhangyong.myframeapp”>
4
56android:allowBackup=”true”
7android:icon=”@mipmap/ic_launcher”
8android:label=”@string/app_name”
9android:supportsRtl=”true”
10android:theme=”@style/AppTheme”>
11
12
13
14
15
16
17
18
19
20
图314AndroidManifest.xml
上述XML代码中,第1行说明XML版本为1.0,采用UTF8编码方法,这种编码方法中,如果某个字符在Unicode码中的值小于256,则使用一个字节存储,这样有效地节约了存储空间。第2行的manifest与第20行的/manifest配对,表示这两行之间为配置内容,配置字段名使用“:”连接,例如xmlns:android和android:allowBackup等。第2行的xmlns:android=http://schemas.android.com/apk/res/android指定工程中使用的Android程序包,这一句不能改动。第3行指定应用程序的包名为cn.edu.jxufe.zhangyong.myframeapp。第7行的android:icon指定应用程序图标为资源文件“@mipmap/ic_launcher”,即图313中的mipmap分组下的文件ic_laucher.png,多个同名的.png文件的分辨率不同,保存在不同的目录下,一般地,mdpi、hdpi、xhdpi、xxhdpi和xxxdhdpi的分辨率依次为48×48、72×72、96×96、144×144和192×192,Android系统将根据智能终端的显示屏分辨率自动选择合适的图标,因此,这些图标文件名是相同的,保存在硬盘的不同目录下,如图315所示。默认的ic_launcher.png是绿色小机器人,如图312所示。
图315不同分辨率的同名图标的存储目录结构
第8行的android:label指应用程序的名称(这个名称可作为出现在应用程序图标下面的字符串,见图312),“@string/app_name”表示字符串资源文件strings.xml中的名称为app_name对应的常量字符串,strings.xml文件的内容如下:
1
2框架实例
3
第2行将app_name由原来的“MyFrameApp”修改为“框架实例”。上述所说的“@string/app_name”就是字符串“框架实例”,将被用作应用的图标名称。现在运行MyFrameApp应用,其运行结果如图316所示。
图316应用MyFrameApp及其图标
但是,往往不希望改变app_name,而是修改文件AndroidManifest.xml的第11行如下:
表示activity的标题为mainact_name(这个标题同时作为应用程序图标下的字符串,见图316),然后,修改strings.xml如下:
1
2MyFrameApp
3框架实例
4
运行结果如图316所示。现在回到文件AndroidManifest.xml,第11~17行为Activity的说明代码,第11行说明Activity的名称为MyFrameMainAct,即类名; 第12~16行为Intentfilter,Intent译为意图,用于管理Activity的数据,Intentfilter说明Activity的执行方式(或称动作); 第13行指定动作(action)的名称为“MAIN”,第15行指定类属名称为“LAUNCHER”,表示名称为MyFrameAct的Activity将作为主窗口启动。在指定应用程序名或活动界面标题时,除了可以使用“@string/app_name”从字符串资源文件中查找字符串外,还可以直接指定字符串,例如前述AndroidManifest.xml文件代码的第8行可写为形式“android:label=”MyFrameApp “”而不影响应用的执行情况。3.3.3Android资源文件如图313所示,新建应用MyFrameApp时Android Studio自动创建的资源文件分为4类,即drawable(存放图像)、layout(布局)、mipmap(多分辨率图像和图标)和values(值)。布局将在第4章详细介绍,mipmap在上一小节已经介绍过,这里重点介绍values和drawable类型的资源文件应用方法。此时的应用MyFrameApp工作界面如图317所示。
图317应用MyFrameApp工作窗口
在图317中,单击菜单File|New|XML|Values XML File,弹出图318所示的界面。在图318中,单击Finish按钮,则文件strings_hz.xml自动添加到工程管理器的res|values分组下,如图319所示。
图318新建常量资源文件
图319strings_hz.xml资源文件
在图319中双击strings_hz.xml,并编辑它的内容如下:
1
2
3 爱护我们共同的家园——地球!/string>
4
其中,第3行代码表示常量字符串名为tvhello_name,在调用时引用“@string/ tvhello_name”,其字符串值(即字符串内容)为“爱护我们共同的家园——地球!”。然后,打开布局文件activity_my_frame_main.xml,将其中的语句
“android:text=”Hello World!””
修改为:
“android:text=”@string/tvhello_name””
此时,运行应用MyFrameApp,运行结果如图320(a)所示。
图320应用MyFrameApp运行结果
现在,在图319中的colors.xml文件中(在其倒数第2行)插入以下语句:
#FF0000
表示colorRed为红色,颜色常量结构为#RRGGBB,RR、GG和BB分别表示红色、绿色和蓝色分量的大小,用十六进制数表示,取值均为0x00~0xFF,例如#FF0000表示红色,#00FF00表示绿色,#0000FF表示蓝色。接着在布局文件activity_my_frame_main.xml中的第14行插入以下语句:
android:textColor=”@color/colorRed”
然后,执行应用MyFrameApp,运行结果如图320(b)所示,文本以红色显示。回到图319,图形文件可以存放在drawable下,也可以存放在mipmap下,事实上,可以在drawable下创建子目录drawablehdpi、drawablemdpi和drawableldpi,分别用于存放高分辨率、中分辨率和低分辨率图形文件,与mipmap类似将文件名相同的不同分辨率的图像文件存放在不同的目录下。由于mipmap下可存放各种分辨率的文件,这里建议drawable下存放任意分辨率的图像文件,Android系统会根据显示区域对图像进行自动缩放处理。从网上下载了一幅地球的图像,命名为omearth.jpg(这里故意使用了1280×720分辨率的图像,其实可以为任意分辨率),将其保存在目录“D:\MyAndroidWorkSpace\MyFrameApp\app\src\main\res\drawable”下,则Android Studio自动将omearth.jpg添加到工程管理器中,如图321所示。现在,修改布局文件activity_my_frame_main.xml,在其第8行插入以下代码:
android:background=”@drawable/omearth”
表示使用drawable类型的资源图像omearth.jpg作为activity的背影。此时执行应用MyFrameApp,运行结果如图322所示。
图321添加了图像omearth.jpg的drawable资源
图322应用MyFrameApp运行结果
现在回到图321,从图321中可见工程管理器的资源res|values中还有styles.xml和dimens.xml文件,前者用于指定activity或各种控制的样式风格,后者用于指定activity显示区域的边界宽度等。样式styles.xml文件可由布局文件自动生成,并且样式风格可以继承。layout分组下为布局文件,应用MyFrameApp中只有一个Activity,即只有一个活动界面,所以,这里只有一个activity_my_frame_main.xml文件。当工程中有多个Activity时,需要在layout下添加多个布局文件。通过熟练和巧妙地使用资源文件,可有效地减少工程中的Java代码量,并且增强程序的层次性和可维护性。新建的资源文件均会自动存放在res分组下的相应子分组中。3.3.4Android源程序文件参考图321,可知应用MyFrameApp中只有一个程序文件,即MyFrameMainAct.java,它包含一个公有类MyFrameMainAct,该类位于包cn.edu.jxufe.zhangyong.myframeapp中,与程序文件同名,其中的方法为onCreate(返回值为void)。文件MyFrameMainAct.java的代码如下:
1package cn.edu.jxufe.zhangyong.myframeapp;
2
3import android.support.v7.app.AppCompatActivity;
4import android.os.Bundle;
5
6public class MyFrameMainAct extends AppCompatActivity {
7
8@Override
9protected void onCreate(Bundle savedInstanceState) {
10super.onCreate(savedInstanceState);
11setContentView(R.layout.activity_my_frame_main);
12}
13}
上述代码是创建新应用工程向导自动生成的。第6行说明类MyFrameMainAct继承了类AppCompatActivity; 第9~12行的onCreate方法只有在该Activity次执行时被调用,在其执行过程中不会被再次调用,因此,onCreate方法一般用于初始化应用程序的数据和界面。第9行中显示onCreate方法具有一个Bundle型参量,Bundle类继承了java.lang.Oject类并实现了接口android.os.Parcelable,因此,Bundle类的实例(对象)可用于保存和恢复其他类的实例(对象)。如果有一个MyFramceMainAct类的实例正处于休眠态中(即由于其他活动界面处于执行状态而被停止运行),那么处于休眠态的实例对象将被保存在参量savedInstanceState中; 当再次执行类MyFrameMainAct的实例时,即调用onCreate方法时,原来的对象实例将通过参量savedInstanceState传递; 如果原来的休眠态实例不存在,则参量savedInstanceState为空。显然,次创建类MyFrameMainAct的实例时,参量savedInstanceState为空; 当该实例执行过程中,由于其他应用程序的执行,而被迫停止时,则将类MyFrameMainAct的实例保存在参量savedInstanceState中; 当类MyFrameAct的实例需要再次执行时,它原来的对象实例将通过参量savedInstanceState传递(这部分内容可参考第3.4节关于Activity的生命周期的详细说明)。第10行借助关键字super调用父类Activity的onCreate方法; 第11行调用方法setContentView(继承自父类AppCompatActivity的公有方法),根据资源的ID号(索引号)调用相应的布局文件设置活动界面,这里是调用activity_my_frame_main.xml布局文件设置活动界面。随后Android操作系统会管理MyFrameMainAct应用程序界面的显示和运行。应用MyFrameApp的布局文件activity_my_frame_main.xml的代码如下:
1
23xmlns:app=”http://schemas.android.com/apk/res-auto”
4xmlns:tools=”http://schemas.android.com/tools”
5android:id=”@ id/activity_my_frame_main”
6android:layout_width=”match_parent”
7android:layout_height=”match_parent”
8android:background=”@drawable/omearth”
9tools:context=”cn.edu.jxufe.zhangyong.myframeapp.MyFrameMainAct”>
10
1112android:layout_width=”wrap_content”
13android:layout_height=”wrap_content”
14android:text=”@string/tvhello_name”
15android:textColor=”@color/colorRed”
16app:layout_constraintBottom_toBottomOf=”@ id/activity_my_frame_main”
17app:layout_constraintLeft_toLeftOf=”@ id/activity_my_frame_main”
18app:layout_constraintRight_toRightOf=”@ id/activity_my_frame_main”
19app:layout_constraintTop_toTopOf=”@ id/activity_my_frame_main” />
20
21
该布局文件的内容在第4章还将深入介绍,这里第11~19行表示一个静态文本框控件TextView,在第16行插入语句:
android:id=”@ id/tvEarth”
表示该TextView的ID号为tvEarth。可在onCreate方法中调用该控件的方法setText设置其显示的字符串。修改应用MyFrameApp的代码文件MyFrameMainAct.java代码如下:
1package cn.edu.jxufe.zhangyong.myframeapp;
2
3import android.graphics.Color;
4import android.support.v7.app.AppCompatActivity;
5import android.os.Bundle;
6import android.widget.TextView;
7
8public class MyFrameMainAct extends AppCompatActivity {
9private static TextView textView;
10@Override
11protected void onCreate(Bundle savedInstanceState) {
12super.onCreate(savedInstanceState);
13setContentView(R.layout.activity_my_frame_main);
14
15this.setTitle(“爱护地球”);
16
17textView=(TextView)findViewById(R.id.tvEarth);
18textView.setText(“我们热爱大自然!”);
19textView.setTextColor(Color.RED);
20}
21}
上述代码中,在第9行中添加类MyFrameMainAct的私有静态文本框类对象成员textView; 在第15行调用setTitle方法设置活动界面的标题为“爱护地球”; 第17行通过findViewById方法由控件的资源ID号获得控件实例(对象); 第18行调用setText方法设置textView对象的显示文字为“我们热爱大自然!”; 第19行调用setTextColor方法设置字体颜色为红色。此时执行应用MyFrameApp,运行结果如图323所示。
图323MyFrameApp应用执行结果
对比图322和图323,可知标题由原来的“框架实例”变为“爱护地球”,视图中央显示的文字由原来的“爱护我们共同的家园——地球”变为“我们热爱大自然!”。3.4Activity生命周期Activity生命周期是指活动界面实例(对象)从创建到被Android操作系统关闭的整个生存周期,在这一过程中,Android系统将依次自动调用Activity的6种方法,即OnCreate、OnStart、OnResume、OnPause、OnStop和OnDestroy。这6种方法相对于Android系统而言,类似于Activity的6个“钩子”函数(钩子函数是指挂接在某个方法中的空函数,当扩展这个方法的功能时,只需要向其钩子函数中添加特定代码即可,而不用修改这个方法的语句)。Activity的生命周期如图324所示,为力求表达准确无误,这里直接引用了Android开发者手册上的英文框图。
图324Activity生命周期
由图324可知,当某时刻Activity启动了,那么其中的方法onCreate首先得到执行,程序员可以在该方法中添加初始化Activity的代码,此时Activity界面仍然不可见; 然后方法onStart得到执行,一般可在该方法中添加一些服务,该方法执行后,Activity界面才可见; 之后,执行onResume方法,使Activity获得显示焦点而处于与用户交互的状态,即“Activity is running”。当另一个Activity由于系统调度原因在前台显示而获得焦点时,即“Another activity comes in front of the activity”,该Activity将执行onPause方法,暂停当前Activity的执行,onPause方法中不宜添加大量代码,因为只有onPuase方法执行完成后,另一个Activity的Resume方法才能执行。当该Activity不可见时,将调用onStop方法停止该Activity。在该Activity被彻底关闭(指在内存中也不存在了)前,将调用onDestroy方法,之后,该Activity生命周期结束,即“Activity is shut down”。因此,onCreate、onStart和onResume方法是主动式执行,而onPause、onStop和onDestroy方法是被动式执行,即调用onCreate方法后,Activity在内存中创建; 调用onStart方法后,Activity可见(不可用); 调用onResume方法后,Activity可见可用。当Activity不可用时,调用onPause方法; 当Activity不可见时,调用onStop方法; 当Activity要从内存中删除时,调用onDestroy方法。Android应用程序往往具有多个Activity,当一个Activity界面(记为A)在可用状态下,弹出了对话框Activity界面(记为B),B界面处于获得焦点状态,但B界面没有完全覆盖A界面; 然后B界面关闭,A界面又获得焦点。对于A而言这一处理过程为: A的onResume方法执行使A可用可见; A可见不可用使得A的onPause方法执行; 再次执行A的onResume方法使A可用可见。如图324中部的循环: onResume→Activity is running→Another activity comes in front of the activity→onPause→The activity comes to the foreground→onResume。当一个Activity界面(记为A)在可用状态下,弹出了另一个Activity界面(记为B),B界面处于获得焦点状态,且B界面完全覆盖A界面; 然后B界面关闭,A界面又获得焦点。对于A而言这一处理过程为: A的onStart和onResume方法执行使A可用可见; A不可用不可见使得A的onPause和onStop方法执行; 执行Restart方法,然后再次执行A的onStart和onResume方法使A可用可见。如图324右部的循环: onStart→onResume→Activity is running→Another activity comes in front of the activity→onPause→The activity is no longer visible→onStop→The activity comes to the foreground→onRestart→onStart。当一个Activity界面(记为A)在可用状态下,弹出了另一个Activity界面(记为B),B界面处于获得焦点状态,但B界面没有完全覆盖A界面; 此时由于Android系统需要内存,把A运行时占用的内存(即进程)清空了,但是创建A的数据结构的内存仍然存在。然后B界面关闭,A界面又再次获得焦点。对于A而言这一处理过程为: A的onCreate、onStart和onResume方法执行使A可用可见; A不可用使得A的onPause方法执行; 执行onCreate方法,然后再次执行A的onCreate、onStart和onResume方法使A可用可见。如图324左部的循环: onCreate→onStart→onResume→Activity is running→Another activity comes in front of the activity→onPause→Other applications need memory→Process is killed→User navigates back to the activity→onCreate。后一种情况为: 当一个Activity界面(记为A)在可用状态下,弹出了另一个Activity界面(记为B),B界面处于获得焦点状态,且B界面完全覆盖A界面; 此时由于Android系统需要内存,把A运行时占用的内存(即进程)清空了,但是创建A的数据结构的内存仍然存在。然后B界面关闭,A界面又再次获得焦点。对于A而言这一处理过程为: A的onCreate、onStart和onResume方法执行使A可用可见; A不可用不可见使得A的onPause和onStop方法执行; 执行onCreate方法,然后再次执行A的onCreate、onStart和onResume方法使A可用可见。如图324左部的循环: onCreate→onStart→onResume→Activity is running→Another activity comes in front of the activity→onPause→The activity is no longer visible→onStop→Other applications need memory→Process is killed→User navigates back to the activity→onCreate。下面通过例33说明图324中各个方法的调用情况。由于onPause、onStop和onDestroy方法是被动执行方法,特别是onDestroy方法,必须是Activity被关闭时才能调用。可以使用事件处理技术(详见第4章)调用Activity的finish方法关闭活动界面,此时会调用onDestroy方法,由于目前没有介绍Android事件处理技术,因此,例33没有显示onDestroy方法的调用。例33Activity生命周期中各方法的调用顺序。新建应用MyOnFrameApp,即应用名为MyOnFrameApp,包名为cn.edu.jxufe.zhangyong.myonframeapp,活动界面名为MyOnFrameAct,SDK版本为KitKat。修改MyOnFrameAct.java文件内容如下:
1package cn.edu.jxufe.zhangyong.myonframeapp;
2
3import android.support.v7.app.AppCompatActivity;
4import android.os.Bundle;
5import android.util.Log;
6
7public class MyOnFrameAct extends AppCompatActivity {
8private static final String TAG=”MyOnFrameAct”;
9@Override
10protected void onCreate(Bundle savedInstanceState) {
11super.onCreate(savedInstanceState);
12setContentView(R.layout.activity_my_on_frame);
13Log.i(TAG,”onCreate-Method”);
14}
15public void onStart(){
16super.onStart();
17Log.i(TAG,”onStart-Method”);
18}
19public void onResume(){
20super.onResume();
21Log.i(TAG,”onResume-Method”);
22}
23public void onRestart(){
24super.onRestart();
25Log.i(TAG,”onRestart-Method”);
26}
27public void onDestroy(){
28super.onDestroy();
29Log.i(TAG,”onDestroy-Method”);
30}
31public void onStop(){
32super.onStop();
33Log.i(TAG,”onStop-Method”);
34}
35public void onPause(){
36super.onPause();
37Log.i(TAG,”onPause-Method”);
38}
39}
上述代码中,在第8行添加常量字符串TAG,其值为“MyOnFrameAct”。在onCreate方法中添加“Log.i(TAG,”onCreateMethod”);”(第13行),android.util.Log类直接继承自java.lang.Object类,Log类不能派生子类,用于输出日志信息(log)。这里使用Log类的静态公有方法i(String tag, String msg),即使用类名Log调用,Log.i(TAG,”onCreateMethod”)输出日志信息“onCreateMethod”,日志名(tag)为TAG字符串,即“MyOnFrameAct”。第15~18行为onStart方法,首先调用父类的onStart方法,然后输出日志信息; 第19~22行为onResume方法,第23~26行为onRestart方法,第27~30行为onDestroy方法,第31~34行为onStop方法,第35~38行为onPause方法,所有这些方法均需要先调用父类的同名方法,然后调用Log.i方法输出日志信息。所谓的日志信息可以在Android Monitor观测窗口中显示出来,如图325所示。
图325日志信息
执行应用MyOnFrameApp,接着,在模拟器中单击Home按钮进入欢迎界面,然后,在模拟器的应用程序界面中单击MyOnFrameAct应用图标再次进入该程序,其MyOnFrameAct日志显示结果如图325所示。由图325的执行时间栏可知,当程序开始执行时,依次(几乎同时)执行onCreate、onStart和onResume方法,执行完onResume方法约25秒之后,操作模拟器进入到欢迎界面,此时依次执行onPause和onStop方法; 然后又过了约9秒钟,操作摸拟器重新运行MyOnFrameAct工程,则依次(几乎同时)执行onRestart、onStart和onResume方法。了解Activity的生命周期的主要目的在于理解Android应用程序的执行过程。由于Android是多任务操作系统,其应用程序是面向事件而执行的,与传统的面向过程应用程序相比,其执行过程很难理解。传统的面向过程应用程序在其全部执行过程中独占CPU使用权,程序退出时释放CPU使用权。而Android应用程序一旦执行,就把CPU使用权交给Android系统,Android系统综合调度和管理所有运行的应用程序。与其他嵌入式操作系统一样,Android系统直接管理外部事件,根据外部事件的事件源和事件类型,将事件信息交给相应的应用程序处理。3.5本章小结Android应用程序框架使得编写Android应用程序更加容易,不需要输入代码即可生成一个显示“Hello World”的Android应用程序工程。Android应用程序框架包括工程配置文件、资源文件和Java源程序文件等,合理使用资源文件可以增强Android工程的层次性,工程配置文件用于定义和管理工程中的活动界面、意图(Intent)、服务和内容提供者等程序元素,Java源程序文件包含程序执行的动作。Android应用程序启动后,其活动界面中的onCreate方法将首先被调用,因此,该方法一般用于初始化活动界面的数据和显示控件。活动界面的生命周期从执行onCreate方法开始,到执行onDestroy方法结束。此外,网址http://android.xsoftlab.net/reference/packages.html是国内镜像的Android开发者手册,在阅读本书过程中应经常查阅该手册,特别是本书中关于一些类和其方法的说明比较简略的地方,在Android开发者手册中有详细的介绍。
评论
还没有评论。