打造高质量Android应用:Android开发必知的50个诀窍(txt+pdf+epub+mobi电子书下载)


发布时间:2020-07-22 22:51:08

点击下载

作者:(美)塞萨(Sessa,C.)

出版社:机械工业出版社

格式: AZW3, DOCX, EPUB, MOBI, PDF, TXT

打造高质量Android应用:Android开发必知的50个诀窍

打造高质量Android应用:Android开发必知的50个诀窍试读:

推荐序

Android是一个迅速向各个领域扩张的生态系统。每天都会有厂商发布新的设备和外观设计,每天都会有客户购买和激活上百万台设备,每天都会有用户下载和试用新的应用程序。开发美观、有吸引力并且令用户满意的应用程序来丰富和完善这个生态系统是每一位开发者(希望也包括读者本人)应尽的责任,只有这样才能为用户提供更好的交互体验。

Android是一个软件开发平台,它诞生于2003年年底,由Danger公司(开发流行的Sidekick手机的公司)的前雇员开发。2005年,运营Android的Danger公司被Google公司收购。三年后,HTC Dream(G1)作为第一款运行Android操作系统的手机正式发布。此后三年,虽然硬件与平台发生了很大的更新和迭代,但是Android依然保持为一个单纯的手机操作系统。

2011年,Google公司为Android添加了新的特性,增加了对两种设备的支持:平板电脑和电视。这不仅标志着官方第一次扩充Android所支持设备的种类,还激发了厂商对其他潜在支持设备的兴趣。现在,Android已经可以运行在笔记本电脑、手表、视频游戏机、车载音响等多种设备上。我相信在不久的将来Android会支持更多的设备。

作为应用开发者,理解平台的多样化和发展方向是非常重要的。在Android上做开发已经不像为竖屏手机设计软件那么简单了。尽管这意味着开发者开发应用程序的工作量增加了,但是,最终结果却是无论应用程序运行在哪种设备上,都会为使用者提供良好的用户体验。

在开发应用程序的过程中,除了个人创造力和开发意愿以外,开发者还需要具备三样东西:平台开发文档、开源社区以及整合资源并融会贯通的能力。平台开发文档比较容易获取,最新版本托管在http://developer.android.com网站上。开源社区有GitHub、Google Code、Stack Overflow以及其他类似网站,这些网站提供了开源库、代码片段以及能够简化程序开发的设计模式。此外,开发者还需要具备把上述零散的知识整合到应用中的能力。这个整合的过程可不像搭积木一样简单,如果那样,任何人都可以开发应用了。本书便是一本分析如何整合资源的指南。

本书以示例程序的形式分析如何解决Android开发过程中出现的常见问题。书中有些示例程序相对简单,有些示例程序相当复杂。这些示例程序分享了一些只有零散或者零星文档可查但是却经常困扰开发者的问题。本书不仅仅是一本单纯学习和掌握Android开发技巧的书,更是一本填补空白的书。

精心设计一个能够动态支持所有Android设备的应用是一项艰巨的任务。通过学习本书以及类似出版物和在线资源提供的知识,我希望能提升读者开发和发布应用的能力。除此之外,我跟读者一样,也是一名开发者和热心用户,我也在耐心等待下一个精彩应用的出现,或许读者就是那个开发它的人。Jake WhartonAndroid工程师序

早在2009年我便开始研究Android。当时,Android 1.5刚刚发布并且显示出巨大的发展潜力。

在2009年7月,得益于澳大利亚的一位朋友,我拿到了第一台运行Android操作系统的设备,这台设备就是运行Android 1.5的HTC Magic手机。说实话,这台设备的运行速度比我想象的要慢,但是我依然通过它开始研究Android的API,并且根据自己的需求开发应用程序,然后在这台设备上运行这些应用。当时,我预感到Android会获得更多人的关注,我相信如果我能为Android开发一款应用程序,这款应用程序一定能被许多人使用。

事实证明,我的预感是正确的。不久后,Android开发的大幕便拉开了,而且发展得越来越快。一时间,许多支持Android平台的工具和第三方开发库便涌现出来,从cocos2d-x这样的游戏框架到Apache Maven这样的编译系统,几乎无所不包。

2010年11月,我受邀审阅Manning出版社出版的《Android in Practice》(www.manning.com/collins/)一书。当深度参与到这项工作之后,我突然想到,我可以用另一种方法写一本Android开发的书。我打算模仿Joshua Bloch所著的《Effective Java》(www.amazon.com/Effective-Java2nd-Joshua-Bloch/dp/0321356683)一书的风格,向读者展示这些年来我在Android开发过程中总结的小窍门和开发模式。

从根本上讲,我想在一本书里涵盖开发过程中总结的我知道的所有小窍门,并为这些小窍门提供一定的解释性文档。本书汇聚了开发与众不同的Android应用程序所需要的技巧和窍门。

我喜欢《Effective Java》一书的原因是,这本书没有特定的章节顺序,因此可以自由学习不同章节的内容。每隔一段时间,当回顾此书时,我总能为当前项目找到一些不同的应用程序。在写这本书的时候,我一直牢记一个信条:我想象读者在上班路上或者睡觉前会有兴趣学习本书里的某个Hack,并且从这个Hack中获得对当前项目有益的启发。

我已经在新项目中应用了这本书的内容,我会在特定的工作任务中复用书中的示例代码,使用示例代码向同事解释特定的开发模式。实践证明,本书对我是十分有用的,当然,我也希望这本书对你同样有用。

撰写本书以及书中的示例代码时,我把最小SDK版本设置为1.6。如非特别提及,本书中多数技巧都适用于Android 1.6及其以上版本。你会注意到,有一些技巧只适用于最新版本的Android,但是多数建议和技巧都适用于所有版本。每个Hack都提供一个图标,用来表示这个Hack适用的最低SDK版本。

那么接下来,你就从本书的目录中挑选自己感兴趣的技巧开始学习吧。希望你能从我写的内容中学到尽可能多的知识。

致谢

每当读到其他书的致谢时,我总会惊讶作者感谢的人竟然如此之多。现在终于明白为什么需要感谢这么多人,当写到这里的时候,我很紧张,生怕遗漏了某个人。

首先,我要感谢的是编辑Cynthia Kane,她帮助我加工整理整本书的内容。她不仅指出本书中需要修改的每个地方,还处理我英语语言上需要润色的地方,并且帮助我理解图书出版过程中的每个关键环节。修订每一行文字,修改她发现的每一个不足之处,通过这个反复迭代的修正过程,终于完成了这本值得我骄傲的书。

其次应该感谢Nicholas Chase,Nick负责支持Manning出版社的XML文档结构和创作工具。幸运的是,每当我有问题需要请教他时,他的Skype总是在线。

Manning出版团队的其他成员也参与了大量工作。参与这项工作的有Ozren Harlovic、Kevin Sullivan、Tara McGoldrick Walsh、Benjamin Berg、Katie Tennant、Candace Gillhoolley、Martin Murtonen、Michael Stephens以及Maureen Spencer。

感谢我的合著者:William Sanville(Hack 40和Hack 41)、Chris King(Hack 26)以及Christopher Orr(Hack 50)。他们分享了在这些领域的专业知识。

感谢Cyril Mottier,他深入阅读了本书,并且毫不保留地指出书中他不喜欢或者认为需要改进的地方。他始终对本书保持高要求,我很喜欢跟他合作。非常感谢!

感谢我在NASA Trained Monkeys公司的合作伙伴们。他们帮助我审阅了书中大部分内容,并提出很多建设性意见。大部分很酷的Hack标题都来源于他们丰富的想象力。

感谢Android社区,特别感谢那些对开源软件库有贡献的人们。(这里只提及几个人的名字,他们是:Michael Burton、Manfred Moser、Matthias K.ppler、Jake Wharton、Jeremy Feinstein、cocos2d-x团队、Jan Berkel、Jeff Gilgelt、Xavi Rigau、Chris Banes、James Brechtel和Dmitry Skiba)。

感谢审阅本书的每一个人。你们的审阅意见帮助我及时发现疏漏的地方以及需要强化的主题。从我敬佩的人那里获得正面的评价是很有意义的事情。感谢以下审阅者,你们在百忙之中审阅本书,我也希望这本书对你们有一些启发,这些人是:Adam Koch、Alberto Pose、Bill Cruise、Christian Badenas、Frank Ableson、Ignacio Luciani、Jeff Goldschrafe、Joshua Skinner、Matthias K.ppler、Maximiliano Gomez Vidal、“Ming”、Octavian Damiean、Paul Butcher、Robi Sen、Roger Binns、Shan Coster、Suzanne Alexandra和Will Turnage。

感谢我的家人和朋友——你们给予我巨大的支持。

最后要感谢Mili,你的工作同样重要,每当我需要帮助的时候,你总是在我身边。我爱你。

关于本书

Android是一个发展势头很好的项目。Android的第一个正式版本(Android 1.0)发布于2008年9月23日,截至2010年年底,Android已经发展成为首要的智能手机平台。

每当有新版本发布,Android都会引入一组新的API和新特性。尽[1]管在Android 1.5的时期,市场上只有HTC Dream手机运行Android系统,但是发展至今,Android系统不仅可以运行在从手机到电视等多种设备上,还可以运行在不同屏幕大小的平板电脑和笔记本电脑上。

上述情况给Android开发者带来了两个不小的难题。第一个难题是开发者必须面对和适配Android支持的不同类型的设备。虽然有很多方法处理不同的屏幕尺寸和像素密度,但是开发者必须开发出能够运行在各种设备上并且显示正常的应用。另外,需要对各种Android设备可能导致的用户体验不一致的情况做出处理。用户对手机和电视的使用习惯是不同的。

第二个难题是Android的版本更新问题。这个难题是周而复始的:使用新版本的Android系统,意味着开发者可以使用新的API,新的API可以为应用程序增加优秀的功能;但是开发者必须同时支持旧的Android版本,因为并不是每个用户都会升级系统,而且目标用户获取和认可应用程序也需要一定时间。

开发者需要在两者之间做出选择:要么使用新的API功能并发布一个特定版本的应用,满足那些使用新版本Android系统的用户;要么采取折中的方法,保证一些新的功能只适用于新版本的Android系统。

上述选择最终都由Android开发者决定,因此我写这本书的目的是帮助开发者解决这个难题。本书以“问题/解决方案”的形式提出开发过程中遇到的问题并给出其解决方法,并对一些已有问题提供了进一步的处理方案。什么是Android

Android是一个基于Linux内核的开源操作系统。起初,Android只支持手机设备,但是发展到现在,Android可以运行于平板电脑、电视、电脑甚至汽车音响等多种设备。Android在移动领域赢得了巨大的发展空间,到目前为止,50%以上的移动设备运行了Android操作系统。

运行在Android操作系统上的应用通常使用Java语言开发,Android提供了一个强大的SDK(软件开发工具包)供开发者开发不同类型的应用程序。Android允许开发者定制几乎所有模块,例如,开发者可以开发定制的墙纸、键盘、桌面以及在其他平台上想都不敢想的功能。本书读者对象

本书适用于已经学习过Android开发的程序员,并且假定读者已经熟悉Java编程语言,并理解Android平台的基本概念。

本书不仅提供适用于Android初学者的技巧,还提供适用于高级开发者的技巧。如果读者正在开发Android应用程序,我相信通过本书,你可以学到很多有帮助的知识。

通过以下几个问题,读者可以知道本书是否适合自己:

·你是一个Android应用程序开发者吗?

·你正在绞尽脑汁思考更好的解决方案吗?

·你正在寻找新的方法解决编程中出现的问题吗?

·你想知道其他人是如何解决类似问题的吗?如何使用本书

我的建议是:在读者学习每一条Hack前,先编译并运行示例代码,这样有助于读者更好地理解每个案例。此外,读者不需要按照特定顺序学习本书,读者可以随时跳转到自己感兴趣的章节开始学习。本书结构

虽然读者可以灵活选择自己感兴趣的部分学习,不会因为前后章节顺序的原因出现阅读困难,但是读者仍然可以按顺序阅读本书。各章节的概要内容如下:

·第1章包含4个Hack,讲解布局相关的小窍门。

·第2章包含4个Hack,介绍动画处理相关的小窍门。

·第3章包含9个Hack,涵盖与View相关的小窍门。

·第4章包含两个Hack,概括除IDE以外的可用工具。

·第5章包含4个Hack,提供适用于Android开发的模式示例。

·第6章包含7个Hack,提供一组适用于ListView和Adapter类的小窍门。

·第7章包含两个Hack,解释如何在应用中使用第三方库。

·第8章包含两个Hack,通过一些例子,解释如何用Java以外的编程语言为Android编写程序。其中一个Hack分析如何与Objective-C语言交互,另一个Hack分析如何与Scala语言交互。

·第9章包含6个Hack,提供一些可以复用的代码片段。

·第10章包含3个Hack,展示一些使用数据库的高级技巧。

·第11章包含4个Hack,展示如何令应用程序运行在不同的Android版本上。

·第12章通过最后3个技巧提供如何构建应用的小窍门。代码规范和下载

本书所有示例代码都以monospace字体显示。注释直接写在代码中,对于较长的注释,使用数字编号标识。

本书所有示例代码都可以从出版社网站下载,出版社网址是[2]www.manning.com/50AndroidHacks。读者也可以从Google公司的code项目中下载源代码,下载最新示例代码的方法列在附录中。此外,示例代码托管在GitHub中,读者还可以从https://github.com/Macarse/50AH-code下载。

如果要运行本书的示例代码,读者需要安装以下工具:

·Eclipse

·Android SDK

·Eclipse Android插件

如果读者不知道如何安装,我建议首先访问http://developer.android.com/sdk/installing/index.html,这里提供了配置开发环境的简单步骤。作者在线支持

Manning出版社运营的网上论坛为本书提供免费的在线支持。读者可以通过该论坛发表关于本书的意见和建议,也可以提问技术问题,还可以从作者和其他读者处得到帮助和支持。访问和订阅该论坛的方法很简单,读者只需要在浏览器中输入以下网址:www.manning.com/50AnroidHacks。这个网页提供了论坛注册后的注意事项、读者服务以及论坛规则等信息。

Manning出版社对读者的承诺是:提供一个在读者和读者之间,以及读者和作者之间可以产生良好互动的交流场所。出版社并不能保证作者有充足的时间与读者互动,因为作者完全是自愿且免费为论坛服务的。我们建议读者多向作者提问一些有挑战的问题,以激发作者答疑的兴趣。

本书出版后,读者可以从出版社的网站访问作者在线支持论坛查看已有的讨论帖。关于作者

Carlos Sessa不仅是一位充满激情的全职Android开发者,同时,他也是一家移动开发公司的创始人,公司名称为NASA Trained Monkeys,位于阿根廷的布宜诺斯艾利斯。他的公司专注于为Android和iOS等移动开发平台提供解决方案。[1] 代号Cupcake,纸杯蛋糕。——译者注[2] 截止本书翻译时,该网址已经更改为http://www.manning.com/sessa/。——译者注

关于原书封面插图

本书英文版封面插图中的人物是一个樵夫。这幅插图取自Sylvain Maréchal所著的四卷《区域服饰习俗概要》,该书于19世纪在法国出版。书中每幅插图都经过精心绘制和手工着色。通过大量丰富多彩的图片,Maréchal向我们生动地展示了如何从文化上区分200年前世界上不同的城镇和地区。由于彼此隔绝,不同地区的人们说着不同的方言和语言。无论是在街道还是在乡间,我们可以仅仅根据服饰区分出人们生活的区域、职业以及状况。

此后,着装要求和区域服饰的多样化发生了变化,当时丰富多彩的服饰也逐渐消失。现在已经很难区分不同大陆的居民,就更不用说区分不同的城镇和地区的居民了。或许,我们以文化的多样性为代价换来了丰富多彩的个人生活,当然,换来的是更多样、更快节奏的科技生活。

当计算机书籍千篇一律,读者很难一次就区分出不同的计算机书籍的时候,Manning出版社赞赏计算机业务部门通过图书封面呈现多样性的创造思维和主动性,本书便以Maréchal描绘的两个世纪前不同区域的丰富多彩和活灵活现的生活写照来体现这种多样性。第1章活用布局

本章将介绍Android布局相关的一些窍门和建议。通过本章,读者不仅可以学习如何从零开始创建特定类型的布局,还可以学到如何改进和优化现有布局。Hack 1 使用weight属性实现视图的居中显示

Android v1.6+

在给开发者做演讲时,当我解释如何通过XML文件创建视图的时候,一个开发者问道:“如果我想将按钮居中显示,并且占据其父视图宽度的一半,应该怎么做呢?”起初,我并没有完全理解他的意思,后来他把想要实现的功能画在了黑板上,我才恍然大悟。他想实现的功能如图1-1和图1-2所示。

看起来很简单是吗?现在开始,请读者用5分钟时间实现这个功能。在这个Hack里,我们分析如何结合LinearLayout的android:weightSum属性和LinearLayout的子视图的android:layout_weight属性来解决这个问题。这听起来似乎很简单,不过我经常在面试中问到这个问题,很少有面试者知道最佳答案。图1-1 居中显示按钮,并占据父视图50%宽度(竖屏)图1-2 居中显示按钮,并占据父视图50%宽度(横屏)1.1 合用weightSum属性和layout_weight属性

不同Android设备的尺寸往往是不同的。作为开发者,我们需要创建适用于不同尺寸屏幕的XML文件。硬编码是不可取的,因此需要其他方法来组织视图。

本节分析如何合用layout_weight和weightSum这两个属性来填充布局内部的任意剩余空间。android:weightSum(见1.3节)的开发文档里的一段描述与我们现在想要实现的功能类似,文档内容如下:“定义weight总和的最大值。如果未指定该值,以所有子视图的layout_weight属性的累加值作为总和的最大值。一个典型的案例是:通过指定子视图的layout_weight属性为0.5,并设置LinearLayout的weightSum属性为1.0,实现子视图占据可用宽度的50%。”

设想一个场景:我们要在盒子里放置其他物体。盒子可用空间的比例就是weightSum,盒子中每个物体可用空间的比例就是layout_weight。例如,盒子的WeightSum是1,我们需要往盒子里放置两个物体:物体A和物体B。物体A的layout_weight为0.25,物体B的layout_weight为0.75。那么,物体A可以占据盒子25%的空间,而物体B可以占据剩下的75%的空间。

本章开头所讨论问题的解决方案是与之类似的。我们为父视图指定一个weightSum,然后指定Button的android:layout_weight属性为weightSum的一半。XML文件的源码如下所示:

在①中,指定LinearLayout的android:weightSum属性值为1,表示其内部所有子视图的weight比例总和是1。LinearLayout只有唯一一个子视图:Button控件。在②中,指定Button的android:layout_width属性值为0dp,因此需要根据android:weight-Sum属性决定Button的width。在③中,指定Button的android:layout_weight属性值为0.5,最终Button将占据50%的可用空间。

接下来以宽为200dp,android:weightSum属性值为1的Linear-Layout为例分析上述过程。计算Button宽度的公式如下:

因为指定Button的宽度为0dp,Button的weight为0.5,sum(weight)等于1,所以结果如下:1.2 概要

当开发者需要根据比例分配布局可用空间的时候,使用LinearLayout的weight属性是很有必要的,这避免了使用硬编码的方式带来的副作用。如果目标平台是Honeycomb并且使用Fragment,读者会发现绝大多数案例中都是使用weight在布局文件中为Fragment分配空间。深入理解如何使用weight会为读者增添一项重要技能。1.3 外部链接

http://developer.android.com/reference/android/widget/LinearLayout.htmlHack 2 使用延迟加载以及避免代码重复

Android v1.6+

当创建复杂的布局时,开发者可能会发现添加了很多View-Group和View控件。随之而来的问题是View树的层次越来越深,应用程序也越来越慢。优化布局是创建运行速度快,响应灵敏的应用程序的基础。

在这个Hack里,读者会学到如何在XML文件中使用标签来避免代码的重复以及如何使用ViewStub类实现视图的延迟加载。2.1 使用标签避免代码重复

设想一种情况:我们需要为应用程序中的每个视图都添加一个页脚。为了简化问题,我们假设页脚是一个显示应用程序名的TextView。通常多个Activity会对应多个XML文件。难道我们需要把这个TextView复制到每个XML文件中吗?如果以后需要修改这个TextView会出现什么情况?“复制/粘贴”的方式固然能够解决这个问题,但并不是高效的方法。解决上述问题的最简单方法是使用标签。接下来分析该标签是如何解决这个难题的。

我们可以通过标签把在其他XML文件中定义的布局插入当前布局文件中。在本节的示例代码里,我们将创建一个完整的视图布局文件,在该文件最后的位置,使用标签插入页脚布局。以其中一个Activity为例,其XML布局文件如下所示:

footer_with_layout_properties布局文件如下所示:

在上述示例代码中,我们使用了标签,并且只需要指定该标签的layout属性值。读者可能会想:“这种方式之所以可行是因为Activity在main布局文件中使用的是RelativeLayout。如果其中一个Activity的布局文件使用的是LinearLayout呢?虽然android:layout_alignParentBottom="true"适用于RelativeLayout,但是并不适用于LinearLayout。”这个想法是正确的。接下来分析使用标签的第二种方法,在这种方法里,我们直接在标签里使用android:layout_*属性。

以下是修改后的main.xml文件,其中使用了标签的android:layout_*属性,源码如下所示:

修改后的页脚布局文件如下:

在第二种方法中,我们通过标签指定页脚的位置。[1]Android的缺陷(Issue)跟踪系统中报告过一个缺陷,缺陷的标题是:“标签失效了,如果想通过标签的属性覆盖被包含的布局所指定的属性是行不通的。”。这个issue描述的问题在一定程度上是正确的,问题出在如果想在标签中覆盖被包含布局所指定的任何android:layout_*属性,必须在标签中同时指定android:layout_width和android:layout_height这两个属性。

在这个Hack中,读者有没有注意到一个小细节?在第二个示例程序中,我们把所有android:layout_*属性都移到标签中了,而footer.xml文件中的layout_width和layout_height属性都指定为0dp。这么做的目的是由footer.xml文件的使用者在标签中指定layout_width和layout_height属性。如果使用者不指定这两个属性,它们的默认值都是0,我们便看不到页脚。[1] Issue原始地址位于http://code.google.com/p/android/issues/detail?id=2863。——译者注2.2 通过ViewStub实现View的延迟加载

设计布局的时候,读者可能想过根据上下文或者用户交互情况显示一个视图。如果想要一个视图只在需要的时候显示,请继续往下阅读,你会尝试使用ViewStub这个类。

Android开发文档中有关于ViewStub的介绍(参照2.4节),主要内容如下:“ViewStub是一种不可视并且大小为0的视图,可以延迟到运行时填充(inflate)布局资源。当ViewStub设置为可视或者inflate()方法被调用后,就会填充布局资源,然后ViewStub便会被填充的视图替代。”

既然已经清楚ViewStub是什么,接下来看看它能做什么。在下面的示例代码中,我们使用ViewStub来延迟加载一个MapView。假设需要创建一个视图来显示地理位置的详细信息,先看两种可能情况:

·一些场所没有GPS信息

·用户可能并不需要地图信息

如果一个场所没有GPS信息,开发者不需要在地图上显示标记信息。同样,如果用户不需要地图信息,也就无须加载地图。我们可以把MapView放置在ViewStub标签中,让用户自己决定是否显示地图信息。

要达到上述目的,需要使用下面的布局:

很显然,需要通过map_stub这个ID从Activity中获取ViewStub。同时,以android:layout属性指定需要填充的布局文件。对于本例,需要填充的布局文件是map.xml文件,源码如下:

最后一个需要说明的属性是inflatedId。inflatedId是调用ViewStub的inflate()方法或者setVisibility()方法时返回的ID,这个ID便是被填充的View的ID。在本例中,我们不需要操作MapView,只需要调用setVisibility(View.VISIBLE)方法即可。如果想获取被填充的视图的引用,inflate()方法会直接返回该引用,这样避免了再次调用findViewById()方法。

Activity的源码比较简单,如下所示:

如上述代码所示,只需要改变ViewStub的可视性便可控制map的显示。2.3 概要

标签是整理布局的有效工具。如果读者使用过Fragment,会发现它与标签的使用方法几乎是相同的。就像使用Fragment一样,完整的视图可以由一系列标签组成。

标签提供了合理组织XML布局文件的有效方法。如果读者正在创建一个复杂的布局或者布局文件变得很大,那么可以试试创建不同的布局片段,然后通过标签将这些片段组合起来。这样XML布局文件就会变得更清晰更易组织。

ViewStub是实现延迟加载视图的优秀类。无论在什么情况下,只要开发者需要根据上下文选择隐藏或者显示一个视图,都可以用ViewStub实现。或许并不会因为一个视图的延迟加载而感觉到性能的明显提升,但是如果视图树的层次很深,便会感觉到性能上的差距了。2.4 外部链接

http://code.google.com/p/android/issues/detail?id=2863

http://android-developers.blogspot.com.ar/2009/03/android-layout-tricks-3-optimize-with.html

http://developer.android.com/reference/android/view/ViewStub.htmlHack 3 创建定制的ViewGroup

Android v1.6+

当设计应用程序时,开发者可能需要在不同的Activity中显示复杂的视图。假设读者正在开发一款扑克牌游戏,需要创建类似图3-1的布局来显示玩家的手牌。应该如何创建这样的布局呢?图3-1 扑克牌游戏中的玩家手牌

或许读者会说,使用margin属性便足以实现这种布局。答案是正确的,开发者可以使用RelativeLayout布局管理器,然后为其内部View控件指定margin属性值,这样便可以实现类似上图的的功能,XML布局文件源码如下:

上述布局的显示效果如图3-2所示。

在这个Hack里,我们分析实现上述功能的另一种方法:创建自定义ViewGroup。该方法相对于在XML文件中手工指定margin值有如下优点:

·在不同Activity中复用该视图时,更易维护。

·开发者可以使用自定义属性来定制ViewGroup中子视图的位置。

·布局文件更简明,更容易理解。

·如果需要修改margin,不必重新手动计算每个子视图的margin。图3-2 使用Android默认控件创建的玩家手牌

接下来首先看看Android是如何绘制视图的。3.1 理解Android绘制视图的方式

在创建自定义ViewGroup前,读者首先需要理解Android绘制视图的方式。我不会涉及过多细节,但是需要读者理解Android开发文档(见3.5节)中的一段话,这段话解释如何绘制一个布局。内容如下:“绘制布局由两个遍历过程组成:测量过程和布局过程。测量过程由measure(int,int)方法完成,该方法从上到下遍历视图树。在递归遍历过程中,每个视图都会向下层传递尺寸和规格。当measure方法遍历结束,每个视图都保存了各自的尺寸信息。第二个过程由layout(int,int,int,int)方法完成,该方法也是由上而下遍历视图树,在遍历过程中,每个父视图通过测量过程的结果定位所有子视图的位置信息。”

为了理解这个概念,下面分析ViewGroup的绘制过程。第一步是测量ViewGroup的宽度和高度,在onMeasure()方法中完成这步操作。在该方法中,ViewGroup通过遍历所有子视图计算出它的大小。最后一步操作,在onLayout()方法中完成,在该方法中,ViewGroup利用上一步计算出的测量信息,布局所有子视图。3.2 创建CascadeLayout

本节开始为自定义ViewGroup编码。读者会看到与图3-2一样的结果。将自定义ViewGroup命名为CascadeLayout。CascadeLayout使用的XML布局文件如下所示:

现在读者已经理解需要创建什么功能,接下来我们就正式开始了。我们要做的第一件事是定义那些定制的属性。为此,需要在res/values目录下创建一个属性文件attrs.xml,该文件的内容如下:

同时还需要指定水平间距和垂直间距的默认值,以便在未指定这些值时使用。把这些默认值保存在dimens.xml文件中,该文件同样位于res/values文件夹下。dimens.xml文件的内容如下:

理解了Android如何绘制View之后,读者可能会想到实现一个继承自ViewGroup的CascadeLayout类,然后在CascadeLayout类中重写ViewGroup的onMeasure()和onLayout()方法。接下来的代码有点长,我们分成三部分内容分别予以分析。这三部分是:构造函数、onMeasure()方法和onLayout()方法。先看构造函数,代码如下:

在编写onMeasure()方法之前,先创建自定义LayoutParams类,该类用于保存每个子视图的x、y轴位置。把LayoutParams定义为CascadeLayout的内部类,该类的定义如下:

要使用新定义的CascadeLayout.LayoutParams类,还需要重写CascadeLayout类中的其他一些方法。这些方法是checkLayout-Params()、generateDefaultLayoutParams()、generateLayoutPar ams(AttributeSetattrs)和generateLayoutParams(ViewGroup.LayoutParams p)。这些方法的代码在不同ViewGroup之间往往是相同的。如果读者对这些方法的具体内容感兴趣,可以在示例代码中找到这些内容。

下一步是对onMeasure()方法编码。这是该类的核心部分。代码如下所示:

最后一步是对onLayout()方法编码,代码如下所示:

由以上代码可知,代码逻辑是非常简单的。该方法以onMeasure()方法计算出的值为参数循环调用子View的layout()方法。3.3 为子视图添加自定义属性

在最后一节,学习如何为子视图添加自定义属性。作为示例,下面将添加为特定子视图重写(override)垂直间距的方法。读者可以看到图3-3所示结果。

第一步是向attrs.xml文件中添加一个新的属性,代码如下:

因为属性名的前缀是layout_,没有包含一个视图属性,因此该属性会被添加到LayoutParams的属性表中。正如CascadeLayout类,在LayoutParams类的构造函数中读取这个新属性。源码如下:图3-3 使第一个子视图具有不同的垂直间距

verticalSpacing是一个公共字段(field成员变量),我们会在CascadeLayout类的onMeasure()方法中使用到该字段。如果子视图的LayoutParams包含verticalSpacing,就可以使用它。源码如下:

试读结束[说明:试读内容隐藏了图片]

下载完整电子书


相关推荐

最新文章


© 2020 txtepub下载