作者:mingjava 文章来源:http://www.j2medev.com/Article/ShowArticle.asp?ArticleID=859
本文内容摘自即将出版的《Symbian OS J2ME编程指南》一书,关于本书的详细介绍请访问:http://www.china-pub.com/computers/common/info.asp?id=25538 6.3 移植问题
这一节讨论一系列特定的移植问题,涉及UI(包括低级图像和高级UI组件)、可选的和第三方API以及下载大小限制。
为了创建能在一系列不同类型和功能的设备上运行的MIDlet,在MIDlet运行期间,识别设备的性能是非常有用的,这样它就能动态改变其行为,或者在提供MIDlet时,服务器能发送一个恰当的经过裁剪的JAR文件。
支持设备的运行期识别也是相当有限的:我们能使用System.getProperty()来识别JTWI或MIDP版本,并且我们可以使用Canvas.getHeight()、Canvas.getWidth()、Canvas.isDoubleBuffered,Display.isColor()和Display.numColors()来识别显示能力。
当前,当下载一个应用程序时,通常让用户点击手机上的链接来(例如,“BoyRacer for Sony Ericsson P800/P900”或“BoyRacer for Nokia 6600 or Series 60”)下载。然而,在每个HTTP处理期间,设备将自己的识别码加入用户代理字段(例如,“Sony Ericsson P900”或“Nokia 6600”),这能够被提供下载的服务器识别来发送恰当的JAR应用程序。针对设备识别的Composite Capability/Preference Profiles(CC/PP,参见www.w3.org/Mobile/CCPP)UAProf标准正在慢慢地形成,它将使提供下载的服务器能够获得一个手机的更详细的特性。
HTTP处理一个URI,它指向手机的详细信息,但是也能包含一些其他信息,这些信息能够标识出单个手机相对厂家标准可能进行了哪些修改。这就能使下载服务器为一个指定的手机动态创建一个量身定制的JAR文件。
通常,需要检查目标设备的设计标准并尽量服从这些标准。甚至开发者可能实现任何他们希望使用的低层GUI API,对用户而言,使用他们熟悉的界面会更容易。因此,对于不同的主机设备,尽可能地模拟菜单和命令的标准命名法。一些设备为用户提供一个一致的界面。例如,在Nokia手机上,右边的软键通常总是“导航”命令,如退出、后退和取消等,左边的软键用于“主动的”命令,如确定、选择和连接等。
6.3.1 低级图形内容
在游戏应用程序中,构成基本用户界面的便是图形内容。
尽管在一个游戏环境中,主要的Sprite一般都保持大小不变,但对于背景图像就不一定。背景构成了游戏的“世界”,并且随着屏幕尺寸不同而变化。例如,Nokia 6600显示像素为176×208,而Sony Ericsson P900显示像素为208×253,当显示软键盘时,尺寸变为208×173。
当UI被初始化后,需要使用Canvas.getHeight()和Canvas.getWidth()方法来查询设备屏幕的宽度和高度。这就为创建背景图像提供了足够的信息。使用TiledLayer时,我们能做以下两件事情:
· 我们能改变贴砖的大小来反映屏幕的尺寸。这最大限度地减少了对MIDlet的影响,虽然这对图形设计者增加了负担。更重要的是,游戏背景的贴砖可能变形。
· 我们能使TiledLayer更智能,在初始化时,通过查询设备屏幕尺寸,对背景作出合适的更改。新的贴砖背景的尺寸取决于单个的贴砖和屏幕尺寸。这种更好的方式允许我们调整视角来反映不同的屏幕尺寸,使MIDlet允许用户在一个较大的设备上有一个较大的游戏世界的视图。例如,一个迷宫游戏应当显示更多的迷宫。7.14节的LifeTime MIDlet就使用了这种方式,以在大屏幕设备上显示更多的游戏空间。
用于创建游戏的图像通常要根据目标手机的屏幕特性来裁剪,可能还要根据手机的内存和性能特性来裁剪。它们甚至要根据下载的JAR文件大小的限制来进行更改。因此我们需要针对一些手机采用小的黑白图像,但是对有更大处理能力的彩屏手机,(应当)采用更大的彩色图像。这需要针对每一个或者一组目标设备创建各自的JAR包。
MIDP 2.0的更有用的新特性就是游戏API。它允许通过一个包含所有帧的图像文件为一个角色或屏幕对象创建一个Sprite。在第5章的Racer MIDlet示例中,我们提供了一个4帧的序列,其中封装了动画所必需的所有帧。
Sprite的子类使用一个PNG文件初始化,并且根据自身已知的尺寸创建帧。这意味着如果屏幕尺寸改变而帧的数量不变,我们可以改变帧序列而不是改动代码,使得Sprite仍然保持比例。
我们已经讨论了改变图像以适应设备的必要性,但是Sprite可能也需要改变。如果Sprite类足够智能,能检测到它们自身的尺寸改变,那么一切将工作得很好。然而,它们可能会以不同的方式移动,这就需要改变移动的方法。Sprite间的碰撞检测也可能改变。例如,一个更小的图像可能需要一个更小的碰撞检测区。在一些情况下,使用整个图像来进行碰撞检测的处理太耗费时间,因此我们要使用defineCollisionRectangle()方法来定义一个更小的区域。Sprite大小的改变可能意味着其碰撞检测区也要随之改变。
屏幕尺寸的改变可能需要更少的Sprite的副本。可能会有更小的空间来显示敌方角色,或者那些应该出现在屏幕上的Sprite落在了屏幕外。例如,在一个典型的Space Invaders游戏中,较小的屏幕尺寸可能意味着较少的攻击玩家角色的敌人。你希望在更大的屏幕上得到更多的攻击和子弹吗?你认为在不增加游戏难度的情况下,MIDlet应该在初始化时计算出多少次攻击是合适的吗?应该隐藏更少的或更小的障碍吗?这些值可能被硬编码在Sprite类的成员变量中。考虑创建一个资源包来提供这些值,或者将它们添加到JAD文件,使MIDlet能够在启动时查询到它们,这是不是更明智?
尽可能地使用游戏动作。它提供了一个通用的游戏动作的映射,比如开火、上、下、左、右等,可以很容易地在键盘上实现,如对应2、8、4和6。一些键盘有不同的布局,比如MIDP 1.0手机Siemens SX-1,可能以不同的方式映射这些动作。甚至像Sony Ericsson P900这样主要使用基于操纵杆的设备,其操纵杆也能被用于游戏动作的向上和向下。游戏设计可能需要简化,或者可以使用可卷动的Choice列表作为游戏菜单让用户选择。
一些设备提供了持续检测一个键的状态是否为“按下”或“释放”的能力。持续检测一个键当前是否被按下使我们能给予用户“快速开火”的能力。不是所有的设备都有这个功能,因此需要注意。
6.3.2 输入方式的不同
开发者需要意识到,不同的设备有不同的输入方式。至少,他们需要编写保护式的代码以允许不同的输入方式。为一个指针设备或一个键盘设备进行测试是明智的。例如,如果一个MIDlet是针对Sony Ericsson P900的,那么需要将按钮置于屏幕上,并需要更大的图像使得用户选择时更加方便。在一个键盘设备上,例如Nokia 6600等,用户就要依赖操纵杆来导航,并且需要自动选中项目。
Sony Ericsson P900提供了一个软键盘来弥补没有键盘的问题。这对于用户的游戏会有什么影响呢?他们会仍然喜欢类似一个键盘手机上的体验吗?除了这两种输入方式外,是否应该开发一种不同的用户界面?例如,不监听左右键,MIDlet可以检测屏幕上哪一部分被手写笔按下;如果按在角色的左边或右边,角色就应该向此方向移动。在角色身上按下手写笔将引发开火。操纵杆可以配合手写笔使用。换句话说,应该试图尝试其他捕获用户输入的方式,而不是模拟键盘。
也许开发者需要问他们自己,基于指针的设备是否对另一种用户仍旧有吸引力。游戏设计者是否应该考虑充分使用设备的特性,而不是试图移植一个不适合的游戏?最好的商业决定也许不是移植所有的应用,而是为设备创建其特有的感官。
6.3.3 高级用户界面组件
使用高级UI组件(如TextField、List和Form)而不是直接绘制到一个Canvas上,这通常能提供一个可移植的UI。这些组件及其布局都是抽象的,底层设备实现处理组件在屏幕上的显示。应用程序不关心如何捕获用户输入或单个的键,也不负责定义可视外观以及导航和卷动等动作。
这对于基于信息显示的应用程序来说效果很好,因为开发者可以更关注如何在屏幕上以一致的方式组织信息。开发者基本上没有控制外观的能力,因此,UI界面保持和本地应用程序的外观一致。
高级API中的一个例外是CustomItem,它允许开发者自定义他们自己的Form对象。尽管这是一个从Item派生的高级组件,但它的表现更像一个Canvas。尽管其他高级Form对象已经实现了用户交互管理和对象间切换,但是扩展了抽象类CustomItem的类将负责实现其行为。
Sony Ericsson P900和Nokia 6600对CustomItem的实现是不同的,反映在两种手机对用户交互的不同。在Nokia 6600上扩展CustomItem并重新定义keyPressed()、keyReleased()和keyRepeated()方法,而在Sony Ericsson P900上重定义pointerPressed()、pointerDragged()和pointerReleased()方法。这样,扩展的CustomItem能在两种平台上正确表现其行为。
6.3.4 适应私有API和可选API
当前参与MIDP 2.0标准的有许多对其感兴趣的合作伙伴,像设备制造商、网络运营商和包括Symbian在内的操作系统开发商。在某些情况下,为了促进使用下一代技术和一些可预见的技术,会随设备发布其私有的API,以允许开发者能够使用这些尚未成为(或许永远不会成为)标准的API来创建更为复杂的应用程序。 例如, Nokia为广播SMS消息创建了其私有API, 且Nokia MIDP 1.0设备的另一个私有的UI API使游戏开发者能控制Canvas是否充满整个屏幕。 这些功能后来加入到了标准中。JSR 120支持SMS,并且MIDP 2.0提供了Canvas.setFullScreenMode()的方法。在这种情况下,Nokia的UI API就申明为过时的(deprecated),尽管其实现仍将确保向后兼容。
开发者应该在假定他们使用的所有类都是标准的之前,认识到目标设备的能力。应该保守地编写代码,来确保当一个API不可用时MIDlet仍然可以运行,且Mzblet可以采取合适的动作而不是异常地关闭应用程序。对开发者而言,更好的做法是,认识到设备上的库并在此新设备上发布应用程序前对应用程序的功能做出主动的决定。
然而,这使得开发者进退两难。他们仅仅使用目标设备以及适合其需求的操作吗?还是试图编写突破限制的代码来达到相同的结果?例如,是否可以改变屏幕的布局或菜单次序来适应一个较小的屏幕尺寸?
设备之间的不同之处的另一个方面是它们对多媒体的支持能力。例如,MIDP 2.0中的Media API(在第3章中讨论过)以最小的子集为多媒体提供了有限的能力。如果设备有很好的本地多媒体功能,例如,内置的摄像头和麦克风,那么,开发者应该适当地使用它们来操作多媒体数据。然而,目前,仅有一部分功能更强的手机(如Nokia 3650和Nokia 6600)完整地实现了Mobile Media API(JSR 135),它能绘画和记录媒体数据(如音频和视频重放)以及捕获照片。这个API使第5章讨论的Picture Puzzle MIDlet之类的应用程序能从内置的摄像头捕获一个图像,然后操作并存储以便将来使用。然而,这样的应用程序的实现显然被限制在这些支持MMAPI和拥有图像捕获功能(JSR 135的可选功能)的设备上。
CLDC/MIDP API的分割被普遍认为是一个严重的问题。因此,人们成立了Java无线行业技术(Java Technology for the Wireless Industry,JTWI)专家组来处理这个问题(http://jcp.org)。第3章介绍了JTWI并关注构成JTWI蓝图第一版的组成JSR。JTWI的一个目标是提供一个最小的、强迫设备必须实现的API和功能。针对JTWI平台的应用程序,开发者能确保这些应用程序可以运行在尽可能多的设备上。JTWI针对特定的组成JSR还定义了在性能和可选功能方面的最小需求。这些已在第3章详细讨论,但是这里可以列出一部分相关的示例:
· 设备应当允许最大64KB的JAR文件、最大5KB的JAD文件和30KB的持久存储空间。
· 对于图像,除支持PNG外,还添加了对JPEG文件格式的支持,以提供更大的灵活性。
· 应当采用至少125×125像素大小的屏幕,并且颜色深度达到12位。
· 运行在GSM/UMTS网络上的设备必须支持SMS Push,它与Push Registry一同工作,一旦接收到一条SMS短消息,能唤醒MIDlet。
Symbian是JSR 185专家组成员,并且从Symbian OS 8.0版开始,Symbian的Java实现是JTWI兼容的。JTWI的第一个发布版的批准在MIDP 2.0标准之后,但是许多主要的MIDP 2.0设备可以在不久的将来符合JTWI标准。
6.3.5 下载限制
Symbian系统设备如Nokia 6600和Sony Ericsson P900并不指定MIDlet的JAR文件的最大尺寸限制;相反的,JAR文件的大小受到设备上可用的持久化存储空间的大小的限制。一般的,Symbian系统设备有16MB空间,但是随着操作系统和应用程序的不断添加,大约只剩下8MB。一些设备有记忆棒和MMC卡,这样的话,当然就有非常大的存储空间。其他的考虑还包括运营商在WAP网关设置的下载限制。一个太大的应用程序不会好卖,因为没有人能够下载它!混淆(在第7章讨论)提供了一种减少JAR文件大小的方法。
进一步地分析市场,开发者应该意识到:一些设备有一个最大下载限制。Nokia Serise 40设备有最大64KB的限制,而Sony Ericsson T610允许最大60KB的JAR文件。这些能给出一些建议:最终的JAR文件应该多大尺寸才最适合移植。
当然,大小是由文件的内部内容决定的,因此,仔细考虑我们应当包含进去的内容是值得的。确实需要添加声音文件吗?例如,目标设备可能没有播放某种格式的声音的能力,或者没有绘画某种格式的图像的能力。为了移植到一个不同的设备,我们可能要扔掉这些额外的内容。在一个比较低级的设备上,播放一个声音可能对MIDlet的速度和设备内存会有意想不到的负面效果。
也许一个较小的JAR文件意味着一个较小的游戏世界。可能我们应该考虑减少供用户游戏的通关数量?
混淆可以打乱代码来防止那些喜欢偷窥的人,它还有减小最终JAR文件大小的功能,并能改善性能,尤其是对于早期的VM。一些混淆器有更高的效率并能减小更多的JAR文件大小,因此可以尝试不同的混淆器(第7章还将简洁地讨论两种可用于Sun ONE Studio Mobile Edition的混淆器)。
6.3.6 堆内存
开发者需要意识到堆内存,尤其是把应用程序移植到另一个设备上时。堆内存保存所有的运行期代码、图像和其他与MIDlet相关的对象。如果没有将其大小保持在一个限度内的话,将导致一个OutOfMemory错误,并且MIDlet将终止运行。例如,一个用贴砖填充的背景可能需要使用屏幕外缓冲来优化设备性能,此时就可能导致此类问题。
通常,Symbian系统设备并不指定堆内存的限制,以便让开发者有足够的空间使用。Nokia 6600和Sony Ericsson P900/P908都允许最大达8MB的堆内存。当然,手机的其他应用程序也共享此内存空间,并且,在任一时间,应用程序管理软件可能决定哪些能运行、哪些不能运行。开发者可以采用一些策略来最小化内存使用。Flyweight设计模式、对象工厂和对象再生都能最小化内存中对象的数量,当对象不再使用时将其释放,确保应用程序有足够的内存使用,而不是仅仅依赖垃圾收集器来管理内存。
把MIDlet移植到更小的或不同的设备可能会有一系列挑战。这些设备可能只有少得多的堆内存,开发者应该意识到这一点。重要的一点是,记住,用于创建应用程序图像的图像文件的大小在运行期间对堆内存的使用有直接的影响。一个折衷的方案可能是减少图像内容来减少整个内存的消耗,例如,通过减小Sprite中的图像质量和图像细节。
此外,较少的堆内存可能引起垃圾收集器更加频繁地运行,从而影响整个MIDlet的性能。
6.4 小结
在这一章中,我们研究了为移动设备创建灵活的和可移植的应用程序所应当运用的技术和模式,以便最大限度地提高收入。我们还研究了一些设计模式,在编写MIDP 2.0代码时,你可以使用它们来解决面临的移植问题。你需要仔细考虑用户界面,尤其是图形内容。我们还讨论了在游戏开发中使用低级API带来的一些问题。
在第7章中,我们将讨论为受限设备开发应用程序的另一个重要问题:为J2ME平台优化代码。