Android基础知识详解wulimingwuliming_sc@qq.comwuliming_sc@hotmail.com922010.08参考书目目录 TOC \o "1-2" \z \u HYPERLINK \l "_Toc290755614" 参考书目 290755614 2 HYPERLINK \l "_Toc290755615" 目录 290755615 3 HYPERLINK \l "_Toc290755616" Android的系统架构 290755616 6 HYPERLINK \l "_Toc290755617" 一、应用程序 290755617 6 HYPERLINK \l "_Toc290755618" 二、应用程序框架 290755618 6 HYPERLINK \l "_Toc290755619" 三、Android Runtime 290755619 7 HYPERLINK \l "_Toc290755620" 四、系统库 290755620 7 HYPERLINK \l "_Toc290755621" 五、Linux 内核 290755621 8 HYPERLINK \l "_Toc290755622" Webkit浏览器引擎简介 290755622 9 HYPERLINK \l "_Toc290755623" Dalvik虚拟机简介 290755623 11 HYPERLINK \l "_Toc290755624" 什么是Dalvik虚拟机 290755624 11 HYPERLINK \l "_Toc290755625" Dalvik和Android系统 290755625 11 HYPERLINK \l "_Toc290755626" Dalvik虚拟机的主要特征 290755626 12 HYPERLINK \l "_Toc290755627" Android应用开发和Dalvik虚拟机 290755627 15 HYPERLINK \l "_Toc290755628" Activity生命周期 290755628 16 HYPERLINK \l "_Toc290755629" 一、Activity栈 290755629 16 HYPERLINK \l "_Toc290755630" 二、Activity的4种状态 290755630 16 HYPERLINK \l "_Toc290755631" 三、Activity的生命周期 290755631 17 HYPERLINK \l "_Toc290755632" 四、实例说明 290755632 18 HYPERLINK \l "_Toc290755633" Android控件的继承关系 290755633 22 HYPERLINK \l "_Toc290755634" 一、View与ViewGroup关系 290755634 22 HYPERLINK \l "_Toc290755635" 二、各控件的继承关系 290755635 23 HYPERLINK \l "_Toc290755636" 界面布局 290755636 25 HYPERLINK \l "_Toc290755637" LinearLayout(线性布局) 290755637 25 HYPERLINK \l "_Toc290755638" TableLayout(表格布局) 290755638 28 HYPERLINK \l "_Toc290755639" RelativeLayout(相对布局) 290755639 31 HYPERLINK \l "_Toc290755640" AbsoluteLayout(绝对布局) 290755640 34 HYPERLINK \l "_Toc290755641" FrameLayout(框架布局) 290755641 34 HYPERLINK \l "_Toc290755642" Toast 290755642 36 HYPERLINK \l "_Toc290755643" Notification 290755643 38 HYPERLINK \l "_Toc290755644" 对话框 290755644 42 HYPERLINK \l "_Toc290755645" 一、带三个按钮的对话框 290755645 42 HYPERLINK \l "_Toc290755646" 二、简单列表对话框、单选列表对话框、多选列表对话框 290755646 44 HYPERLINK \l "_Toc290755647" 三、水平进度对话框和圆形进度对话框 290755647 47 HYPERLINK \l "_Toc290755648" 四、自定义对话框 290755648 49 HYPERLINK \l "_Toc290755649" Menu菜单 290755649 52 HYPERLINK \l "_Toc290755650" 选项菜单 290755650 52 HYPERLINK \l "_Toc290755651" 上下文菜单 290755651 53 HYPERLINK \l "_Toc290755652" 三、子菜单 290755652 54 HYPERLINK \l "_Toc290755653" 4种响应菜单项单击事件的方式 290755653 56 HYPERLINK \l "_Toc290755654" 显示和编辑文本的控件 290755654 57 HYPERLINK \l "_Toc290755655" TextView 290755655 57 HYPERLINK \l "_Toc290755656" CheckedTextView 290755656 60 HYPERLINK \l "_Toc290755657" EditText 290755657 60 HYPERLINK \l "_Toc290755658" ExtraEditText 290755658 61 HYPERLINK \l "_Toc290755659" AutoComplteteTextView、MultiAutoCompleteTextView (自动完成输入内容) 290755659 61 HYPERLINK \l "_Toc290755660" Button 290755660 63 HYPERLINK \l "_Toc290755661" ImageButton 290755661 65 HYPERLINK \l "_Toc290755662" ZoomButton 290755662 65 HYPERLINK \l "_Toc290755663" 日期和时间控件 290755663 66 HYPERLINK \l "_Toc290755664" DatePicker、TimePicker 290755664 66 HYPERLINK \l "_Toc290755665" AnalogClock、DigitalClock 290755665 68 HYPERLINK \l "_Toc290755666" 单选框、复选框、开关状态按钮 290755666 69 HYPERLINK \l "_Toc290755667" 单项选择(RadioGroup、RadioButton) 290755667 69 HYPERLINK \l "_Toc290755668" 复选框(CheckBox) 290755668 71 HYPERLINK \l "_Toc290755669" 开关状态按钮(ToggleButton) 290755669 73 HYPERLINK \l "_Toc290755670" 下拉列表框Spinner 290755670 74 HYPERLINK \l "_Toc290755671" ScrollView、HorizontalScrollView 290755671 77 HYPERLINK \l "_Toc290755672" 垂直滚动(ScrollView) 290755672 77 HYPERLINK \l "_Toc290755673" 水平滚动(HorizontalScrollView) 290755673 78 HYPERLINK \l "_Toc290755674" 两个方向均可滚动 290755674 78 HYPERLINK \l "_Toc290755675" TabHost 290755675 79 HYPERLINK \l "_Toc290755676" ProgressBar、SeekBar、RatingBar 290755676 81 HYPERLINK \l "_Toc290755677" 进度条(ProgressBar) 290755677 81 HYPERLINK \l "_Toc290755678" 拖动条(SeekBar) 290755678 83 HYPERLINK \l "_Toc290755679" 评分组件(RatingBar) 290755679 86 HYPERLINK \l "_Toc290755680" GridView、Gallery和ImageSwitcher 290755680 88 HYPERLINK \l "_Toc290755681" GridView 290755681 88 HYPERLINK \l "_Toc290755682" Gallery和ImageSwitcher 290755682 91 HYPERLINK \l "_Toc290755683" ListView 290755683 94 HYPERLINK \l "_Toc290755684" 一、普通的ListView 290755684 94 HYPERLINK \l "_Toc290755685" 可以单选和多选的ListView 290755685 95 HYPERLINK \l "_Toc290755686" 使用SimpleAdapter建立复杂的列表项 290755686 97 HYPERLINK \l "_Toc290755687" 自定义Adapter来建立复杂的列表项 290755687 99 HYPERLINK \l "_Toc290755688" 动态添加、删除ListView列表项 290755688 102 HYPERLINK \l "_Toc290755689" 改变ListView列表项选中状态的背景颜色 290755689 102 HYPERLINK \l "_Toc290755690" 可展开的列表组件 290755690 102 HYPERLINK \l "_Toc290755691" 数据的存取 290755691 103 HYPERLINK \l "_Toc290755692" SharePreferences 6.1 290755692 103 HYPERLINK \l "_Toc290755693" 文件的存储6.2 290755693 103 HYPERLINK \l "_Toc290755694" SQLite数据库6.4 290755694 103 HYPERLINK \l "_Toc290755695" ContentProvider、ContentResolver 6.5 290755695 105 HYPERLINK \l "_Toc290755696" Intent 290755696 106 HYPERLINK \l "_Toc290755697" 用Intent启动Activity,并在Activity之间传递数据 290755697 106 HYPERLINK \l "_Toc290755698" 调用其他应用程序中的Activity(打电话、浏览网页、发Email等) 290755698 109 HYPERLINK \l "_Toc290755699" 接收和发送广播 290755699 113 HYPERLINK \l "_Toc290755700" 接收系统广播 290755700 113 HYPERLINK \l "_Toc290755701" 在自己的应用程序中发送广播 290755701 117 HYPERLINK \l "_Toc290755702" Android服务 290755702 118 HYPERLINK \l "_Toc290755703" 系统服务 8.2 290755703 118 HYPERLINK \l "_Toc290755704" 时间服务 8.3 290755704 118 HYPERLINK \l "_Toc290755705" 跨进程访问 8.4 290755705 118 HYPERLINK \l "_Toc290755706" 网络 290755706 119 HYPERLINK \l "_Toc290755707" 图形、音频、视频 290755707 120 HYPERLINK \l "_Toc290755708" 图形 10.1 290755708 120 HYPERLINK \l "_Toc290755709" 音频、视频 10.2 290755709 120 HYPERLINK \l "_Toc290755710" 2D动画 290755710 121 HYPERLINK \l "_Toc290755711" 帧动画 290755711 121 HYPERLINK \l "_Toc290755712" 补间动画 290755712 121 HYPERLINK \l "_Toc290755713" OpenGL ES编程 290755713 122 HYPERLINK \l "_Toc290755714" Android支持的各种资源 290755714 123 HYPERLINK \l "_Toc290755715" 窗口小部件(App Widget) 290755715 124 HYPERLINK \l "_Toc290755716" NDK编程 290755716 125Android的系统架构Android的系统架构和其操作系统一样,采用了分层的架构。从架构图看,android分为四个层,从上层到低层分别是应用程序层、应用程序框架层、Android运行时和库、linux内核:一、应用程序Android会同一系列核心应用程序包一起发布,该应用程序包包括电子邮件,短信,日历,地图,浏览器,联系人管理程序等。所有的应用程序都是使用JAVA语言编写的。当然,你也可以自己用自己编写的应用程序来替换Android提供的应用程序。二、应用程序框架应用程序框架是我们进行Android开发的基础,开发人员大部分情况下也是在和应用程序框架层打交道。应用程序框架层包括了活动管理器、窗口管理器、内容提供器、视图系统、包管理器、电话管理器、资源管理器、位置管理器、通知管理器九大部分,如上图所示。各部分的具体功能如下:活动管理器(Activity Manager):活动管理器用来管理应用程序生命周期并提供常用的导航回退功能窗口管理器(Window Manager):管理所有的窗口程序内容提供器(Content Providers):内容提供器使得应用程序可以访问另一个应用程序的数据,或者共享出它自己的数据视图系统(View System):丰富而又可扩展的各种视图,是构建应用程序的基本组件。 它包括列表,网格,文本框,按钮, 甚至是可嵌入的web浏览器等等包管理器(Package Manager):Android系统内的程序管理电话管理器(Telephony Manager):用来管理所有的移动设备的功能资源管理器(Resource Manager):提供各种资源让应用程序去使用,比如本地化字符串、图片、布局文件、视频文件等等位置管理器(Location Manager):用来提供位置服务通知管理器(Notification Manager):使应用程序可以在状态栏中显示警告信息。状态栏通常在手机的顶部,短信、邮件等的提示信息就会出现在这里在Android平台上,开发人员可以完全访问核心应用程序所使用的API框架。并且,任何一个应用程序都可以发布自身的功能模块,而其他应用程序则可以使用这些已发布的功能模块。基于这样的重用机制,用户就可以方便地替换平台本身的各种应用程序组件。三、Android RuntimeAndroid运行时包括核心库和Dalvik虚拟机两部分,这两部分的具体功能如下所示:核心库:核心库包含两部分内容:一部分为绝大多数java语言所需要调用的功能函数,另一部分为Android的核心库,比如android.os、android.net、android.media等等。与标准java不一样的是,每个Android应用程序都有一个自有的进程,Android不是用一个Dalvik虚拟机来同时执行多个Android应用程序,而是每个Android应用程序都用一个自有的Dalvik虚拟机来执行。Dalvik虚拟机:Dalvik是一种基于寄存器的java虚拟机,Dalvik虚拟机主要是完成对象生命周期的管理,堆栈的管理,线程管理,安全和异常的管理,以及垃圾回收等等重要功能。基于寄存器的虚拟机的一个优点就是所需要的资源相对较少,用硬件实现虚拟机比较容易一些。Dalvik虚拟机是专门为移动设备设计的,它在开发的时候就考虑到用最少的内存资源来执行,以及支持同时执行多个虚拟机的特性。Dalvik虚拟机所执行的中间码并非是java虚拟机所执行的java字节码,而是依靠转换工具dx将java字节码转换成 .dex 格式由虚拟机执行。Dalvik虚拟机与java虚拟机最大的不同在于java虚拟机基于栈,而Dalvik基于寄存器。四、系统库系统库各部分功能如下所示:Surface Manager:对显示子系统进行管理,并且为多个应用程序提供了2D和3D图层的无缝融合媒体库:基于 PacketVideo OpenCORE;该库支持多种常用的音频、视频格式回放和录制,同时支持静态图像文件。编码格式包括MPEG4, H.264, MP3, AAC, AMR, JPG, PNG SQLite:一个对于所有应用程序可用,功能强劲的轻量级关系型数据库引擎OpenGL ES:Android是依据OpenGL ES 1.0 API标准来实现其3D绘图函数库的,该函数库可以用软件方式执行,也可以用硬件加速方式执行,其中3D软件光栅处理方面已进行高度优化FreeType:提供点阵字、向量字的描绘显示WebKit:Wekbit是一个开源的Web浏览器引擎。Apple的Safari, Google的Chrome, Nokia S60平台的默认浏览器,Apple手机和Android手机的默认浏览器,都采用的是Webkit作为浏览器的引擎。另外两个浏览器引擎分别是Gecko和Trident,大名鼎鼎的Firefox便是使用的Gecko,而微软的IE系列则使用的是Trident。WebKit引擎比其它引擎更受程序员欢迎的原因,除了其引擎的高效稳定,兼容性好外,其源码结构清晰,易于维护,是一个很重要的原因。近年来,google的加入更是让Webkit有所升温,从 Goole Chrome浏览器, Goole Anroid手机操作系统内置浏览器均采用Webkit作为内核。SGL: 2D绘图方面的绘图引擎Libc:一个从 BSD 继承来的标准C系统函数库( libc),它是专门为基于embedded linux的设备定制的SSL:………………………………五、Linux 内核Android 的核心系统服务依赖于 Linux 2.6 内核,如安全性,内存管理,进程管理,网络协议栈和驱动模型。Linux内核也同时作为硬件和软件栈之间的抽象层。Linux内核中包含如下一些驱动:显示驱动、摄像头驱动、flash内存驱动、Binder(IPC)驱动、键盘驱动、Wifi驱动、Audio驱动、电源管理等等WebKit简介参照其它总结材料Dalvik虚拟机简介参照其它总结材料Webkit浏览器引擎简介 HYPERLINK "http://www.cnblogs.com/jyli/archive/2010/01/31/1660355.html" http://www.cnblogs.com/jyli/archive/2010/01/31/1660355.html什么是Webkit Wekbit是一个开源的Web浏览器引擎。Apple的Safari, Google的Chrome, Nokia S60平台的默认浏览器,Apple手机和Android手机的默认浏览器,都采用的是Webkit作为浏览器的引擎。另外两个浏览器引擎分别是Gecko和Trident,大名鼎鼎的Firefox便是使用的Gecko,而微软的IE系列则使用的是Trident。WebKit引擎比其它引擎更受程序员欢迎的原因,除了其引擎的高效稳定,兼容性好外,其源码结构清晰,易于维护,是一个很重要的原因。近年来,google的加入更是让Webkit有所升温,从 Goole Chrome浏览器, Goole Anroid手机操作系统内置浏览器均采用Webkit作为内核。Wekbit做了什么? 作为浏览器的内核,Webkit做了哪些工作?为了了解这些,先让我们来看下一个Web浏览器究竟做了什么。我们可以从输入输出的角度来看一个Web浏览器为我们做了哪些工作。先看一个简单的例子,Web浏览器的输入是一个HTML文档,输出则是一个我们用眼睛所看到的一个Web页面, 就普通用户而言它的输入和输出就是这么简单,如下图所示: INCLUDEPICTURE "http://images.cnblogs.com/cnblogs_com/jyli/webkit/browser_fun.jpg" \* MERGEFORMATINET 那么Webkit的输入和输出又是什么呢?如果能明白这个,那我们就能很清楚的知道Webkit到底是做什么的了。不过现在要说清楚这个还有点困难,因为Webkit的输出就要复杂些了,因为它的输出本来就非直接面向用户,简单点来说,Webkit的输入是web文档,输出是一些看不见的模型,浏览器上层借助于这些模型来绘制出我们所看到的实际页面。 Webkit组成 Webkit实际上包含三大部分,至少从代码结构上来说是这样的,当然,如果细分的话还能够划分出更多的模块。如下所示 INCLUDEPICTURE "http://images.cnblogs.com/cnblogs_com/jyli/webkit/webkit_overview.jpg" \* MERGEFORMATINET 其中,WebCore是Webkit的核心部分,它实现了对文档的模型化,包括了CSS, DOM, Render等的实现;JavaSript Core显然是对JavaSript支持的实现(WebCore和JSCore来自于KDE项目的KHTML和KJS开源项目)。而橘黄色标注的Webkit部分包含了很多不同平台对Webkit封装的实现,即抽象出了与浏览器所能直接对应的一些概念的实现,比如WebView,WebPage, WebFrame等等。这三部分共同构成了Webkit, 在源码中,它们分别对应三个目录,即Webkit三大部分为WebCore, JavaSript Core,Webkit。 更多关于Webkit的介绍,搜索相关的资料…Dalvik虚拟机简介 HYPERLINK "http://www.ophonesdn.com/article/show/15" http://www.ophonesdn.com/article/show/15什么是Dalvik虚拟机Google于2007年底正式发布了Android SDK, 作为 Android系统的重要特性,Dalvik虚拟机也第一次进入了人们的视野。它对内存的高效使用,和在低速CPU上表现出的高性能,确实令人刮目相看。依赖于底层Posix兼容的操作系统,它可以简单的完成进程隔离和线程管理。每一个Android应用在底层都会对应一个独立的Dalvik虚拟机实例,其代码在虚拟机的解释下得以执行。很多人认为Dalvik虚拟机是一个Java虚拟机,因为Android的编程语言恰恰就是Java语言。但是这种说法并不准确,因为Dalvik虚拟机并不是按照Java虚拟机的规范来实现的,两者并不兼容,同时还有两个明显的不同:1、Java虚拟机运行的是Java字节码,而Dalvik虚拟机运行的则是其专有的文件格式DEX(Dalvik Executable)。 2、在Java SE程序中的Java类会被编译成一个或者多个字节码文件(.class)然后打包到JAR文件,而后Java虚拟机会从相应的CLASS文件和JAR文件中获取相应的字节码;Android应用虽然也是使用Java语言进行编程,但是在编译成CLASS文件后,还会通过一个工具(dx)将应用所有的CLASS文件转换成一个DEX文件,而后Dalvik虚拟机会从其中读取指令和数据。 Dalvik和Android系统Android的系统架构和其操作系统一样,采用了分层的架构。从架构图看,android分为四个层,从上层到低层分别是应用程序层、应用程序框架层、Android运行时和库、linux内核:如图所示,Android RunTime包括两部分:核心库和Dalvik虚拟机。核心库包括了最基本的类库,如data structure, network, Utilities, File system等的,很多实现代码都是来自 HYPERLINK "http://harmony.apache.org/" Apache Harmony项目,主要目的是保证虚拟机的类库能够和Java SE的类库最大可能的兼容,从而降低应用开发者从Java SE阵营转移到Android开发阵营的难度,增加其可用性。Dalvik虚拟机主要是完成对象生命周期的管理,堆栈的管理,线程管理,安全和异常的管理,以及垃圾回收等等重要功能。Dalvik虚拟机的主要特征Dalvik虚拟机非常适合在移动终端上使用,相对于在桌面系统和服务器系统运行的虚拟机而言,它不需要很快的CPU速度和大量的内存空间。根据Google的测算,64M的RAM已经能够令系统正常运转了。其中24M被用于底层系统的初始化和启动,另外20M被用于高层启动高层服务。当然,随着系统服务的增多和应用功能的扩展,其所消耗的内存也势必越来越大。归纳起来,Dalvik虚拟机有如下几个主要特征:一、专有的DEX文件格式DEX是Dalvik虚拟机专用的文件格式,而为什么弃用已有的字节码文件(CLASS文件)而采用新的格式呢?1、一个应用中会定义很多类,编译完成后即会有很多相应的CLASS文件,CLASS文件间会有不少冗余的信息;而DEX文件格式会把所有的CLASS文件内容整合到一个文件中。这样,除了减少整体的文件尺寸,I/O操作,也提高了类的查找速度。原来每个类文件中的常量池,在DEX文件中由一个常量池来管理,具体方式如下图:2、增加了新的操作码的支持3、文件结构尽量简洁,使用等长的指令,借以提高解析速度4、尽量扩大只读结构的大小,借以提高跨进程的数据共享如何生成DEX文件呢?Android系统和Dalvik虚拟机提供了工具(DX),在把Java源代码编译成CLASS文件后,使用DX工具。二、DEX的优化DEX文件的结构是紧凑的,如果我们还想要求运行时的性能有进一步提高,我们就仍然需要对DEX文件进行进一步优化。优化主要是针对以下几个方面:1、调整所有字段的字节序(LITTLE_ENDIAN)和对齐结构中的每一个域 2、验证DEX文件中的所有类 3、对一些特定的类进行优化,对方法里的操作码进行优化。优化后的文件大小会有所增加,应该是原DEX文件的1-4倍。优化发生的时机有两个:对于预置应用,可以在系统编译后,生成优化文件,以ODEX结尾。这样在发布时除APK文件(不包含DEX)以外,还有一个相应的ODEX文件;对于非预置应用,包含在APK文件里的DEX文件会在运行时被优化,优化后的文件将被保存在缓存中。三、基于寄存器 相对于基于堆栈的虚拟机实现,基于寄存器的虚拟机实现虽然在硬件通用性上要差一些,但是它在代码的执行效率上却更胜一筹。一般来讲,虚拟机中指令的解释执行时间主要花在以下三个方面:1、分发指令 2、访问运算数 3、执行运算 其中“分发指令”这个环节对性能的影响最大。在基于寄存器的虚拟机里,可以更为有效的减少冗余指令的分发和减少内存的读写访问,如:虽然Dalvik虚拟机并没有使用目前流行的虚拟机技术,如JIT,但是根据Google的报告,这个功能的缺失并没有让Dalvik虚拟机在性能上有所损失。我们也相信,Dalvik虚拟机的性能还有进一步提高的空间。 四、一个应用,一个虚拟机,一个进程 每一个Android应用都运行在一个Dalvik虚拟机实例里,而每一个虚拟机实例都是一个独立的进程空间。虚拟机的线程机制,内存分配和管理,Mutex等等都是依赖底层操作系统而实现的。所有Android应用的线程都对应一个Linux线程,虚拟机因而可以更多的依赖操作系统的线程调度和管理机制。不同的应用在不同的进程空间里运行,加之对不同来源的应用都使用不同的Linux用户来运行,可以最大程度的保护应用的安全和独立运行。Zygote是一个虚拟机进程,同时也是一个虚拟机实例的孵化器,每当系统要求执行一个Android应用程序,Zygote就会FORK出一个子进程来执行该应用程序。这样做的好处显而易见:Zygote进程是在系统启动时产生的,它会完成虚拟机的初始化,库的加载,预置类库的加载和初始化等等操作,而在系统需要一个新的虚拟机实例时,Zygote通过复制自身,最快速的提供个系统。另外,对于一些只读的系统库,所有虚拟机实例都和Zygote共享一块内存区域,大大节省了内存开销。 应用程序包(APK)被发布到手机上后,运行前会对其中的DEX文件进行优化,优化后的文件被保存到缓存区域(优化后的格式被称为DEY),虚拟机会直接执行该文件。如果应用包文件不发生变化,DEY文件不会被重新生成。Android应用开发和Dalvik虚拟机Android应用所使用的编程语言是Java语言,和Java SE一样,编译时使用Sun JDK将Java源程序编程成标准的Java字节码文件(.class文件),而后通过工具软件DX把所有的字节码文件转成DEX文件(classes.dex)。最后使用Android打包工具(aapt)将DEX文件,资源文件以及AndroidManifest.xml文件(二进制格式)组合成一个应用程序包(APK)。应用程序包可以被发布到手机上运行。Activity生命周期一、Activity栈Android系统中,所有Acitivity被保存在Activity栈中。当启动一个新的Activity时,这个Activity就被压入Activity栈的顶部。如果用户通过返回键回到上一个Activity的画面,则栈顶的Activity将被弹出,下一个Activity就变成新的栈顶Activity,并显示在屏幕上。下图显示了Activity栈的运作方式:二、Activity的4种状态Activity状态的变化完全由Android的内存管理器决定,变化顺序是不确定的,用户无法预知。Activity从创建到关闭,可能经历下面的4种状态:1、活跃状态:当一个Activity位于Activity栈的顶部时,它所代表的用户界面位于屏幕的最前端。也就是说,此时Activity代表的界面对用户来说是可见的,同时用户还可以在这个界面上进行操作。Android会尽可能维持处于活跃状态的Activity,采取的措施包括中止位于Activity栈上其他的Activity,以便释放资源。此时如果另一个Activity的状态变为活跃,之前活跃的Activity将变为暂停。2、暂停状态:有一种特殊情况,Activity对用户来说是可见的,但是它并不拥有用户输入的焦点,如果Activity处于这种状态,我们就称之为暂停的Activity。这种情况发生的场景通常是:在应用程序的前端有一个透明的、或者非全屏显示的Activity,处于暂停状态的Activity的界面位于这个透明的、或者非全屏显示的界面下面。一般情况下,Android也不会结束处于暂停状态的Activity,但是如果资源极其匮乏,系统也有可能结束暂停的Activity。[在程序中模拟这样的情况]3、结束状态:Activity所显示的界面在屏幕上不可见,那么它的状态就是结束状态。系统会在内存中保存处于结束状态的Activity的状态信息,以便该Activity重新变为可见的时候,状态能够迅速切换。当系统内存不足需要释放内存资源时,处于结束状态的Activity是首选对象。4、销毁状态:当Activity彻底结束或者关闭后,它的状态就变为非活跃状态,这时Activity已经从Activity栈上移除。 三、Activity的生命周期从上图可以看到,有3个比较关键的生命周期循环: 1、activity完整的生命周期 自第一次调用 onCreate()开始,直至调用onDestroy()为止。activity在onCreate()中初始化Activity,而在onDestroy()中释放所有系统资源。比如说,如果activity有一个线程在后台运行以从网络上下载数据,它会以 onCreate()创建那个线程,而以 onDestroy()销毁那个线程。 2. activity的可见生命周期 自onStart() 调用开始直到对应的onStop()调用。当Activity运行到onStart()时,用户可以在屏幕上看到此Activity,当Activity运行到onStop()时,这个Activity就从屏幕上消失。在此期间,Activity对用户来说是可见的,虽然有时候Activity并不拥有对用户的输入焦点。 3. activity的活跃生命周期 自onResume()调用起,到对应的onPause()调用为止。在此期间,用户不仅能够看到Activity,还能够通过屏幕获得输入的焦点。和可见生命周期类似,在Activity完整的生命周期中可能经历多个活跃生命周期。尽可能保持onPouse()和 onResume()的简洁,这样能够使得应用程序切换的时候响应迅速(需要注意的是,在内存不足的时候,onPause()、onStop()这两种状态是可以被系统直接kill的)四、实例说明当activity从一个状态转变到另一个状态时,Activity类中对应于该状态的方法将被调用:onCreate() onStart() onResume() onPause() onStop() onDestroy() 我们可以重载所有这些方法以便在状态改变时做一些合适的工作。所有的activity都必须实现onCreate()用以当对象第一次实例化时进行初始化设置。很多activity会实现 onPause()以提交数据变化或准备停止与用户的交互。 具体代码参见附件,这里仅仅列出重要的部分:AndroidManifest.xml package="com.studio.android" android:versionCode="1" android:versionName="1.0"> android:label="@string/app_name"> ActivityLifeCycle.javapackage com.studio.android;import android.app.Activity;import android.app.AlertDialog;import android.content.DialogInterface;import android.content.Intent;import android.content.DialogInterface.OnClickListener;import android.os.Bundle;import android.util.Log;import android.view.View;import android.widget.Button;public class ActivityLifeCycle extends Activity { private static final String TAG = "[LifeCycle]"; private Button btnOpenDialog; private Button btnOtherActivity; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); initialView();//对控件进行各种初始化操作 Log.i(TAG, "onCreate"); } @Override public void onRestart() { super.onRestart(); Log.i(TAG, "onRestart"); } @Override public void onStart() { super.onStart(); Log.i(TAG, "onStart"); } @Override public void onResume() { super.onResume(); Log.i(TAG, "onResume"); } @Override public void onPause() { super.onPause(); Log.i(TAG, "onPause"); } @Override public void onStop() { super.onStop(); Log.i(TAG, "onStop"); } @Override public void onDestroy() { super.onDestroy(); Log.i(TAG, "onDestroy"); } private void initialView() { btnOpenDialog = (Button)this.findViewById(R.id.btnOpenDialog); btnOtherActivity = (Button)this.findViewById(R.id.btnOtherActivity); Button.OnClickListener btnOpenDialogListener = new Button.OnClickListener(){ public void onClick(View v) { new AlertDialog.Builder(ActivityLifeCycle.this) .setIcon(android.R.drawable.ic_dialog_info) .setTitle("欢迎") .setMessage("欢迎使用本程序,Activity生命周期测试.") .setPositiveButton("确定", new OnClickListener(){ public void onClick(DialogInterface dialog, int which) { // TODO Auto-generated method stub } }).create().show(); } }; Button.OnClickListener btnOtherActivityListener = new Button.OnClickListener(){ public void onClick(View v) { Intent intent = new Intent(ActivityLifeCycle.this,OtherActivity.class); startActivity(intent); } }; btnOpenDialog.setOnClickListener(btnOpenDialogListener); btnOtherActivity.setOnClickListener(btnOtherActivityListener); } }运行后模拟器的界面如下:五、根据log信息,详细分析Activity的生命周期1、启动该程序: Activity的启动顺序是onCreate -> onStart -> onResume2、启动然后退出该程序:退出当前Activity时,onPause -> onStop -> onDestory3、启动改程序,然后点击“open dialog”按钮,打开一个新的按钮:我们发现打开或者关闭对话框时log信息无任何变化,这说明打开对话框不会影响当前activity的状态变化。4、预留问题:用非全屏显示的Activity,或者透明的Activity,模拟那种从运行到暂停的状态变化5、先启动ActivityLifeCycle,然后启动另外一个Activity1,最后返回ActivityLifeCycle: INCLUDEPICTURE "C:\\DOCUME~1\\reanow\\LOCALS~1\\Temp\\}DB9$2C[($U%E4UK0W)53SR.jpg" \* MERGEFORMATINET 注意,这里所打印出来的log信息,都是ActivityLifeCycle这个Activity里面的,进入另外的Activity1时相关的log信息未成打印出来。6、启动改程序,然后按Ctrl+F12切换屏幕方向,然后按返回键退出该程序:保存activity状态protected void onSaveInstanceState (Bundle outState)protected void onRestoreInstanceState (Bundle savedInstanceState)Android控件的继承关系一、View与ViewGroup关系View:View是可视化控件的基类,它主要提供了控件描绘和事件处理的方法。而可视化控件,是指重新实现了View的绘制和事件处理方法并最终与用户交互的对象,如文本显示、按钮等等。ViewGroup:ViewGroup类也是继承自View类,ViewGroup的作用就是作为View的容器,它负责对添加进ViewGroup的这些View进行管理和布局。一个ViewGroup还可以加入到另外一个ViewGroup里面。布局相关的控件并不直接显示给用户,其主要功能在于控制子控件在屏幕上的摆放位置。ViewGroup的嵌套关系:ViewGroup的继承关系图:二、各控件的继承关系三、视图的显示控制《Android/Ophone开发完全讲义》P34~38使用XML布局文件控制视图 《Android/Ophone开发完全讲义》4.2.2在代码中控制视图 《Android/Ophone开发完全讲义》4.2.3界面布局为了适应各式各样的界面风格,Android系统提供了5种布局,这5种布局分别是:LinearLayout(线性布局)TableLayout(表格布局)RelativeLayout(相对布局)AbsoluteLayout(绝对布局)FrameLayout(框架布局)利用这五种布局,可以在屏幕上将控件随心所欲的摆放,而且控件的大小和位置会随着屏幕大小的变化作出相应的调整。下面是这五个布局在View的继承体系中的关系:LinearLayout(线性布局)线性布局是程序中最常见的一种布局方式,线性布局可以分为水平线性布局和垂直线性布局两种,通过android:orientation属性可以设置线性布局的方向。下面是一个简单的线性布局的例子: android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="wrap_content" > android:layout_width="fill_parent" android:layout_height="wrap_content" /> android:orientation="horizontal" android:layout_width="fill_parent" android:layout_height="wrap_content" android:gravity="right"> 对应的模拟器上的布局效果以及框架图如下所示:最外层布局为垂直线性布局,宽度为整个屏幕(fill_parent),高度为刚好适合子控件(wrap_content)。然后依次添加一个EditText,一个水平布局的LinearLayout,在这个线性布局里面,摆放两个Button,该线性布局的gravity属性设置为”right”,所以里面的两个Button靠右显示。android:gravityLinearLayout标签有一个非常重要的属性gravity,该属性用于控制布局中控件的对齐方式。如果是没有子控件的控件设置此属性,表示其内容的对齐方式,比如说TextView里面文字的对齐方式;若是有子控件的控件设置此属性,则表示其子控件的对齐方式,比如上面例子里面的两个Button的对齐方式。gravity可以取以下值,如果需要设置多个属性值,需要使用“|”进行组合:android:gravity与android:layout_gravity的区别:android:gravity定义了这个元素内所有子元素对于这个元素的布局,比如一个TextView内部文字的对齐方式;android:layout_gravity定义了这个元素相对于父元素(比如Layout)的布局,比如一个TextView在整个Layout中的位置。这两个属性对应的常量值都是一样的,如上表所示。2、android: layout_weight首先需要注意的是,没有android:weight这样的属性,这个与上面的android:gravity不一样。我们可以通过设置控件的layout_weight属性以控制各个控件在布局中的相对大小。layout_weight属性是一个非负整数值。线性布局会根据该控件layout_weight值与其所处布局中所有控件layout_weight值之和的比值为该控件分配占用的区域。例如,在水平布局的LinearLayout中有两个Button,这两个Button的layout_weight属性值都为1,那么这两个按钮都会被拉伸到整个屏幕宽度的一半。如果layout_weight指为0,控件会按原大小显示,不会被拉伸;对于其余layout_weight属性值大于0的控件,系统将会减去layout_weight属性值为0的控件的宽度或者高度,再用剩余的宽度或高度按相应的比例来分配每一个控件显示的宽度或高度。下例简要说明该属性的用法: android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent"> android:layout_width="fill_parent" android:layout_height="fill_parent" android:layout_weight="1"> android:orientation="vertical" android:layout_width="fill_parent"android:layout_height="fill_parent" android:layout_weight="1"> android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="左上按钮" android:layout_gravity="left" /> android:orientation="vertical" android:layout_width="fill_parent"android:layout_height="fill_parent" android:layout_weight="1"> android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="右上按钮" android:layout_gravity="right" /> android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent" android:layout_weight="1" android:gravity="center"> android:layout_width="wrap_content" android:layout_height="wrap_content"android:text="中心按钮" /> android:orientation="horizontal" android:layout_width="fill_parent" android:layout_height="fill_parent" android:layout_weight="1"> android:layout_width="fill_parent" android:layout_height="fill_parent" android:layout_weight="1" android:gravity="left|bottom"> android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="左下按钮" /> android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent" android:layout_weight="1" android:gravity="right|bottom"> android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="右下按钮"/> 对应的模拟器上的布局效果以及框架图如下所示: INCLUDEPICTURE "C:\\DOCUME~1\\reanow\\LOCALS~1\\Temp\\%GGHL0NUXRWF(}26U2_H_~X.jpg" \* MERGEFORMATINET TableLayout(表格布局)表格布局模型以行列的形式管理子控件,每一行为一个TableRow的对象,当然也可以是一个View的对象。TableRow可以添加子控件,每添加一个为一列。android:layout_colum官方解释:The index of the column in which this child should be,也即是设置该控件在TableRow中所处的列。android:layout_span官方解释:Defines how many columns this child should span,也即是设置该控件所跨越的列数。android:collapseColumns官方解释:The 0 based index of the columns to collapse. The column indices must be separated by a comma: 1, 2, 5.也即是将TableLayout里面指定的列隐藏,若有多列需要隐藏,请用逗号将需要隐藏的列序号隔开。 android:stretchColumns官方解释:The 0 based index of the columns to stretch. The column indices must be separated by a comma: 1, 2, 5. You can stretch all columns by using the value "*" instead. Note that a column can be marked stretchable and shrinkable at the same time.也即是设置指定的列为可伸展的列,可伸展的列会尽量伸展以填满所有可用的空间,若有多列需要设置为可伸展,请用逗号将需要伸展的列序号隔开。 android:shrinkColumns官方解释:The 0 based index of the columns to shrink. The column indices must be separated by a comma: 1, 2, 5. You can shrink all columns by using the value "*" instead. 设置指定的列为可收缩的列。当可收缩的列太宽以至于让其他列显示不全时,会纵向延伸空间。当需要设置多列为可收缩时,将列序号用逗号隔开。 下面用一个例子简单说明TableLayout的用法: android:layout_width="fill_parent" android:layout_height="fill_parent"android:stretchColumns="1"> android:layout_column="1" android:text="打开..." android:padding="3dip" /> android:text="Ctrl-O" android:gravity="right" android:padding="3dip" /> android:layout_column="1" android:text="保存..." android:padding="3dip" /> android:text="Ctrl-S" android:gravity="right" android:padding="3dip" /> android:layout_column="1" android:text="另存为..." android:padding="3dip" /> android:text="Ctrl-Shift-S" android:gravity="right" android:padding="3dip" /> android:layout_height="2dip" android:background="#FF909090" /> android:text="*" android:padding="3dip" /> android:text="导入..." android:padding="3dip" /> android:text="*" android:padding="3dip" /> android:text="导出..." android:padding="3dip" /> android:text="Ctrl-E" android:gravity="right" android:padding="3dip" /> android:layout_height="2dip" android:background="#FF909090" /> android:layout_column="1" android:text="退出" android:padding="3dip" /> 对应的模拟器效果图如下所示: INCLUDEPICTURE "C:\\DOCUME~1\\reanow\\LOCALS~1\\Temp\\~`O8M5B1_0{1OCM[]ZEGYNP.jpg" \* MERGEFORMATINET 从效果图可以看出,该布局总共有三列,第一个TableRow里面的控件,从第1列开始布局。如果去掉所有控件的属性” android:layout_column="1"”,显示效果如下所示(总共3列,也即第0、1、2列,每一列都用虚线框标示): INCLUDEPICTURE "C:\\DOCUME~1\\reanow\\LOCALS~1\\Temp\\C}9O%4OPA{0FW$OS0(19421.jpg" \* MERGEFORMATINET 另外一个例子布局文件如下所示: android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="wrap_content" > android:layout_width="fill_parent" android:layout_height="wrap_content" android:collapseColumns="1" > android:text="表一" android:gravity="center" /> android:text="列0" android:background="@drawable/dot"/> android:text="列1" android:background="@drawable/dot"/> android:layout_width="fill_parent" android:layout_height="wrap_content" android:stretchColumns="1">将列序号用逗号隔开,例如:android:stretchColumns=“0,1”--> android:text="表二" android:gravity="center" /> android:text="列0不能伸展" android:background="@drawable/dot"/> android:text="列1可以伸展" android:gravity="right" android:background="@drawable/dot"/> android:layout_width="fill_parent" android:layout_height="wrap_content" > android:text="表三" android:gravity="center" /> android:text="这一列很长,将会造成下一列无法显示或显示不全" android:background="@drawable/dot" /> android:text="这一列被挤到了屏幕外" android:background="@drawable/dot"/> android:layout_width="fill_parent" android:layout_height="wrap_content" android:shrinkColumns="0">当需要设置多列为可收缩时,将列序号用逗号隔开,例如:android:shrinkColumns=“0,1”--> android:text="表四" android:gravity="center" /> android:text="由于设置成了可收缩,所以这一列不管有多长都不会把其他列挤出去" android:background="@drawable/dot" /> android:text="这一列会被显示完全" android:background="@drawable/dot" /> 对应的模拟器效果图如下所示: INCLUDEPICTURE "C:\\DOCUME~1\\reanow\\LOCALS~1\\Temp\\XN{5@X)SJ8I9C9P[X7YF9B5.jpg" \* MERGEFORMATINET 布局分析:最外层用了一个垂直的linearLayout来放置里面的4个TableLayout,每个TableLayout由两行构成,分别是一个TextView和一个TableRow,每一个TableRow都由两个TextView组成了两列。RelativeLayout(相对布局)相对布局的子控件会根据它们所设置的参照控件和参数进行相对布局。参照控件可以是父控件,也可以是其它子控件,但是被参照的控件必须要在参照它的控件之前定义。下面是一个简单的例子: android:layout_width="fill_parent" android:layout_height="fill_parent" > android:id="@+id/aclock" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerInParent="true" /> android:id="@+id/dclock" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_below="@id/aclock" 该数字时钟会顶到左屏幕边显示--> android:layout_alignLeft="@id/aclock"如果没有设置marginLeft 属性的话--> android:layout_marginLeft="40px" /> android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="当前时间:" android:layout_toLeftOf="@id/dclock" android:layout_alignTop="@id/aclock"/> 对应的模拟器效果图如下所示:另外一个相对布局的例子: android:layout_width="fill_parent" android:layout_height="fill_parent" > android:layout_height="wrap_content" android:textSize="20dp" android:text="按钮1"/> android:layout_height="wrap_content" android:textSize="20dp" android:text="按钮2" android:layout_toRightOf="@id/button1" android:layout_below="@id/button1" /> android:layout_height="wrap_content" android:textSize="20dp" android:text="按钮3" android:layout_toLeftOf="@id/button2" android:layout_below="@id/button2" /> android:layout_height="wrap_content" android:textSize="20dp" android:text="按钮4" android:layout_toRightOf="@id/button2" android:layout_above="@id/button2" /> android:layout_height="wrap_content" android:textSize="20dp" android:text="按钮5" android:layout_toRightOf="@id/button2" android:layout_below="@id/button2" /> 对应的模拟器效果图如下所示:AbsoluteLayout(绝对布局)绝对布局的子控件需要指定相对于此坐标布局的横纵坐标值,否则将会像框架布局那样被排在左上角。手机应用需要适应不同的屏幕大小,而这种布局模型不能自适应屏幕尺寸大小,所以应用的相对较少。下面以一个例子简单说明绝对布局: android:layout_width="fill_parent" android:layout_height="fill_parent" > android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="语文" android:layout_x="10px" android:layout_y="10px" /> android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="数学" android:layout_x="30px" android:layout_y="30px" /> android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="英语" android:layout_x="50px" android:layout_y="50px" /> FrameLayout(框架布局)框架布局是最简单的布局形式。所有添加到这个布局中的视图都以层叠的方式显示。第一个添加的控件被放在最底层,最后一个添加到框架布局中的视图显示在最顶层,上一层的控件会覆盖下一层的控件。这种显示方式有些类似于堆栈。 android:layout_width="fill_parent" android:layout_height="fill_parent"> android:layout_width="300dp" android:layout_height="300dp" android:layout_gravity="center" android:background="#FF33ffff" /> android:layout_width="240dp" android:layout_height="240dp" android:layout_gravity="center" android:background="#FF33ccff" /> android:layout_width="180dp" android:layout_height="180dp" android:layout_gravity="center" android:background="#FF3399ff" /> android:layout_width="120dp" android:layout_height="120dp" android:layout_gravity="center" android:background="#FF3366ff" /> android:layout_width="60dp" android:layout_height="60dp" android:layout_gravity="center" android:background="#FF3300ff" /> Toast我们可以用对话框显示各种信息来提示用户应用程序处于某个状态,或者完成了某项任务。但是对话框是以独占方式显示的,也就是说,如果不关闭对话框,就无法做其他的事情。Android提供了Toast来解决这个问题。通过Toast显示提示信息,就算提示信息还未关闭,用户也可以做其他的事情。如果只想在Toast上面显示文本信息,可以使用如下所示的代码:Toast textToast = Toast.makeText(this, "这里是用Toast显示的提示信息... ", Toast.LENGTH_LONG);textToast.show();该段代码使用Toast类的静态方法创建了一个Toast对象。该方法的第二个参数表示要显示的文本信息,第三个参数表示Toast提示信息显示的时间长短。该参数可以设置为Toast.LENGTH_SHORT(提示框在较短时间内关闭)或者Toast.LENGTH_LONG(提示框在较长时间内关闭)。Toast信息提示框没有按钮,也无法通过手机按键来关闭它,只能通过显示时间的长短来控制Toast信息提示框的关闭。创建Toast对象时请注意,在创建只显示文本的Toast对象时建议使用makeText方法,而不要直接使用new关键字创建Toast对象。虽然Toast有setText方法,但是不能在使用new关键字创建Toast对象后,再使用setText方法设置Toast信息提示框的文本信息。也就是说,下面的代码会抛异常:Toast toast = new Toast(this);toast.setText("这里是用Toast显示的提示信息... "); //执行这段代码会抛异常toast.show();如果现在Toast提示框上显示更加丰富的内容,可以使用Toast类的setView方法设置一个View对象,代码如下: View view = getLayoutInflater().inflate(R.layout.toast, null); TextView textView = (TextView) view.findViewById(R.id.textview); textView.setText("这里是用Toast显示的\n提示信息..."); Toast toast = new Toast(this); toast.setDuration(Toast.LENGTH_LONG); toast.setView(view); toast.show();为什么使用new创建一个Toast对象后,能够使用setView方法将一个View对象放在Toast提示框上,而不能通过setText来设置文本信息呢?其实makeText方法的代码和上面这段代码类似,同样是使用setView方法设置了一个View对象,Toast方法实际上就是通过一个View对象来显示信息的。如果创建Toast对象时未使用makeText方法,而是用new,那么在调用setText方法时View对象还没有创建出来(setText并不会负责创建对象的),系统自然会抛出异常了。如果同时有多条信息需要用Toast显示,系统会将这些信息缓存起来,等前一个Toast信息提示框关闭后,才会显示下一个Toast信息提示框。Toast信息提示框是顺序显示的。下面以一个例子说明Toast的使用:main.xml: android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent" > android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="只显示文本的Toast" /> android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="显示文本和图像的Toast" /> toast.xml: android:orientation="horizontal" android:layout_width="fill_parent" android:layout_height="fill_parent" android:background="#555" android:layout_margin="10dp"> android:layout_height="50dp" android:alt="51CTO下载-Android基础知识详解,毕业论文设计,开题报告,外文翻译" src="@drawable/face" /> android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_margin="10dp" /> main.java:public class Main extends Activity implements OnClickListener{ public void onClick(View v) { switch (v.getId()) { case R.id.btnTextToast: Toast textToast = Toast.makeText(this, "这里是用Toast显示的\n提示信息...",Toast.LENGTH_LONG); textToast.show(); break; case R.id.btnImageToast: View view = getLayoutInflater().inflate(R.layout.toast, null); TextView textView = (TextView) view.findViewById(R.id.textview); //R.id.textview是在toast.xml文件中定义的控件 textView.setText("这里是用Toast显示的\n提示信息..."); Toast toast = new Toast(this); toast.setDuration(Toast.LENGTH_LONG); toast.setView(view); toast.show(); break; } } public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); Button btnTextToast = (Button) findViewById(R.id.btnTextToast); Button btnImageToast = (Button) findViewById(R.id.btnImageToast); btnTextToast.setOnClickListener(this); btnImageToast.setOnClickListener(this); }}模拟器:NotificationNotification与Toast都可以起到通知、提醒的作用,但它们的实现原理和表现形式完全不一样。Toast相当于一个没有按钮的对话框。Notification是显示在屏幕上方状态栏中的信息,并且Notification需要用NotificationManager来管理,而Toast只需要简单创建Toast对象即可。下面来看创建并显示一个Notification的步骤: NotificationManager notificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE); Notification notification = new Notification(resId, tickerText, System.currentTimeMillis()); PendingIntent contentIntent = PendingIntent.getActivity(this, 0, getIntent(), 0); notification.setLatestEventInfo(this, contentTitle, contentText, contentIntent); notificationManager.notify(id, notification);(1)、通过getSystemService方法获得一个NotificationManager对象(2)、创建一个Notification对象。这一步设置显示在屏幕上方状态栏的通知消息对应的图像资源ID、通知消息内容、该通知将要发出的时间(一般设置为当前时间)(3)、由于Notification可以与应用程序脱离,也就是说,即使应用程序关闭,Notification仍然会显示在状态栏中。因此,需要创建一个PendingIntent对象,该对象由Android系统负责维护。(4)、使用Notification类的setLatestEventInfo方法设置Notification的详细信息,也就是将状态栏往下拖拽,在这部分里面显示的详细的提示信息。包括提示信息的标题,提示信息的具体内容等等。(5)、使用NotificationManager类的notify方法显示Notification消息。这一步需要指定标示该Notification消息的唯一ID。这个ID必须相对于同一个NotificationManager对象是唯一的,否则会覆盖相同ID的Notification。为了使这个值唯一,我们可以使用res目录中的某些资源ID,比如对应的图像资源的ID。如果需要清除某个消息,可以使用NotificationManager类的cancel方法,该方法只有一个参数,表示要清除的Notification的ID。使用cancelAll可以清除当前NotificationManager对象中所有的Notification。下面以一个实例详细说明相关的概念:AndroidManifest.xml: package="net.blogjava.mobile" android:versionCode="1" android:versionName="1.0"> android:label="@string/app_name"> main.xml: android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent"> android:layout_height="wrap_content" android:text="我今天非常高兴" android:drawablePadding="10dp" android:drawableLeft="@drawable/smile" /> android:layout_height="wrap_content" android:text="这是为什么呢?" android:drawablePadding="10dp" android:drawableLeft="@drawable/why" /> android:layout_height="wrap_content" android:text="今天心情不好" android:drawablePadding="10dp" android:drawableLeft="@drawable/wrath" /> android:layout_height="wrap_content" android:text="使用默认的声音" /> android:layout_height="wrap_content" android:text="使用默认的震动" /> android:layout_height="wrap_content" android:text="使用默认的Light" /> android:layout_height="wrap_content" android:text="所有的都使用默认值" /> android:layout_height="wrap_content" android:text="清除通知" /> main.java:public class Main extends Activity implements OnClickListener{ private NotificationManager notificationManager; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); notificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE); Button btnSmile = (Button) findViewById(R.id.btnSmile); Button btnWhy = (Button) findViewById(R.id.btnWhy); Button btnWrath = (Button) findViewById(R.id.btnWrath); Button btnClear = (Button) findViewById(R.id.btnClear); Button btnRing = (Button) findViewById(R.id.btnRing); Button btnVibrate = (Button) findViewById(R.id.btnVibrate); Button btnLight = (Button) findViewById(R.id.btnLight); Button btnRingAndVibrate = (Button) findViewById(R.id.btnRingAndVibrate); btnSmile.setOnClickListener(this); btnWhy.setOnClickListener(this); btnWrath.setOnClickListener(this); btnClear.setOnClickListener(this); btnRing.setOnClickListener(this); btnVibrate.setOnClickListener(this); btnLight.setOnClickListener(this); btnRingAndVibrate.setOnClickListener(this); } private void setDefaults(String tickerText, String contentTitle, String contentText, int id, int resId, int defaults) { Notification notification = new Notification(resId, tickerText, System.currentTimeMillis()); PendingIntent contentIntent = PendingIntent.getActivity(this, 0, new Intent(this, Main.class), 0); notification.setLatestEventInfo(this, contentTitle, contentText, contentIntent); notification.defaults = defaults; notificationManager.notify(id, notification); } private void showNotification(String tickerText, String contentTitle,String contentText, int id, int resId) { Notification notification = new Notification(resId, tickerText, System.currentTimeMillis()); PendingIntent contentIntent = PendingIntent.getActivity(this, 0, getIntent(), 0); notification.setLatestEventInfo(this, contentTitle, contentText, contentIntent); notificationManager.notify(id, notification); } public void onClick(View v) { switch (v.getId()) { case R.id.btnSmile: showNotification("今天非常高兴", //显示在状态栏上的提示文字 "今天考试得了全年级第一", //详细通知的标题 "数学100分、语文99分、英语100分,yeah!", //详细通知的具体内容 R.drawable.smile, //Notification对应的唯一ID值 R.drawable.smile); //资源图片的ID break; case R.id.btnWhy: showNotification("这是为什么呢?", "这道题为什么会出错呢?", "谁有正确答案啊.", R.drawable.why, R.drawable.why); break; case R.id.btnWrath: showNotification("今天心情不好", "也不知道为什么,这几天一直很郁闷.", "也许应该去公园散心了", R.drawable.wrath, R.drawable.wrath); break; case R.id.btnClear: notificationManager.cancelAll(); break; case R.id.btnRing: setDefaults("使用默认的声音", "使用默认的声音", "使用默认的声音", R.id.btnRing, R.drawable.smile, Notification.DEFAULT_SOUND); case R.id.btnVibrate: setDefaults("使用默认的震动", "使用默认的震动", "使用默认的震动", R.id.btnVibrate, R.drawable.smile, Notification.DEFAULT_VIBRATE); case R.id.btnLight: setDefaults("使用默认的Light", "使用默认的Light", "使用默认的Light", R.id.btnLight, R.drawable.smile, Notification.DEFAULT_LIGHTS); case R.id.btnRingAndVibrate: setDefaults("所有的都使用默认值", "所有的都使用默认值", "所有的都使用默认值", R.id.btnRingAndVibrate, R.drawable.smile, Notification.DEFAULT_ALL); break; } }}模拟器:对话框在Android系统中创建对话框的方式很多,使用AlertDialog类来创建对话框是最常用的一种方式。由于AlertDialog类的构造函数被声明为protected,所以不能直接使用new来创建AlertDialog类的对象实例。为了创建AlertDialog对象,需要使用Builder类,然后通过AlertDialog.Builder返回的AlertDialog对象的show方法显示对话框;或者通过Builder类的create方法返回AlertDialog对象,然后对该对话框进行一些必要的设置,最后通过AlertDialog类的show方法显示对话框,下面是这两种方式的示例代码:AlertDialog alertDialog = new AlertDialog.Builder(this).create();...alertDialog.setMessage("...");alertDialog.setTitle("...");...alertDialog.show();new AlertDialog.Builder(this) .setIcon(...) .setTitle(...) .setMessage(...) .setPositiveButton(...) .setNegativeButton(...) .show();AlertDialog.Builder有两个方法可以分别设置对话框的确定和取消按钮,这两个方法是://设置确认按钮的方法AlertDialog.Builder setPositiveButton(CharSequence text, DialogInterface.OnClickListener listener) AlertDialog.Builder setPositiveButton(int textId, DialogInterface.OnClickListener listener) //设置取消按钮的方法AlertDialog.Builder setNegativeButton(CharSequence text, DialogInterface.OnClickListener listener) AlertDialog.Builder setNegativeButton(int textId, DialogInterface.OnClickListener listener)还有一个方法,可以设置中性的按钮:AlertDialog.Builder setNeutralButton(CharSequence text, DialogInterface.OnClickListener listener)AlertDialog.Builder setNeutralButton(int textId, DialogInterface.OnClickListener listener) 上面这三个设置按钮的方法的调用顺序可以是任意的,也即是无论调用顺序怎样,setPositiveButton方法设置的按钮总会排在第一位,setNeutralButton方法设置的按钮总会排在第二位,setNegativeButton方法设置的按钮总会排在最后一位。使用AlertDialog类创建的对话框最多只能有3个按钮。这三个设置对话框按钮的方法虽然都可以被重复多次调用,但是系统只以每一个方法最后一次调用为准。如果不进行任何其它设置,只是简单地显示一个带Message的对话框,这个对话框并不会起多大的作用。因为在对话框上面没有按钮,除非按手机上的取消键,否则无法关闭这个对话框。为了给对话框加上图片、文字和按钮,可以在调用show方法之前,调用AlertDialog.Builder类中的相关方法对对话框进行设置,比如说左上角显示的图标、标题、提示信息等等,这些设置对话框相关信息的方法返回的都是AlertDialog.Builder对象,所以可以串在一起写。AlertDialog.Builder类有两个重要的方法:create和show,create虽然返回了AlertDialog对象,但是并不显示这个对话框,而show方法则会立即显示对话框。如果想在获得AlertDialog对象后做进一步处理,而不是立即显示该对话框,可以使用create方法,在相关事情处理完毕后,再调用show方法显示对话框。一、带三个按钮的对话框main.xml: android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent"> android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="显示 确认/忽略/取消 对话框"/> main.java:public class Main extends Activity implements OnClickListener{ @Override public void onClick(View v) { new AlertDialog.Builder(this) .setIcon(R.drawable.question) .setTitle("是否删除文件?") .setMessage("是否删除选定文件的对话框\n请想好后再点击相关按钮") .setPositiveButton("确定", new DialogInterface.OnClickListener(){ public void onClick(DialogInterface dialog, int whichButton) { new AlertDialog.Builder(Main.this).setMessage("您选择了确定按钮,文件已经被删除.").show(); } }) .setNeutralButton("忽略", new DialogInterface.OnClickListener(){ public void onClick(DialogInterface dialog, int whichButton) { new AlertDialog.Builder(Main.this).setMessage("您选择了忽略按钮,将跳过该操作.").show(); } }) .setNegativeButton("取消",new DialogInterface.OnClickListener(){ public void onClick(DialogInterface dialog, int whichButton) { new AlertDialog.Builder(Main.this).setMessage("您选择了取消按钮,该文件未被删除.")..show(); } }) .show(); } @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); Button button = (Button) findViewById(R.id.button); button.setOnClickListener(this); }}模拟器:二、简单列表对话框、单选列表对话框、多选列表对话框(1)、简单列表对话框通过AlertDialog.Builder类的setItems方法可以创建简单的列表对话框。这种对话框实际上相当于将ListView控件放在对话框上,然后在ListView中添加若干简单的文本。setItems方法的定义如下所示:AlertDialog.Builder setItems(int itemsId, DialogInterface.OnClickListener listener) AlertDialog.Builder setItems(CharSequence[] items, DialogInterface.OnClickListener listener)setItems可以通过传递一个字符串数组资源ID或字符串数组变量为对话框中的列表提供数据。(2)、单选列表对话框通过AlertDialog.Builder类的setSingleChoiceItems方法可以创建带单选按钮的列表对话框。setSingleChoiceItems方法有如下4种重载形式://从资源文件中装载数据AlertDialog.Builder setSingleChoiceItems(int itemsId, int checkedItem, DialogInterface.OnClickListener listener) //从字符串数组中装载数据AlertDialog.Builder setSingleChoiceItems(CharSequence[] items, int checkedItem, DialogInterface.OnClickListener listener) //从ListAdapter对象中装载数据AlertDialog.Builder setSingleChoiceItems(ListAdapter adapter, int checkedItem, DialogInterface.OnClickListener listener) //从数据集中装载数据AlertDialog.Builder setSingleChoiceItems(Cursor cursor, int checkedItem, String labelColumn, DialogInterface.OnClickListener listener)checkedItem:表示默认选中的列表项listener: 表示单击某个列表项时被触发的对象labelColumn:如果数据源是数据集,该数据集中指定的列会作为对话框的数据加载到列表框中(3)、多选列表对话框通过AlertDialog.Builder类的setMultiChoiceItems方法可以创建带复选框的列表对话框。setMultiChoiceItems方法有如下3种重载形式://从数据集中装载数据AlertDialog.Builder setMultiChoiceItems(Cursor cursor, String isCheckedColumn, String labelColumn, DialogInterface.OnMultiChoiceClickListener listener) //从资源文件中装载数据AlertDialog.Builder setMultiChoiceItems(int itemsId, boolean[] checkedItems, DialogInterface.OnMultiChoiceClickListener listener) //从字符串数组中装载数据AlertDialog.Builder setMultiChoiceItems(CharSequence[] items, boolean[] checkedItems, DialogInterface.OnMultiChoiceClickListener listener)checkedItems: 该参数的数组长度要和列表框中列表项个数相等,该参数用于设置每一个列表项的默认值,如果为true,表示当前的列表项为选中状态,否则表示未选中状态。listener: 表示选中某个列表项时被触发的对象。isCheckedColumn:确认列表项是否被选中,1表示选中,0表示未选中。下面的例子是创建这三种对话框的相关代码main.xml: android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent"> android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="显示列表对话框" /> android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="显示单选列表对话框" /> android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="显示多选列表对话框" /> Main.java:public class Main extends Activity implements OnClickListener{ private String[] citys = new String[]{ "北京", "上海", "深圳", "成都", "重庆", "营山" }; private boolean boolMultiChoiseDialog[] = new boolean[]{ false, true, false, true, false, false }; private ButtonOnClick buttonOnClick = new ButtonOnClick(1); private ListView lv = null; private void showListDialog() { new AlertDialog.Builder(this) .setTitle("选择城市") .setItems(citys, new DialogInterface.OnClickListener(){ public void onClick(DialogInterface dialog, int which) { final AlertDialog ad = new AlertDialog.Builder(Main.this).setMessage("您已经选择了: " + which + ":" + citys[which]).show(); //设置一个定时器,5秒钟后关闭对话框 android.os.Handler hander = new android.os.Handler(); hander.postDelayed(new Runnable(){ @Override public void run() { ad.dismiss();//调用AlertDialog类的dismiss方法关闭对话框,当然也可以调用cancel方法 } }, 5 * 1000); } }) .show(); } private void showSingleChoiceDialog() { new AlertDialog.Builder(this) .setTitle("选择城市") .setSingleChoiceItems(citys, 1, buttonOnClick) .setPositiveButton("确定",buttonOnClick) .setNegativeButton("取消", buttonOnClick) .show(); } private void showMultiChoiceDialog() { AlertDialog ad = new AlertDialog.Builder(this) .setIcon(R.drawable.image) .setTitle("选择城市") .setMultiChoiceItems(citys, boolMultiChoiseDialog, new DialogInterface.OnMultiChoiceClickListener(){ public void onClick(DialogInterface dialog,int whichButton, boolean isChecked) { } }) .setPositiveButton("确定", new DialogInterface.OnClickListener(){ public void onClick(DialogInterface dialog, int whichButton) { String s = "您选择了"+lv.getCheckedItemPositions().size()+"项--"; for (int i = 0; i < citys.length; i++) { /* SparseBooleanArray android.widget.ListView.getCheckedItemPositions() 说明 :Returns the set of checked items in the list. 返回值:A SparseBooleanArray which will return true for each call to get(int position) where position is a position in the list. SparseBooleanArray:SparseBooleanArrays map integers to booleans. Unlike a normal array of booleans there can be gaps in the indices. It is intended to be more efficient than using a HashMap to map Integers to Booleans. SparseBooleanArray的get(int key)方法: Gets the boolean mapped from the specified key, or false if no such mapping has been made. */ if (lv.getCheckedItemPositions().get(i)) { s += i + ":" + lv.getAdapter().getItem(i) + " "; } } if (lv.getCheckedItemPositions().size() > 0) { new AlertDialog.Builder(Main.this).setMessage(s).show(); } else { new AlertDialog.Builder(Main.this).setMessage("您未选择任何城市").show(); } } }) .setNegativeButton("取消", null) .create(); lv = ad.getListView();//获取多选列表对话框中的ListView对象 ad.show(); } private class ButtonOnClick implements DialogInterface.OnClickListener { private int index; //城市数组的索引 public ButtonOnClick(int index) { this.index = index; } //如果在单选列表对话框里面添加了按钮,在处理单击事件时需要同时考虑列表项和确定、取消按钮。 //由于它们的单击事件的接口都是DialogInterface.OnClickListener,因此,可以为这些单击事件编写一个内嵌的java类。 //然后将该类的对象传入setSingleChoiceItems、setPositiveButton、setNegativeButton public void onClick(DialogInterface dialog, int whichButton) { //whichButton表示单击的按钮或者列表项的索引,所有列表项的索引都是不小于0的,而按钮的索引都是小于0的 if( whichButton >= 0 ) { index = whichButton; //如果单击的是列表项,将当前列表项的索引保存在index里面 //如果想在单击列表项后关闭该对话框,可在此调用dialog.cancel()或者dialog.show() } else { if (whichButton == DialogInterface.BUTTON_POSITIVE) // -1 { new AlertDialog.Builder(Main.this).setMessage("您已经选择了:" + index + ":" + citys[index]).show(); } else if (whichButton == DialogInterface.BUTTON_NEGATIVE) // -2 { new AlertDialog.Builder(Main.this).setMessage("您什么都未选择").show(); } } } } @Override public void onClick(View view) { switch (view.getId()) { case R.id.btnListDialog: { showListDialog(); break; } case R.id.btnSingleChoiceDialog: { showSingleChoiceDialog(); break; } case R.id.btnMultiChoiceDialog: { showMultiChoiceDialog(); break; } } } @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); Button btnListDialog = (Button) findViewById(R.id.btnListDialog); Button btnSingleChoiceDialog = (Button) findViewById(R.id.btnSingleChoiceDialog); Button btnMultiChoiceDialog = (Button) findViewById(R.id.btnMultiChoiceDialog); btnListDialog.setOnClickListener(this); btnSingleChoiceDialog.setOnClickListener(this); btnMultiChoiceDialog.setOnClickListener(this); }}模拟器:三、水平进度对话框和圆形进度对话框下面以一个实际例子来说明水平进度对话框和圆形进度对话框的实现方式。本例中的进度对话框包括两个按钮:【暂停】和【取消】,单击暂停按钮后,对话框关闭,再次显示该对话框时,进度条的起始位置从上一次关闭对话框的位置开始(这个仅限于水平对话框)。单击取消按钮后,对话框关闭,再次显示该对话框时,进度的起始位置仍然从0开始。要实现进度随着时间的变化不断递增的效果,可以使用多线程以及定时器来完成这个工作。本例中使用Handler类来不断更新进度对话框的进度值。main.xml: android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent"> android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="显示进度对话框"/> android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="显示旋转指针对话框"/> Main.java:public class Main extends Activity implements OnClickListener{ private static final int MAX_PROGRESS = 200; private ProgressDialog progressDialog; private Handler progressHandler; private int progress; // 显示进度对话框,style表示进度对话框的风格 private void showProgressDialog(int style) { progressDialog = new ProgressDialog(this); progressDialog.setIcon(R.drawable.wait); progressDialog.setTitle("正在处理数据..."); progressDialog.setMessage("请稍后..."); progressDialog.setProgressStyle(style); //设置进度对话框的风格 progressDialog.setMax(MAX_PROGRESS); //设置进度对话框的进度最大值 // 设置进度对话框的【暂停】按钮 progressDialog.setButton(DialogInterface.BUTTON_POSITIVE,"暂停", new DialogInterface.OnClickListener(){ public void onClick(DialogInterface dialog, int whichButton) { progressHandler.removeMessages(1); //通过删除消息代码的方式停止定时器 } }); // 设置进度对话框的【取消】按钮 progressDialog.setButton(DialogInterface.BUTTON_NEGATIVE,"取消", new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int whichButton) { progressHandler.removeMessages(1); //通过删除消息代码的方式停止定时器的执行 progress = 0; //恢复进度初始值 progressDialog.setProgress(0); } }); progressDialog.show(); progressHandler = new Handler() { @Override public void handleMessage(Message msg) { super.handleMessage(msg); // 进度达到最大值,关闭对话框 if (progress >= MAX_PROGRESS) { progress = 0; progressDialog.dismiss(); } else { progress++; // 将进度递增1 progressDialog.incrementProgressBy(1); // 随机设置下一次递增进度(调用handleMessage方法)的时间 progressHandler.sendEmptyMessageDelayed(1, 50 + new Random().nextInt(500)); } } }; // 设置进度初始值 progress = (progress > 0) ? progress : 0; progressDialog.setProgress(progress); progressHandler.sendEmptyMessage(1); } @Override public void onClick(View view) { switch (view.getId()) { case R.id.button1: //显示进度条风格的进度对话框 showProgressDialog(ProgressDialog.STYLE_HORIZONTAL); break; case R.id.button2: //显示旋转指针风格的进度对话框 showProgressDialog(ProgressDialog.STYLE_SPINNER); break; } } @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); Button button1 = (Button) findViewById(R.id.button1); Button button2 = (Button) findViewById(R.id.button2); button1.setOnClickListener(this); button2.setOnClickListener(this); }}模拟器:注意事项:进度对话框默认情况下是圆形进度条,如果要显示水平进度条,需要使用setProgressStyle进行设置。虽然ProgressDialog类的getProgress方法可以获得当前进度,但只是在水平进度条风格的对话框中该方法才会有效。如果是圆形进度条,该方法永远返回的是0。圆形进度对话框中的进度圆圈只是一个动画图像,并没有任何表示进度的功能,这种对话框一般在很难估计准确时间和进度的情况下使用。四、自定义对话框虽然AlertDialog类提供了很多预定义的对话框,但是这些对话框也不能完全满足系统的需求。为了创建更丰富的对话框,也可以采用与创建Activity同样的方法。也就是说,直接使用XML布局文件或代码创建视图对象,并将这些视图对象添加到对话框中。AlertDialog.Builder类的setView方法可以将视图对象添加到当前的对话框中。可以使用下面的形式将一个视图对象添加到对话框中:new AlertDialog.Builder(this).setIcon(…).setTitle(…).setView(…).show();main.xml: android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent"> android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="显示登录对话框" /> login.xml: android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent"> android:orientation="horizontal" android:layout_width="fill_parent" android:layout_height="fill_parent" android:layout_marginLeft="20dp" android:layout_marginRight="20dp"> android:layout_width="wrap_content" android:text="用户名:" android:textSize="20dp" android:layout_height="wrap_content" /> android:layout_width="fill_parent" android:layout_height="wrap_content" /> android:orientation="horizontal" android:layout_width="fill_parent" android:layout_height="fill_parent" android:layout_marginLeft="20dp" android:layout_marginRight="20dp"> android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="密 码:" android:textSize="20dp" /> android:layout_width="fill_parent" android:layout_height="wrap_content" android:password="true" /> Main.java:public class Main extends Activity implements OnClickListener{ @Override public void onClick(View v) { LinearLayout loginLayout = (LinearLayout) getLayoutInflater().inflate(R.layout.login, null); new AlertDialog.Builder(this) .setIcon(R.drawable.login) .setTitle("用户登录") .setView(loginLayout) .setPositiveButton("登录", new DialogInterface.OnClickListener(){ public void onClick(DialogInterface dialog, int whichButton) { //编写处理用户登录的代码 } }) .setNegativeButton("取消",new DialogInterface.OnClickListener(){ public void onClick(DialogInterface dialog, int whichButton) { //取消用户登录,退出程序 } }) .show(); } @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); Button button = (Button) findViewById(R.id.button); button.setOnClickListener(this); }}模拟器五、使用Activity托管对话框Android/OPhone 开发完全讲义 P63六、创建悬浮对话框和触摸任何位置都可以关闭的对话框Android/OPhone 开发完全讲义 P64Menu菜单菜单是Android系统中重要的用户接口之一。在Android中提供了丰富多彩的菜单,比如系统的主菜单,也可称为选项菜单;带图像、复选框、选项按钮的菜单;上下文菜单。本章节将对这些菜单的使用进行详细讲解。选项菜单如果我们在Activity主界面按下手机的Menu按键,这时就会在屏幕底部弹出相应的带图标的选项菜单。这种带图标的选项菜单最多只能显示6个菜单项,当设置超过6个菜单项时,弹出的选项菜单只显示前五个菜单项,右下角的第六个菜单项时More的菜单项。用户点击这个More菜单项后会显示一个浮于主界面之上的一个扩展选项菜单,扩展选项菜单不支持显示图标,但可以显示单选框和复选框。如何定义Activity的选项菜单呢,当我们第一次调用选项菜单时,Activity会调用onCreateOptionsMenu()回调方法,所以只需要重新实现onCreateOptionsMenu()方法,并在里面初始化选项菜单就可以了。该方法的定义如下:public boolean onCreateOptionsMenu(Menu menu)通过Menu的add方法可以添加一个选项菜单项,该方法有4种重载形式,其定义如下:public MenuItem add (int titleRes) public MenuItem add (CharSequence title) public MenuItem add (int groupId, int itemId, int order, int titleRes) public MenuItem add (int groupId, int itemId, int order, CharSequence title)add方法最多有4个参数,这些参数的含义如下:groupId: 菜单项的分组ID,该参数一般用于选项菜单。该参数可以是负整数、0、正整数itemId: 当前添加的菜单项的ID,该参数可以使负整数、0、正整数order: 菜单显示顺序的ID,Android系统在显示菜单项时,根据order参数的值按照升序从左到右、从上到下显示相应菜单项。该参数必须是不小于0的正整数titleRes或title: 菜单项标题的字符串资源ID或字符串add方法返回的是一个MenuItem对象,每一个MenuItem对象对应一个菜单项。可以通过MenuItem的相应方法来设置与菜单项相关的内容。MenuItem的SetIntent方法,可以将一个Activity与菜单项关联,setIntent方法的定义如下:public abstract HYPERLINK "file:///D:\\android\\android_sdk\\docs\\reference\\android\\view\\MenuItem.html" MenuItem setIntent ( HYPERLINK "file:///D:\\android\\android_sdk\\docs\\reference\\android\\content\\Intent.html" Intent intent)将一个Activity与菜单项关联后,单击该菜单项后,系统会调用startActivity方法来显示与菜单项关联的Activity。如果同时也设置了菜单项的单击事件,则与该菜单项关联的Activity将失效。也就是说,系统将会调用单击事件方法,而不会显示与菜单项关联的Activity。下面是一个简单的选项菜单初始化的例子:MenuDemo.java:public class MenuDemo extends Activity { public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); } //选项菜单 public boolean onCreateOptionsMenu(Menu menu){ //public abstract MenuItem add(int groupId, int itemId, int order, CharSequence title) //Add a new item to the menu. This item displays the given title for its label. //这里需要注意的是,菜单项的id必须是唯一的,因为在处理选项菜单的点击事件时,就是通过该id来区分是哪一个菜单项被选中 menu.add(0,1,0,"save") .setIcon(android.R.drawable.ic_menu_save); menu.add(0,2,0,"delete") .setIcon(android.R.drawable.ic_menu_delete); return true; } public boolean onOptionsItemSelected(MenuItem item){ super.onOptionsItemSelected(item); switch(item.getItemId()){ case 1: new AlertDialog.Builder(this).setMessage("你点击了save按钮").show(); break; case 2: new AlertDialog.Builder(this).setMessage("你点击了delete按钮").show(); break; default: break; } return true; }}模拟器:上下文菜单上下文菜单是一种悬浮于主界面之上的菜单。当注册到一个View对象上以后,默认情况下用户可以通过长按View对象以调用上下文菜单。上下文菜单的每个元素依然是菜单项,但是它并不支持显示图标和设置快捷键。另外,上下文菜单还可以设置顶部标题和顶部图标。上下文菜单可以和任何View对象进行关联,比如TextView、EditText、Button等等。与选项菜单类似,初始化上下文菜单依然是通过重新实现onCreateContextMenu()回调方法来完成的,处理上下文菜单的菜单项的点击事件是通过重新实现onContextItemSelected()回调方法来完成的。如果要为View对象注册上下文菜单,需要使用registerForContextMenu()。与选项菜单不同的是,上下文菜单的初始化回调方法并不只被调用一次,它会在每次呼出上下文菜单时被调用。当一个View关联上下文菜单后,触摸该View,不要抬起,等一会儿就会显示上下文菜单。如果有一些View已经有了自己的上下文菜单,例如EditText,这种情况下,系统会将我们自定义的上下文菜单项添加到视图自带的上下文菜单项的后面。下面是一个关于上下文菜单的例子:MenuDemo.java:public class MenuDemo extends Activity { public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); TextView tv = new TextView(this); tv.setText("上下文菜单的载体"); registerForContextMenu(tv); setContentView(tv); } //创建上下文菜单 public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo info){ super.onCreateContextMenu(menu, v, info); //public abstract MenuItem add(int groupId, int itemId, int order, CharSequence title) //Add a new item to the menu. This item displays the given title for its label. //这里需要注意的是,菜单项的id必须是唯一的,因为在处理选项菜单的点击事件时,就是通过该id来区分是哪一个菜单项被选中 menu.add(0,1,0,"save") .setIcon(android.R.drawable.ic_menu_save); menu.add(0,2,0,"delete") .setIcon(android.R.drawable.ic_menu_delete); } public boolean onContextItemSelected(MenuItem item){ super.onOptionsItemSelected(item); switch(item.getItemId()){ case 1: new AlertDialog.Builder(this).setMessage("你点击了save按钮").show(); break; case 2: new AlertDialog.Builder(this).setMessage("你点击了delete按钮").show(); break; default: break; } return true; }}模拟器:三、子菜单子菜单是可以被添加到其它菜单上的菜单,不过子菜单不能添加到子菜单上。当我们有大量的菜单项需要被显示时,利用子菜单对这些菜单项进行分类是一个比较好的办法。这样可以让用户更容易找到他们所需的菜单项,同时也使得菜单看起来更整洁有条理。传统的子菜单是以层次结构显示的,而Android系统中的子菜单采用了弹出式的显示方式。也就是当单击带有子菜单的菜单项后,父菜单会关闭,在屏幕上会单独显示子菜单。在android中使用子菜单十分简单,我们只需把添加菜单项的add()方法替换成addSubMenu()方法,就可以给菜单添加子菜单。addSubMenu方法的定义如下:public SubMenu addSubMenu (int titleRes) public SubMenu addSubMenu (CharSequence title) public SubMenu addSubMenu (int groupId, int itemId, int order, int titleRes) public SubMenu addSubMenu (int groupId, int itemId, int order, CharSequence title)addSubMenu方法和add方法的参数个数和类型完全相同,所不同的是它们的返回值类型。addSubMenu返回的是一个SubMenu对象。可以通过SubMenu的add方法添加对应的子菜单。SubMenu的add方法与Menu的add方法在功能和使用方法上完全相同。在子菜单上还可以带复选框或者单选按钮,具体可以参照《Android/OPhone开发完全讲义》P73下面以一个例子对子菜单的用法进行说明:MenuDemo.java:public class MenuDemo extends Activity { public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); } //选项菜单 public boolean onCreateOptionsMenu(Menu menu){ menu.add(0,1,0,"save") .setIcon(android.R.drawable.ic_menu_save); menu.add(0,2,0,"delete") .setIcon(android.R.drawable.ic_menu_delete); SubMenu subMenu = menu.addSubMenu(0,3,0,"search").setIcon(android.R.drawable.ic_menu_search); subMenu.add(0,4,0,"本地"); subMenu.add(0,5,0,"网络"); return true; } public boolean onOptionsItemSelected(MenuItem item){ super.onOptionsItemSelected(item); switch(item.getItemId()){ case 1: new AlertDialog.Builder(this).setMessage("你点击了save按钮").show(); break; case 2: new AlertDialog.Builder(this).setMessage("你点击了delete按钮").show(); break; case 4: new AlertDialog.Builder(this).setMessage("你点击了子菜单'本地'按钮").show(); break; case 5: new AlertDialog.Builder(this).setMessage("你点击了资产的'网络'按钮").show(); break; default: break; } return true; }}模拟器:4种响应菜单项单击事件的方式onMenuItemSelected: 单击任何类型的菜单项(包括选项菜单项、选项菜单的子菜单项、上下文菜单项、上下文菜单的子菜单项),onMenuItemSelected方法都会被调用,如果多种类型的菜单要执行同一段代码的时候,可以考虑将所有这些代码放在onMenuItemSelected方法中。onOptionsItemSelected: 该方法在单击选项菜单以及选项菜单的子菜单项时被调用。如果只处理这两种类型的菜单,可以考虑将响应代码放在onOptionsItemSelected方法中。onContextItemSelected: 该方法在单击上下文菜单以及上下文菜单项的子菜单时被调用。如果只处理这两种类型的菜单,可以考虑将响应代码放在onContextItemSelected方法中。onMenuItemClick: 如果想将某些响应菜单项单击事件的代码独立出来,可以考虑设置这些菜单项的单击事件,也就是编写一个实现OnMenuItemClickListener接口的类,并将相关的代码放在OnMenuItemClickListener接口的onMenuItemClick方法中。这4个负责响应菜单项单击事件的方法都返回一个boolean类型的值。一般情况下,可以使这些方法永远返回true。如果onMenuItemClick方法返回false,Android系统仍然会继续调用onMenuItemSelected方法。实际上,在Activity. onMenuItemSelected方法中负责根据当前菜单项的类型调用onOptionsItemSelected或onContextItemSelected方法。当然,如果覆盖onMenuItemSelected方法后,未调用Super.onMenuItemSelected,系统就不会调用onOptionsItemSelected或onContextItemSelected方法了。如果onMenuItemSelected、onOptionsItemSelected或onContextItemSelected方法返回false(这里该true还是false,待进一步确认),则系统不会调用与菜单项关联的Activity类的startActivity方法,也就是说,与菜单项关联的Activity不会被显示。显示和编辑文本的控件在应用程序中经常需要显示和编辑文本,Android SDK中提供了TextView和EditText等组件,用于显示和编辑文本。下面将详细介绍这些相关的组件:TextView:Displays text to the user and optionally allows them to edit it. A TextView is a complete text editor, however the basic class is configured to not allow editing.CheckedTextView:An extension to TextView that supports the Checkable interface. This is useful when used in a ListView where the it's setChoiceMode has been set to something other than CHOICE_MODE_NONE.EditText:EditText is a thin veneer over TextView that configures itself to be editable.ExtraEditText:Specialization of EditText for showing and interacting with the extracted text in a full-screen input method.AutoComplteteTextView:An editable text view that shows completion suggestions automatically while the user is typing. The list of suggestions is displayed in a drop down menu from which the user can choose an item to replace the content of the edit box with.MultiAutoCompleteTextView:An editable text view, extending AutoCompleteTextView, that can show completion suggestions for the substring of the text where the user is typing instead of necessarily for the entire thing.下面是文本相关控件在继承体系中的继承关系:TextViewDisplays text to the user and optionally allows them to edit it. A TextView is a complete text editor, however the basic class is configured to not allow editing.TextView是用来显示文本的控件,我们可以对TextView做许多复杂的设置,比如,设置TextView的文字字体大小、文字颜色、背景颜色、文本距离TextView控件边缘的距离、TextView距离其它组件的间距等等,下面以几个例子简要说明这些属性。例一:设置TextView的padding和layout_margin android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent"> android:layout_width="fill_parent" android:layout_height="wrap_content" android:textColor="#3300ff" //设置文本的颜色 android:background="#66ffff" //设置背景颜色 android:text="设置文本颜色、背景颜色" /> android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="更多其它复杂的设置:padding、margin..." android:textSize="20dp" //设置文本大小 android:textColor="#FF00FF" android:background="#ffff00" android:padding="30dp" //设置TextView里面的文本距离该控件边缘的距离 android:layout_margin="30dp" /> //设置该控件距离相邻的其它控件的间距 上面代码中大多属性的含义可以通过属性的字面意思猜测出来,这里要注意两个属性:android:padding和android:layout_margin。android:padding属性用于设置文字距离TextView组件边缘的距离,android:layout_margin属性用于设置TextView组件距离相邻的其它组件的间距。android:padding:Sets the padding, in pixels, of all four edges. Padding is defined as space between the edges of the view and the view's content. A views size will include it's padding. If a background is provided, the padding will initially be set to that (0 if the drawable does not have padding). Explicitly setting a padding value will override the corresponding padding found in the background. android:paddingBottom: Sets the padding, in pixels, of the bottom edgeandroid:paddingLeft: Sets the padding, in pixels, of the left edgeandroid:paddingRight: Sets the padding, in pixels, of the right edgeandroid:paddingTop: Sets the padding, in pixels, of the right edgeandroid:layout_margin :Specifies extra space on the left, top, right and bottom sides of this view. This space is outside this view's bounds. android:layout_marginBottom :Specifies extra space on the bottom side of this view. This space is outside this view's bounds. android:layout_marginLeft: Specifies extra space on the left side of this view. This space is outside this view's bounds. android:layout_marginRight: Specifies extra space on the right side of this view. This space is outside this view's bounds. android:layout_marginTop: Specifies extra space on the top side of this view. This space is outside this view's bounds.除了可以在XML布局文件中设置TextView组件的属性以外,还可以在代码中设置其属性值,例如:textView.setTextColor(android.graphics.Color.RED); //设置字体颜色textView.setBackgroundResource(R.color.background); //设置背景颜色textView.setBackgroundColor(android.graphics.Color.RED); // 设置背景颜色textView.setBackgroundDrawable(getBaseContext().getResources().getDrawable(R.color.background));// 设置背景颜色例二:在TextView中显示URLTextView不仅可以显示普通的文本,还可以识别文本中的链接,并将这些链接转换成可单击的链接。系统会根据不同类型的链接调用相应的软件进行处理。比如,当这个链接是web地址时,单击该链接系统会启动web浏览器,并导航到该网址所指向的网页。TextView控件识别链接的方式有两种:自动识别和HTML解析。自动识别:自动识别是指TextView会将文本中的链接自动识别出来,这些链接并不需要做任何标记。实现自动识别链接的功能需要设置TextView的属性android:autoLink。该属性可设置的值如下:HTML解析:如果不设置TextView标签的Android:autoLink属性,就需要使用HTML的标签来显示可单击的链接。如果通过XML布局文件来设置TextView中的值,可以直接在字符串资源文件中用标签指定链接以及链接的文本,并在布局文件中引用字符串资源的ID。如果使用java代码来设置,需要使用android.text.Html类的fromHtml方法进行转换。下面用的例子中,设置了5个TextView组件,前三个使用自动识别链接的方式识别不同的链接,第四个TextView在字符串资源文件里面指定显示的文本;最后一个TextView在代码中使用Html.fromHtml方法将带等标签的文本转换成Spanned对象。相关的代码如下所示:布局文件 android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent" android:background="#FFFFFF"> android:layout_marginTop="20dp" android:layout_width="fill_parent" android:layout_height="wrap_content" android:textColor="#000000" android:autoLink="web" /> android:layout_marginTop="20dp" android:layout_width="fill_parent" android:layout_height="wrap_content" android:textColor="#000000" android:autoLink="email" /> android:layout_marginTop="20dp" android:layout_width="fill_parent" android:layout_height="wrap_content" android:textColor="#000000" android:autoLink="phone" /> android:layout_marginTop="20dp" android:layout_width="fill_parent" android:layout_height="wrap_content" android:textColor="#000000" android:autoLink="all" android:text="@string/link_text_manual"/> android:layout_marginTop="20dp" android:layout_width="fill_parent" android:layout_height="wrap_content" android:textColor="#000000" android:autoLink="all"/> 字符串资源文件: Hello World Hello 博客:http://blog.csdn.net/wuliming_sc 相关代码: public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); //自动识别链接的方式 TextView tvWebURL = (TextView) findViewById(R.id.tvWebURL); tvWebURL.setText("博客:http://blog.csdn.net/wuliming_sc"); TextView tvEmail = (TextView) findViewById(R.id.tvEmail); tvEmail.setText("电子邮件:thinking@qq.com"); TextView tvPhone = (TextView) findViewById(R.id.tvPhone); tvPhone.setText("联系电话:13800138000"); //在代码中设置带HTML标签的文本 TextView textView2 = (TextView) findViewById(R.id.textview2); textView2.setText(Html.fromHtml("博客:http://blog.csdn.net/wuliming_sc")); }CheckedTextViewAn extension to TextView that supports the Checkable interface. This is useful when used in a ListView where the it's setChoiceMode has been set to something other than CHOICE_MODE_NONE.CheckedTextView将和Listview一起总结。EditTextEditText是TextView类的子类,因此,EditText控件具有TextView的一切XML属性和方法。它们的区别是EditText还可以输入文本,而TextView只能显示文本。EditText可以通过多种方式指定允许输入的字符,例如,如果只想输入数字,可以使用如下三种方式:将EditText标签的android:digits属性值设为0123456789将EditText标签的android:numeric属性值设为integer将EditText标签的android:inputType属性值设为number android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent" android:gravity="center_horizontal"> android:layout_height="wrap_content" android:text="使用android:digits属性(输入数字)" /> android:textColor="#000000" android:background="#FFFFFF" android:layout_margin="10dp" android:digits="0123456789" /> //选中该文本框,不会自动弹出虚拟键盘 android:layout_height="wrap_content" android:text="使用android:numeric属性(输入有符号的浮点数)" /> android:textColor="#000000" android:background="#FFFFFF" android:layout_margin="10dp" android:numeric="decimal|signed"/> //选中该文本框,会自动弹出虚拟键盘 android:layout_height="wrap_content" android:text="使用android:inputType属性(输入数字)" /> android:textColor="#000000" android:background="#FFFFFF" android:layout_margin="10dp" android:inputType="number" /> //选中该文本框,会自动弹出虚拟键盘 android:layout_height="wrap_content" android:text="使用android:digits属性(输入26个小写字母)" /> android:textColor="#000000" android:background="#FFFFFF" android:layout_margin="10dp" android:digits="abcdefghijklmnopqrstuvwxyz" />//选中该文本框,不会自动弹出虚拟键盘 android:layout_height="wrap_content" android:text="使用android:inputType属性(输入Email)" /> android:textColor="#000000" android:background="#FFFFFF" android:layout_margin="10dp" android:inputType="textEmailAddress" /> //选中该文本框,会自动弹出虚拟键盘 在使用android:inputType属性设置EditText允许输入的字符,当焦点落在该控件上时,显示的虚拟键盘会随着inputType属性值的不同而不同。用android:digits属性设置EditText允许输入的字符,当焦点落在该控件上时,不会弹出虚拟键盘。ExtraEditTextSpecialization of EditText for showing and interacting with the extracted text in a full-screen input method.AutoComplteteTextView、MultiAutoCompleteTextView (自动完成输入内容)AutoCompleteTextView和EditText类似,都可以输入文本。但是AutoCompleteTextView可以和一个字符串数组或者List对象绑定,当用户输入两个以及以上字符的时候,系统将在AutoCompleteTextView下方列出字符串数组中所有以输入字符开头的字符串,这个和google的搜索框类似。MultiAutoCompleteTextView具有连续输入的功能。也就是说,当输入完一个字符串后,在该字符串后面输入一个逗号,在逗号前后可以有任意多个空格,然后再输入一个字符串,仍然会显示辅助输入的列表。但是要使用MultiAutoCompleteTextView类的setTokenizer方法指定MultiAutoCompleteTextView.CommaTokenizer类的对象实例(该对象表示输入多个字符串时的分隔符是逗号)。下面以一个例子简单说明: android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent"> android:text="AutoCompleteTextView" /> android:layout_width="fill_parent" android:layout_height="wrap_content" /> android:text="MultiAutoCompleteTextView" /> android:layout_width="fill_parent" android:layout_height="wrap_content" /> public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); String[] autoString = new String[] { "a", "ab", "abc", "abcd","abcde","abcdef","bc", "bcd", "bcdf","bcdfg","bcdfgh","bcdfghi" }; ArrayAdapter adapter = new ArrayAdapter(this,android.R.layout.simple_dropdown_item_1line, autoString); // AutoCompleteTextView AutoCompleteTextView autoCompleteTextView = (AutoCompleteTextView) findViewById(R.id.autoCompleteTextView); autoCompleteTextView.setAdapter(adapter); // MultiAutoCompleteTextView MultiAutoCompleteTextView multiAutoCompleteTextView = (MultiAutoCompleteTextView) findViewById(R.id.multiAutoCompleteTextView); multiAutoCompleteTextView.setAdapter(adapter); multiAutoCompleteTextView.setTokenizer(new MultiAutoCompleteTextView.CommaTokenizer()); }Button ImageButton ZoomButtonButton按钮是用得最多的一种控件,Button直接继承于View。最常用的按钮事件是单击事件,可通过设置Button类的setOnClickListener方法来设置单击事件的处理方法。如果当前类实现了android.view.View.OnClickListener接口,可以直接将this传入setOnClickListener方法:btnTmp. setOnClickListener(this)我们可以通过调用View的setBackgroundDrawable()方法传入Drawable对象或者引用Drawable资源的id,来设置Button显示的背景图片。当然,也可以在XML布局文件中设置android:background值为一个Drawable资源。如果按钮需要动态的调整大小,用固定大小的背景图片就会比较麻烦,需要根据按钮上要显示的文字的宽高对图片进行调整。在android里面,我们可以使用9patch图片来解决这个问题。9patch是android支持的可按规则拉伸的png格式的图片。后缀名为”.9.png”。实际上,9patch图片就是在原来png图片的上下左右分别多了一个像素的边界,通过在这个额外的边界上画黑色的直线,以此设置背景图片的哪些区域会被拉伸、以及向那个方向拉伸。我们可以通过Android SDK提供的9patch图片专用绘图工具draw9-patch打开一张图片png图片,该工具在sdk的安装路径的tools目录里面。通过该工具,在按钮区域外扩展一个像素,并用黑色像素点在这扩展的一像素的边界上画直线:如上图所示,四角区域的图片,在伸展的过程中不做任何改变,保持原样;最上边和最下边两块区域只能在水平方向伸展;最左边和最右边两块区域只能载垂直方向伸展;中间这块区域向两个方向伸展。右边是对应的效果图,最上面的效果图,是原始尺寸的背景图片只在垂直方向做伸展;中间的效果图是原始尺寸的背景图片只在水平方向做伸展。同时显示图像和文字的按钮要同时显示文字和图像,最简单的办法是使用Button标签的android:drawableX属性,其中X的可取值是Top、Bottom、Left、Right。分别表示在文字的上方、下方、左边、右边显示图像。该属性需要指定一个图像资源ID。android:drawableX的属性,可以多个一起使用,比如同时使用android:drawableBottom和android:drawableLeft,则在该按钮文字的下方、左边都会显示指定的图像。我们还可以使用android:drawablePadding属性设置文字到图像之间的距离。下面的代码设置了4个按钮,并分别在上下左右显示图像: android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent"> android:layout_height="wrap_content" android:drawableTop="@drawable/star" android:text="按钮1" /> android:layout_height="wrap_content" android:drawableBottom="@drawable/star" android:text="按钮2" android:drawablePadding="30dp" /> android:layout_height="wrap_content" android:drawableLeft="@drawable/star" android:text="按钮3" /> android:layout_height="wrap_content" android:drawableRight="@drawable/star" android:text="按钮4" android:drawablePadding="20dp"/> ImageButtonImageButton并不是TextView的子类,而是ImageView的之类。因此,Android:text属性并不起作用。ImageButton控件的android:src属性用来设置图片的背景。如果想在代码里面修改ImageButton的图像,可以使用ImageButton类的setImageResource或其它同类的方法。下面的代码,配置了两个带背景图片的按钮: android:orientation="horizontal" android:layout_width="fill_parent" android:layout_height="fill_parent"> android:layout_width="wrap_content" android:layout_height="wrap_content" android:alt="51CTO下载-Android基础知识详解,毕业论文设计,开题报告,外文翻译" src="@drawable/button1_1" /> android:layout_width="wrap_content" android:layout_height="wrap_content" android:alt="51CTO下载-Android基础知识详解,毕业论文设计,开题报告,外文翻译" src="@drawable/button2_1" /> 效果图如下所示:ZoomButton......日期和时间控件DatePicker、TimePickerDatePicker控件用于输入日期,日期的范围是1900-1-1~2100-12-31 通过DatePicker类的getYear、getMonth、getDayOfMonth方法可以分别获得DatePicker控件当前的年、月、日。DatePicker通过init方法进行初始化,init方法的定义如下:void android.widget.DatePicker.init(int year, int monthOfYear, int dayOfMonth, OnDateChangedListener onDateChangedListener)其中year、monthOfYear、dayOfMonth参数分别用来设置年月日,onDateChangedListener参数用来设置DatePicker控件的日期变化事件对象。TimePicker控件用来输入时间,只能输入小时和分钟。TimePicker默认情况下是12小时制,如果想以24小时制显示时间,可以使用TimePicker类的setIs24HourView方法来设置。当TimePicker的时间变化时,会触发OnTimeChanged事件,但是与DatePicker控件不同的是,TimePicker通过setOnTimeChangedListener方法设置时间变化的事件对象,而DatePicker通过init方法设置日期变化的事件对象。下面以一个例子来说明这两个控件的使用情况:main.xml: android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent"> android:layout_width="fill_parent" android:layout_height="wrap_content"/> android:layout_width="fill_parent" android:layout_height="wrap_content"/> android:layout_width="fill_parent" android:layout_height="wrap_content" android:textSize="18dp"/> android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="设置日期" android:textSize="18dp"/> android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="设置时间" android:textSize="18dp"/> Main.java:public class Main extends Activity implements OnDateChangedListener,OnTimeChangedListener{ private TextView textView; private DatePicker datePicker; private TimePicker timePicker; private Button btnSetDate; private Button btnSetTime; private Calendar c; @Override public void onTimeChanged(TimePicker view, int hourOfDay, int minute) { textView.setText("当前时间:"+ timePicker.getCurrentHour()+":"+timePicker.getCurrentMinute()+"\n"); } @Override public void onDateChanged(DatePicker view, int year, int monthOfYear, int dayOfMonth) { textView.setText("当前日期:"+ datePicker.getYear()+"-"+datePicker.getMonth()+"-"+datePicker.getDayOfMonth()+"\n"); } @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); datePicker = (DatePicker) findViewById(R.id.datepicker); timePicker = (TimePicker) findViewById(R.id.timepicker); textView = (TextView) findViewById(R.id.textview); btnSetDate = (Button)findViewById(R.id.btnSetDate); btnSetTime = (Button)findViewById(R.id.btnSetTime); c = Calendar.getInstance(); datePicker.init(2008, 8, 8, this); //初始化日期,并设置其事件的监听方法 timePicker.setOnTimeChangedListener(this); //设置时间选择控件的事件监听方法 timePicker.setIs24HourView(false); //设置日期格式:12或者24小时 timePicker.setCurrentHour(18); //设置小时 timePicker.setCurrentMinute(18); //设置分钟 btnSetDate.setOnClickListener(new Button.OnClickListener(){ public void onClick(View v) { new DatePickerDialog(Main.this, new DatePickerDialog.OnDateSetListener() { public void onDateSet(DatePicker view, int year, int monthOfYear,int dayOfMonth) { //设置日期 datePicker.updateDate(year, monthOfYear, dayOfMonth); } },c.get(Calendar.YEAR),c.get(Calendar.MONTH),c.get(Calendar.DAY_OF_MONTH)) .show(); } }); btnSetTime.setOnClickListener(new Button.OnClickListener(){ public void onClick(View v) { new TimePickerDialog(Main.this, new TimePickerDialog.OnTimeSetListener() { public void onTimeSet(TimePicker view, int hourOfDay, int minute) { //设置时间 timePicker.setCurrentHour(hourOfDay); timePicker.setCurrentMinute(minute); } },c.get(Calendar.HOUR_OF_DAY),c.get(Calendar.MINUTE),true).show(); } }); }}模拟器:AnalogClock、DigitalClockAnalogClock控件用来以表盘的形式显示时间。该控件自有两个指针:时针和分针。DigitalClock控件用来以数字方式显示当前时间。该控件可以显示时分秒。AnalogClock直接继承于View;DigitalClock直接继承于TextView。main.xml: android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent" android:gravity="center_horizontal"> android:layout_width="fill_parent" android:layout_height="wrap_content" /> android:layout_width="wrap_content" android:layout_height="wrap_content" android:textSize="18dp" /> 单选框、复选框、开关状态按钮单项选择(RadioGroup、RadioButton)Android平台提供了单项选择的控件,可以通过RadioGroup、RadioButton组合起来完成一个单项选择效果。下面通过一个例子来演示相关的功能:main.xml: android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent"> android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="@string/hello" /> android:layout_width="wrap_content" android:layout_height="wrap_content" android:orientation="vertical" android:layout_x="3px" android:layout_y="54px" > android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/RadioButton1" /> android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/RadioButton2" /> android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/RadioButton3" /> Activity.java:public class Activity01 extends Activity{ RadioGroup m_RadioGroup; RadioButton m_Radio1, m_Radio2, m_Radio3; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); m_RadioGroup = (RadioGroup) findViewById(R.id.RadioGroup01); m_Radio1 = (RadioButton) findViewById(R.id.RadioButton1); m_Radio2 = (RadioButton) findViewById(R.id.RadioButton2); m_Radio3 = (RadioButton) findViewById(R.id.RadioButton3); /* 设置事件监听 */ m_RadioGroup.setOnCheckedChangeListener(new RadioGroup.OnCheckedChangeListener() { public void onCheckedChanged(RadioGroup group, int checkedId) { if (checkedId == m_Radio1.getId()) { DisplayToast("您选择的是:" + m_Radio1.getText()); } else if (checkedId == m_Radio2.getId()) { DisplayToast("您选择的是:" + m_Radio2.getText()); } else { DisplayToast("您选择的是:" + m_Radio3.getText()); } } }); } /* 显示Toast */ public void DisplayToast(String str) { Toast toast = Toast.makeText(this, str, Toast.LENGTH_LONG); //设置toast显示的位置 toast.setGravity(Gravity.TOP, 0, 220); //显示该Toast toast.show(); }}strings.xml: 你喜欢下面那一种操作系统? Examples Windows Linux Moc os 复选框(CheckBox)多项选择与单项选择最重要的区别就在于它可以让用户选择一个以上的选项。既然用户可以选择多项,为了确认用户是否选择的了某一项,需要对每一个选项进行事件监听。我们可以对CheckBox设置OnCheckedChangeListener事件监听,也可以设置OnClickListener,因为CheckBox是从Button继承而来。CheckBox默认情况下是未选中状态。如果想修改这个默认值,可以将android:checked属性值设置为true,或者使用CheckBox类的setChecked方法设置CheckBox的状态。在代码中可以使用CheckBox类的isChecked方法判断是否被选中。下面看一个例子,当用户选择完毕并提交后,会向用户提示相关的信息:main.xml: android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent" > android:id="@+id/TextView1" android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="@string/hello" /> android:id="@+id/CheckBox1" android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="@string/CheckBox1"> android:id="@+id/CheckBox2" android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="@string/CheckBox2"> android:id="@+id/CheckBox3" android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="@string/CheckBox3"> android:id="@+id/CheckBox4" android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="@string/CheckBox4"> Activity.java:public class Activity01 extends Activity{ CheckBox m_CheckBox1; CheckBox m_CheckBox2; CheckBox m_CheckBox3; CheckBox m_CheckBox4; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); /* 取得每个CheckBox对象 */ m_CheckBox1 = (CheckBox) findViewById(R.id.CheckBox1); m_CheckBox2 = (CheckBox) findViewById(R.id.CheckBox2); m_CheckBox3 = (CheckBox) findViewById(R.id.CheckBox3); m_CheckBox4 = (CheckBox) findViewById(R.id.CheckBox4); final CheckBox.OnCheckedChangeListener btnListener = new CheckBox.OnCheckedChangeListener() { public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { int num = 0; String strTmp = ""; if(m_CheckBox1.isChecked()) { num++; strTmp += m_CheckBox1.getText() + "\n" ; } if(m_CheckBox2.isChecked()) { num++; strTmp += m_CheckBox2.getText() + "\n" ; } if(m_CheckBox3.isChecked()) { num++; strTmp += m_CheckBox3.getText() + "\n" ; } if(m_CheckBox4.isChecked()) { num++; strTmp += m_CheckBox4.getText() + "\n" ; } strTmp = "你选择了" + num + "项,它们分别是:" + "\n" + strTmp; DisplayToast(strTmp); } }; //对每个选项设置事件监听 m_CheckBox1.setOnCheckedChangeListener(btnListener); m_CheckBox2.setOnCheckedChangeListener(btnListener); m_CheckBox3.setOnCheckedChangeListener(btnListener); m_CheckBox4.setOnCheckedChangeListener(btnListener); } public void DisplayToast(String str) { Toast toast = Toast.makeText(this, str, Toast.LENGTH_SHORT); toast.setGravity(Gravity.TOP, 0, 220); //设置toast显示的位置 toast.show(); //显示该Toast }}开关状态按钮(ToggleButton)ToggleButton控件提供了可以表示“开/关”状态的功能。ToggleButton通过在该按钮下方显示一个绿色的指示条表示“开/关”状态。至于绿色的指示条表示开还是关,用户可以自行决定。不过一般来讲绿色的指示条默认为开启状态,白色的指示条默认为关闭状态。虽然ToggleButton是Button的子类,但android:text属性不再起作用。如果要更改默认的按钮文本,可以使用android:textOff和android:textOn属性。默认情况下,按钮上的指示条为白色,如果要在XML布局文件中修改默认值,可以使用android:checked属性,在代码中使用ToggleButton类的setChecked方法。将android:checked属性设置为true时,指示条显示为绿色。main.xml: android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent"> android:layout_width="wrap_content" android:layout_height="wrap_content"/> android:layout_width="wrap_content" android:layout_height="wrap_content" android:checked="true" android:textOff="灯灭:关闭状态" android:textOn="灯亮:开启状态" /> 下拉列表框SpinnerSpinner控件用于显示一个下拉列表。该控件的用法与ListView控件类似,在装载数据的时候也需要创建一个Adapter对象,并在创建Adapter对象的过程中指定要装载的数据(数组、List对象等等)。下面简要介绍一下Spinner数据的几种绑定方式:数组绑定private static final String[] strWeeks={”星期一”,”星期二”,”星期三”,”星期四”,”星期五”,”星期六”,”星期天”};mySpinner = (Spinner) findViewById(R.id.mySpinner);ArrayAdapter adapter = new ArrayAdapter(this, android.R.layout.simple_spinner_item, strWeeks);mySpinner.setAdapter(adapter);列表绑定ArrayList cityList= new ArrayList();//初始化一个city的String arraylistcityList.add("北京");cityList.add("上海");cityList.add("深圳");cityList.add("成都");cityList.add("营山");mySpinner = (Spinner) findViewById(R.id.mySpinner);ArrayAdapter adapter = new ArrayAdapter(this,android.R.layout.simple_spinner_item,cityList);mySpinner.setAdapter(adapter);从XML文件里面获取数据res/values/arrays.xml代码如下:- 中国·北京
- 中国·上海
- 中国·深圳
- 中国·成都
- 中国·营山
布局文件中,Spinner的定义如下:android:layout_width="wrap_content" android:layout_height="wrap_content"android:entries="@+array/ strCityName"/>下面以一个例子说明下拉列表框的使用方式main.xml: android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent"> android:layout_height="wrap_content" /> android:layout_height="wrap_content" android:layout_marginTop="20dp"/> item.xml: android:orientation="horizontal" android:layout_width="fill_parent" android:layout_height="wrap_content"> android:layout_height="60dp" android:alt="51CTO下载-Android基础知识详解,毕业论文设计,开题报告,外文翻译" src="@drawable/icon" android:paddingLeft="10dp" /> android:layout_width="wrap_content" android:layout_height="fill_parent" android:textSize="16dp" android:gravity="center_vertical" android:paddingLeft="10dp" /> Main.java:public class Main extends Activity{ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); //第一个下拉列表框设置 Spinner spinner1 = (Spinner) findViewById(R.id.spinner1); String[] applicationNames = new String[]{ "Android", "window mobile", "iphone", "blackberry", "QQphone" }; ArrayAdapter aaAdapter = new ArrayAdapter(this,android.R.layout.simple_spinner_item, applicationNames); //如果加上下面这条语句,列表项将带RadioButton组件,不加这一句的话,将显示普通的下拉列表框 //aaAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); spinner1.setAdapter(aaAdapter); //第二个下拉列表框相关设置 Spinner spinner2 = (Spinner) findViewById(R.id.spinner2); final List
51CTO下载-Android基础知识详解,毕业论文设计,开题报告,外文翻译
3997
来源:
Licence:
联系:
分类:
平台:
环境:
大小:
更新:
标签:
免费下载
×
温馨提示
请用电脑打开本网页,即可以免费获取你想要的了。