java 发行者 不可用_BlackBerry 应用程序开发者指南 第一卷:基础--第2章 编写BlackBerry Java应用程序...

2

第2章编写BlackBerry Java应用程序

应用程序管理

编写一个例程

重用一般代码

使用命令行

使用蓝牙开发环境

使用Eclipse开发环境

编程指南

当设备启动时,VM加载应用程序管理器,它管理在设备上所有运行的程序。对于其他Java程序,应用程序管理器的功能类似操作系统事件的中心调度员一样。

提供用户界面的应用程序扩展了net.rim.device.api.ui.UiApplication类。这个类为应用程序提供方法来注册事件监听者,管理线程以及UI组件。

没有提供用户界面的应用程序扩展了net.rim.device.api.system.Application类。

应用程序开始于main()函数。当一个程序开始时,它的main()线程调用enterEventDispatcher()来开始处理事件。这个线程运行所有绘图以及事件处理的代码,以及登等待应用程序队列里地事件。

当应用程序管理器接收到一个事件时,它将这个事件拷贝到合适的队列里,这个队列可以允许应用程序管理器指挥消息到特定的程序中。例如,前台的应用程序仅接收用户输入的消息。

扩展UiApplication基类

每个提供用户接口的应用程序扩展了UiApplication基类,UiApplication类为应用程序定义了方法来建立一个事件线程,并且显示和维护Screen对象。

定义main()

在main()中,为应用程序创建一个新的对象。调用enterEventDispatcher()使应用程序进入事件线程并且开始处理消息。

publicstaticvoidmain(String[] args) {

HelloWorld theApp =newHelloWorld();

theApp.enterEventDispatcher();

}

为你的应用程序定义缺省的构造子。缺省的构造子调用UiApplication.pushScreen()以显示当应用程序启动时出现的屏幕。在本例中,屏幕使一个新的HelloWorldScreen实例,它在下节的代码中定义:

publicHelloWorld() {

pushScreen(newHelloWorldScreen());

}

定义main屏幕

为了定义应用程序UI的主屏幕,扩展MainScreen类。MainScreen类是Screen的子类,它实现了TrackwheelListener和KeyboardListener接口,这些接口接收和响应用户交互。如果你扩展Screen类或者其子类中的一个,你并不是必须实现TrackwheelListener和KeyboardListener接口。

你的类至少应该重写2个MainScreen的方法:缺省的构造子和onClose().

在这个例子中,构造子调用了MainScreen的构造子。缺省地,MainScreen提供下列特性:

由一个Close菜单项的缺省菜单。

当你点击Close或者按Escape时,缺省的是关闭动作。为了提供客户定制行为,例如显示一个对话框提示,当用户点击Close菜单项或者按Escape按钮,重写onClose().

一个RichTextField的实例,一个可以接收焦点的只读富文本域为了得到更多关于增加UI组件到屏幕中的信息,参看40页的“提供屏幕导航”

一个Select菜单项的上下文菜单?为了得到更多信息,参看60页的“创建定制的上下文菜单“

接下来的例子创建了一个屏幕,它包含了一个富文本域。当富文本域接收到焦点时,菜单保安一个Close菜单项和一个Select上下文菜单项。

%24clip_image004.gif

例: HelloWorld.java

/**

*HelloWorld.java

*Copyright(C)2001-2005ResearchInMotionLimited.Allrightsreserved.

*/

packagecom.rim.samples.docs.helloworld;

importnet.rim.device.api.ui.*;

importnet.rim.device.api.ui.component.*;

importnet.rim.device.api.ui.container.*;

importnet.rim.device.api.system.*;

importcom.rim.samples.docs.resource.*;

publicclassHelloWorldextendsUiApplication {

publicstaticvoidmain(String[] args) {

HelloWorld theApp =newHelloWorld();

theApp.enterEventDispatcher();

}

publicHelloWorld() {

pushScreen(newHelloWorldScreen());

}

}

finalclassHelloWorldScreenextendsMainScreen {

publicHelloWorldScreen() {

super();

LabelField title =newLabelField(“HelloWorld Sample”, LabelField.ELLIPSIS

| LabelField.USE_ALL_WIDTH);

setTitle(title);

add(newRichTextField(“Hello World!”));

}

publicbooleanonClose() {

Dialog.alert(“Goodbye!”);

System.exit(0);

returntrue;

}

}

%24clip_image006.gif

抽象基类可以使你跨越多个类实现和重用一般功能。每个应用程序可以扩展单个基类。在,加入基类到一个库项目中。为每个应用程序创建一个独立的项目,定义库项目的依赖。

本指南的例程扩展了BaseApp类,它实现下面的功能:

扩展UiApplication类

实现KeyListener和TrackwheelListener接口

定义变量,例如一般的菜单项

定义一个方法创建应用程序菜单。

为菜单选择定义一个方法

定义一个抽象方法退出程序

例: BaseApp.java

/*

* * BaseApp.java

* * Copyright (C) 2001-2005 Research In Motion Limited. All rights reserved.

* */

packagecom.rim.samples.docs.baseapp;

importnet.rim.device.api.i18n.*;

importnet.rim.device.api.system.*;

importnet.rim.device.api.ui.container.*;

importnet.rim.device.api.ui.*;

importnet.rim.device.api.ui.component.*;

importcom.rim.samples.docs.resource.*;

publicabstractclassBaseApp

extendsUiApplicationimplementsBaseAppResource, KeyListener, TrackwheelListener {

privateMenuItem _closeItem;

privatestaticResourceBundle _resources =

ResourceBundle.getBundle(BUNDLE_ID, BUNDLE_NAME);

/* Constructor for the abstract base class. */

publicBaseApp() {

_closeItem =newMenuItem(_resources, MENUITEM_CLOSE, 200000, 10) {

publicvoidrun() {

onExit();

System.exit(0);

}

};

}

/* Override this method to add custom menu items. */

protectedvoidmakeMenu( Menu menu,intinstance) {

Field focus = UiApplication.getUiApplication().

getActiveScreen().getLeafFieldWithFocus();

if(focus !=null) {

ContextMenu contextMenu = focus.getContextMenu();

if( !contextMenu.isEmpty()) {

menu.add(contextMenu);

menu.addSeparator();

}

}

menu.add(_closeItem);

}

/* Invoked when the trackwheel is clicked. */

publicbooleantrackwheelClick(intstatus,inttime ) {

Menu menu =newMenu();

makeMenu( menu, 0);

menu.show();

returntrue;

}

/* Invoked when the trackwheel is released. */

publicbooleantrackwheelUnclick(intstatus,inttime ) {

returnfalse;

}

/* Invoked when the trackwheel is rolled. */

publicbooleantrackwheelRoll(intamount,intstatus,inttime) {

returnfalse;

}

publicbooleankeyChar(charkey,intstatus,inttime) {

/* Intercept the ESC key and exit the application. */

booleanretval =false;

switch(key) {

caseCharacters.ESCAPE:

onExit();

System.exit(0);

retval =true;

break;

}

returnretval;

}

/* Implementation of KeyListener.keyDown(). */

publicbooleankeyDown(intkeycode,inttime) {

returnfalse;

}

/* Implementation of KeyListener.keyRepeat(). */

publicbooleankeyRepeat(intkeycode,inttime) {

returnfalse;

}

/* Implementation of KeyListener.keyStatus(). */

publicbooleankeyStatus(intkeycode,inttime) {

returnfalse;

}

/* Implementation of KeyListener.keyUp(). */

publicbooleankeyUp(intkeycode,inttime) {

returnfalse;

}

protectedabstractvoidonExit();

}

%24clip_image006.gif

为了编写,调试和编译应用程序,使用它是的一部分。

%24clip_image008.gif注:版本4.1使用了Sun JDK 5.0

1.在,选择File菜单,点击New Workspace

2.在Workspace name域,输入一个没有文件扩展名的名字。

3.在Create in this directory域,输入一个文档。

4.点击OK.

2d130bcee228a9c606016db3e863140b.gif注:在包含工作空间的文件夹下的子目录中创建工程。

1.在的Project菜单,点击Create New Project.

2.在Project name域,输入一个没有文件扩张名的项目名称。

3.在Create project in this directory域,输入在此文件夹下创建项目的文件夹名称。

4.点击OK。

5.在工作空间文件区域里,双击项目名称来设置项目属性。

为了得到更多关于项目属性的信息,参看BlackBerry Integrated Development Environment Online Help。

2d130bcee228a9c606016db3e863140b.gif注:保存源文件到和项目文件相同的文件夹下。和所有Java程序一样,为符合你的类使用的包层次关系的源代码创建文件结构,

1.在的File菜单,点击New。

2.在Source file name域,输入一个带.java文件扩展的文件名。

3.在Create source file in this directory域,输入文件夹名。

4.点击OK。

5.在编辑器区域,右击文件,然后点击Insert into project.

6.选择一个项目。

7.点击OK。

和集成源文件管理工具

你可以通过不同的源文件控制程序来使用。允许你为源文件控制程序设置“check out”, “add new file”和“revert”选项。在你为某一特定的源文件控制程序配置好选项后,可以自动check out文件,运行预先设置的命令,恢复改变,以及增加新创建的文件到源文件控制程序里。

1.在的File菜单,点击Edit->Preferences.

2.点击Source Control标签。

3.点击Check out标签。

4.在Check out域,输入命令以能打开一个文件来编辑。例如输入:

p4 edit %1

2d130bcee228a9c606016db3e863140b.gif注:%1参数代表了名称和一个文件的绝对路径。例如:对于一个在c:\mypath的foo.java文件,当执行命令checkout %1,时,实际上运行命令checkout c:\mypath\foo.java。

5.点击Add file标签。

6.在Add new file域,输入命令以增加一个新的文件到源文件控制程序中。例如输入:

p4 add %1

7.点击 Revert file标签.

8.在Revert changes域,输入命令撤销一个源文件控制程序中的文件。例如输入:

p4 revert %1

9.-->单击OK。

当你编译项目时,编译你的源文件到Java字节编码(Bytecode),进行预验证,然后将类打包为一个.cod文件。

2d130bcee228a9c606016db3e863140b.gif注:在Java ME中,字节编码验证分为2个步骤。已经编译的代码在它加载到设备之前预先验证,因此类加载时设备仅必须进行基本的验证。在编译项目时自动进行预验证。

当你编译一个项目时,如果需要,也编译项目依赖的任何库。

动作

过程

附加信息

编译所有项目

>在Build菜单,点击Build All

为了排除一个项目,设置项目属性。

编译所有活动的项目

>在Build菜单,点击Build。

在工作空间,活动的项目名是加粗的。为了改变哪些项目是活动的,在Project菜单,点击Set Active Projects.

编译单一项目

选择一个项目

在Build菜单,点击Build Selected。

―――

创建一个工作空间makefile

>在Build菜单,点击Generate Makefile and Resource.

―――

缺省的,已经编译的.cod文件使用项目名。为了改变这个名字,双击项目文件,点击Build标签,输入output file name(输出文件名)。

混淆应用程序

和传统的编译器不一样,平台的编译器因为受限的无线环境而优化了。在这里无线环境的目标是最小化应用程序的大小。作为结果的.cod文件提供了大量的类似于其他真正混淆包的混淆服务,以致能减小.cod文件本身的大小。例如,下面的信息将从.cod文件中移除:

所有调试的信息

本地变量名

源代码的行数

私有方法和成员名

同样,RIM相信没有必要为应用程序提供混淆,除了已经存在的平台编译的所有应用程序缺省提供的混淆。事实上,RIM没有对自己的产品进行任何额外的混淆。

对通过第三方工具混淆的支持没有集成到同样,需要一个命令行过程来混淆.cod文件供设备上使用。

混淆一个.cod文件

1.在,创建应用程序

2d130bcee228a9c606016db3e863140b.gif提示:在这个过程中将项目文件放到一个独立的目录中。

2.创建临时的目录

3.将创建的jar文件拷贝到一个临时目录。

4.释放.jar文件的内容到一个临时目录。例如,在命令窗口输入下面的命令:*jar xvf SampleApplication.jar

5.删除释放为.jar文件部分的.cod文件。

6.删除.jar文件

7.混淆在临时目录下包含的类文件。

8.使用下面的命令对临时目录的内容运行预验证工具:

*preverify.exe -verbose -d . -classpath ..\lib\net_rim_api.jar;

9.在已混淆(和预验证)的类文件上运行rapc来创建一个.cod文件。使用下面的命令:

*rapc.exe -verbose import=..\lib\net_rim_api.jar listing=SampleApplication.lst codename=SampleApplication SampleApplication.rapc C:\yourTempDir\SampleApplication.class

生成API文档

使用一个宏给代码加入注释。

一旦启用这个功能,如果你在一个函数声明前的任何一行输入/**,生成下面的注释:

/**

* .

* @param menu.

* @param instance .

* @return.

*/

如果你在其他行输入/**, the BlackBerry IDE生成下面的注释::

/**

* .

*/

预先加载.作为查询字符串,再查询第一个实例,然后选择这个实例,这个特性允许你输入描述,然后按F3转移到后面的参数。

因为javadocs宏依赖于分解浏览的信息,仅在成功完成一个编译后增加javadocs。如果你的文件包含一个语法错误,并且在上面你正试着插入注释,宏不会得到函数声明。

增加一个新的编辑器宏

1.在Edit菜单,点击Preferences。

2.点击Editor标签。

3.点击Macros按钮。

4.从When I type下拉列表中,选择/**.

5.在Replace it with文本框里,输入@javadoc.

6.在同一行或者每个函数声明的前一行输入/**。例如,在下面的代码段,在单词”protected”开头的插入点输入/**.

/** protected int makeMenu(Menu menu, int instance) { ... }

包含一个命令行编译器RAPC。RAPC编译.java和.jar文件到可以运行在设备模拟器或者加载到设备上的.cod文件。

Rapc.exe在安装目录下的Bin下面。

RAPC接收下面的命令行选项。

选项

描述

import

指明RIM API和其他依赖的库

codename

指明应用程序名(这典型是.jar文件名)

midlet

指明应用程序是否是MIDlet

jad

指明JAD文件名

\filename_1.java[附加.java文件如果需要>]

指明.java文件名,如果正在编译java文件。

\JAR_filename.jar

指明.jar文件名,如果正在编译一个,jar文件。

为了利用狼牙开发环境使用设备模拟器,你需要从CSR(参看http://www.btdesigner.com/devcasira.htm)得到普通开发系统。

2.在主菜单,选择Edit>Preferences.

3.选择Simulator标签。

4.选择Ports标签。

5.在Communication port type域,选择合适的端口类型(参看Casira Endpoint文档)。

6.在Serial Port域,输入端口信息。

7.点击OK。

Java调试有线协议(Java Debug Wire Protocol, JDWP)的程序为模拟器提供一个接口。当你启动JDWP时,你可以使用第三方集成的开发环境。

启动JDWP

>点击开始>程序>Research In Motion>JDWP.

2d130bcee228a9c606016db3e863140b.gif注:在启动JDWP之前,你必须从启动设备模拟器至少一次。你仅需要启动JDWP一次。为了启动一个设备模拟器,在Eclipse开发环境中,点击Run>Debug.

连接Eclipse开发环境

2d130bcee228a9c606016db3e863140b.gif注:在完成本节的任务之前,安装和配置Eclipse开发环境。

完成下面的步骤:

1.扩展Sun JRE。

2.加入API文档。

3.设置Builder。

4.设置项目变量。

扩展Sun JRE

1.建立你的工作空间和项目。

2.启动Eclipse平台。

3.在Eclipse任务栏,点击Window>Preferences.

4.扩展Java项。

5.选择Installed JREs。

6.点击Add。

7.在Add JRE的窗口的JRE type域,选择Standard VM。

8.在JRE name域,为JRE输入一个名字。

9.在JRE home directory域,输入Sun JRE的位置。例如:

C:\Java\jdk1.5.0_02\jre.

10.务必使Use default system libraries域没有选。

11.点击Add External JARs。

12.浏览你的安装目录下的lib目录,例如:

C:\Program Files\Research In Motion\BlackBerry JDE 4.1.0\lib

13.选择net_rim_api.jar.

14.点击Open。

加入API文档

1.加入RIM.jar到你的项目。

2.在Add JRE窗口,扩展net_rim_api.jar文件。

3.选择Javadoc location.

4.点击Edit。

5.点击Browser。

6.找到找到你的目录下的docs\api目录。例如:

C:\Program Files\Research In Motion\BlackBerry JDE 4.1.0\docs\api

7.点击OK。

8.点击OK。

9.在Installed JREs窗口,选择新创建的JRE,缺省的是RIM JVM。

10.在Add JRE窗口,点击OK。

设置Builder

1.在Eclipse任务栏,点击Project>Properties.

2.选择Builders。

3.点击New。

4.在Choose configuration type窗口,选择Program.

5.点击OK。

6.在New_Builder窗口属性的Name域,为你的Builder输入一个名字。

7.在Location域,点击Browser File System。

8.找到你的目录下的Bin目录,例如:

C:\Program Files\Research In Motion\BlackBerry JDE 4.1.0\bin

9.选择rapc.exe文件。

10.点击Open。

设置项目变量

1.在Working Directory域,点击Variables。

2.在Select Variable窗口,选择build project.

3.点击OK。

4.在Arguments域,输入:

-quiet [desired space separated java, class, jar, or jad files] import=”C\Program Files\Research In Motion\BlackBerry JDE 4.1.0\lib\net_rim_api.jar” codename=C:\Development\ProjectName

例如:

-quiet C:\Development\TestProject\*.java import=”C:\Program Files\Research In Motion\BlackBerry JDE 4.1.0\lib\net_rim_api.jar” codename=C:\Development\TestProject.

5.点击OK。

6.在New_Builder窗口属性里,点击Build Options标签。

7.在Run the builder部分,验证下面的选项是否选择了。

After a“Clean”

During manual builds

During auto builds

8.点击OK。

9.在属性窗口,点击OK。

2d130bcee228a9c606016db3e863140b.gif注:RAPC不支持通配符,如果输入的路径发生错误,使用空格分隔文件列。例如将C:\Development\TestProject\*.java代替为

C:\Development\A.java C:\Development\B.java.

当在Eclipse开发环境里调试时,为了阻止连接超时,为正在调试的程序设置超时连接值。

1.在Eclipse的任务栏,点击Windows>Preferences.

2.扩展Java项。

3.选择Debug。

4.在Communication部分的Debugger timeout域,输入值。

5.在Launch timeout域输入值。

2d130bcee228a9c606016db3e863140b.gif注:你在Debugger timeout和Launch timeout设置的值依赖你的计算机处理速度。如果设置这些域之后连接问题继续出现,增加超时的值。

使用Eclipse开发环境进行调试

1.在Eclipse点击Run>Debug.

2.选择Remote Java Application.

3.点击New。

4.点击Source标签。

5.确认你的程序是否列出。

6.点击Close。

7.打开JDWP程序,为了得到更多信息,参看27页的“启动JDWP“。

8.在Eclipse任务栏,点击Run>Debug.

9.在Remote Java Application项下面,选择一个应用程序。

10.点击Debug。

2d130bcee228a9c606016db3e863140b.gif注:如果出现下面的错误信息:“Failed to connect to remote VM. Connection timed out”,增加调试超时时间。为得到更多信息参看29页的”设置连接时间”.

使用本地变量

不管什么时候,尽量使用本地变量。访问本地变量比访问类的成员高效。

使用速记判断Boolean条件

为了代替第一个例子中没有必要的判断Boolean条件,使用第二个例子中的速记。最后编译的代码会更短:

if( boolean_expression ==true) {

returntrue;

}

else{

returnfalse;

}

// Do this

return( boolean_expression );

使类为final

当你创建一个代码库时,如果你知道他们永远不会被扩展,那么将他们标记为final。final关键字的出现允许编译器生成更高效的代码。

2d130bcee228a9c606016db3e863140b.gif注:缺省,编译器标记你应用程序.cod文件中不会扩展的类为final。

使用int代替long

在Java中,一个long代表的是64位的整数。因为设备使用的是一个32位的处理器,如果你是用int代替long,操作将会快2-4倍。

避免垃圾回收

避免调用System.gc()进行垃圾回收。这个操作会占用许多时间,特别是在内存受限的设备上。让虚拟机进行垃圾回收。

对字符串使用静态变量

当定义String类型的静态字段(也成类字段),可以用静态变量(非final)代替常量(final)加快程序速度。反之,对于原始数据类型,例如int,也成立。

例如,你可能创建一个如下的String对象:

privatestaticfinalString x ="example";

对于这个静态常量(由final关键字标识),你使用常量的每个时候都会创建一个临时的String对象。在字节代码中,编译器去掉”x”,代替它的是字符串“example”,以致每次引用”x”时VM都会进行一次哈希表查询。

相比之下,度于静态变量(非final关键字),字符串只创建一次。仅当初始化“x”时,VM才进行哈希表查询。

2d130bcee228a9c606016db3e863140b.gif注:你可以使用公共常量(也就是final字段),但是标记变量为私有。

避免String(String)的构造子

避免使用java.lang.String(String)构造子,因为它创建了一个没有必要的String对象,这个对象是作为参数提供的一个字符串的拷贝。因为String对象创建后不可以修改,所以拷贝典型没有必要。

2d130bcee228a9c606016db3e863140b.gif注:当使用字符串构造子时,编译器会由警告。

String str =newString("abc");//避免.

String str =newString("found "+ n +" items");//避免.

在Java程序里,每个引用的字符串都作为一个java.lang.String类的对象。换言之,你可以编写如下面的代码来创建一个String。

String str ="abc";//建议.

String str ="found "+ n +" items";//建议.

编写有效的循环

在一个循环外考虑循环不变的代码。

//避免

for(inti = 0; i < vector.size(); i++ ) {

...

}

在这个实现中,在每次的迭代中vector.size()被调用,这是低效的。如果你的容器可能不止一个元素,将容器的大小赋值给本地变量。下面的代码移除了循环不变的代码:

//建议

intsize = vector.size();

for(inti = 0; i < size; ++i ) {

...

}

另外,如果你迭代的项的顺序并不重要,你可以向后迭代来避免栈上多余的本地变量,并且可以使比较更加快速。

for(inti = vector.size() - 1; i >= 0; --i ) {

...

}

优化子表达式

假如你使用相同的表达式2次,不要依赖编译器为你优化。使用本地变量,如下代码:

one( i+1 ); two( i+1 );// Avoid.

inttmp = i+1; one( tmp ); two( tmp );// Prefer.

优化除法操作

除法操作在设备上可能慢,因为处理器没有硬件触发指令。

在你的代码中,当一个正数除以2时,使用向右移一位(>>1)代替.仅当你知道你正在处理的正数时使用“向右移位”(>>).

midpoint = width / 2;// Avoid.

int= width >> 1;// Prefer.

避免java.util.Enumeration

避免使用java.util.Enumeration对象,除非你想隐藏数据(换句话说,为了返回一个数据的枚举代替数据本身。

// Avoid.

for(Enumeration e = v.elements(); e.hasMoreElements();) {

o = e.nextElement();

...

}

为一个Enumeration对象请求一个向量或者哈希表速度慢,并且创建了不必要的垃圾。代替它的是,迭代元素本身,如下面的例子:

// Prefer.

for(inti = v.size() - 1; i >=0; --i ) {

o = v.elementAt( i );

...

}

如果向量可能被其他线程修改,同步迭代,如下例子所示:

synchronized( v ) {

for(inti = v.size() - 1; i >=0; --i ) {

o = v.elementAt( i );

...

}

}

2d130bcee228a9c606016db3e863140b.gif注:Java SE使用一个Iterator对象实现类似的功能,但是iterator在Java ME不可用。

使用instanceof进行转型

使用instanceof代替捕捉一个ClassCastException异常来判断转型是否成功。

// Avoid.

try

{

(String)x.whatever();

}

catch( ClassCastException e ) {

...

}

// Prefer.

if( xinstanceofString ) {

(String)x.whatever();

}

else{

...

}

使用instanceof比用try/catch要快。当转型失败发生异常时才使用try/catch。

在紧跟由一个instanceof检查的条件语句的第一个代码块里,编译器和虚拟机被优化为仅对一个类检查。在由一个instanceof检查的条件语句后面的转型利用了这个优化。

例如,编译器可以优化第一个例子,但是第二个不能:

// Prefer.

if( ainstanceof ) {

instance = ()a;

x.method(instance);

instance.method(x, y, z);

}

// Avoid.

if( ainstanceof ) {

x.method( ()a );

}

使用instanceof判断条件

为了编写较小而快的代码,如果使用instanceof判断条件,不要显式判断一个变量是否为null。当”e”为null时,表达式e instanceof 判断为false。

// Avoid.

if( e !=null&& einstanceofExampleClass ) {

if( e ==null|| ! ( einstanceofExampleClass)

// Prefer.

if( einstanceofExampleClass ) { ... }

if( ! ( einstanceofExampleClass ) ) { ... }

避免使用StringBuffer.append(StringBuffer)

CLDC不包含StringBuilder.append(StringBuilder)方法。采用将一个string buffer加到另一个的方法会创建一个String的中间对象。代替它的是,应用程序可以使用net.rim.device.api.util.StringUtilities.append( StringBuffer dst, StringBuffer src[, int offset, int length ] ).

// Avoid.

publicsynchronizedStringBuffer append(Object obj) {

returnappend(String.valueOf(obj));

}

// Prefer.

publicsynchronizedStringBuffer append(Object obj) {

if(objinstanceofStringBuffer) {

StringBuffer sb = (StringBuffer)obj;

net.rim.device.api.util.StringUtilities.append(this, sb, 0, sb )

returnthis;

}

returnappend(String.valueOf(obj));

}

当编写应用程序时可以采用下面的指南来减小编译后代码的大小。

设置适合的访问方式

当你创建代码库时,为字段和方法使用合适的访问权限可以显著减小编译后代码的大小。特殊的是,完成以下操作:

l不管什么时候,只要可能就将字段声明为private。除了好的编码实践外,这可以使编译器优化.cod文件。

l当可能时,使用缺省(包)的访问方式来代替public访问(也就是,忽略public和protected关键字)

避免创建接口

当创建API库时,避免创建接口,除非你预知API的多个实现。接口会产生更大更慢的代码。

使用内部的静态类

当创建一个内部的类隐藏一个在其他类里的类时,但是内部类没有引用外部类对象,声明这个内部类为static。这个操作压缩了对外部类引用的创建。

例如,下面的代码需要一个对外部类对象的引用。

// Avoid.

classouter {

inti;

classinner {

inner() {}

intexample() {returni; }

}

}

比较而言,下面的代码仅仅定义了内部类名的范围:

// Prefer.

classouter {

staticclassinner {

...

}

}

前一个例子是下面的缩写版本:

classouter {

...

}

classouter$inner {

...

}

当在内部类的方法里需要访问外部类数据时,仅仅使用一个非静态的内部类。如果为命名范围使用一个类,那么使这个类为static。

避免没有必要的初始化

在类里避免没有必要的字段初始化,这些类里,字段有缺省值。如果在一个类里没有初始化一个字段,它会自动使用下面的缺省值初始化字段。

l对象引用初始化为null

lint,byte或long初始化为0

lboolean初始化为false

例如,下面的代码段没有不同:

// Avoid.

classBadExample {

privateintfieldsCount= 0;// Avoid.

privateField _fieldWithFocus =null;// Avoid.

privateboolean_validLayout=false;// Avoid.

}

// Prefer.

classBetterExample {

privateintfieldsCount;// Prefer.

privateField _fieldWithFocus;// Prefer.

privateboolean_validLayout;// Prefer.

}

%24clip_image014.gif注:在一个方法里,必须显式初始化本地变量。

导入单独的类

一个应用程序仅使用了来自一个包的少量的类,这个程序应该导入单独的类,而不是整个库。

// Avoid.

importnet.rim.blackberry.api.browser.*;

// Prefer.

importnet.rim.blackberry.api.browser.Browser;

在对时间敏感的应用程序里,不要为任何事物依赖时间区域,除了显示本地时间给用户。

设备操作系统从January 1, 1970 (UTC)的午夜以毫秒来计算绝对时间。时间一般以CPU周期或毫秒来计量的。

系统时间区域改变

如果因为性能原因正在缓存对时间敏感的对象,那么记住设备上的系统时间区域可能会改变。

当时间区域改变时,系统会发送一个全局的事件消息给应用程序。GlobalEventListener的实现,包括eventOccurred(),会接受这个事件。利用invoking Application.addGlobalEventListener()注册你的实现。

publicvoideventOccurred(longguid,intdata0,intdata1, Object object0,Object object1 ) {

if( guid == DateTimeUtilities.GUID_TIMEZONE_CHANGED ) {

_cal.setTimeZone( TimeZone.getDefault() );

}

}

决定手持设备上的网络时间

调用RadioInfo.GetNetworkTime(long deviceTime)得到以毫秒计量的对应网络报告时间,然后调整本地时间。deviceTime参数代表现在的毫秒级时间。

使用多线程

有效的利用操作系统多线程的能力。特殊地,为网络连接或长操作(大于0.1秒)创建线程。为监听者使用背后(Background)线程,或者当程序启动时使用在背后运行地其他进程。

最小化内存地使用

为了最小化运行时内存,使用下面地指南:

使用原始类型(如int或Boolean)代替对象(如String或Integer)。

不要全部依赖垃圾回收。避免快速地创建多个对象。当完成使用他们时,将对象引用设置为null。尽可能重用对象。

将大地操作一到Server上,例如,在发送数据到设备之前,完成对数据地过滤或排序。

避免返回null

如果你正在编写一个公共地方法返回一个对象,仅在下面地条件下它可以返回一个null:

在正常地程序运行期间,null对象时期望的。

Javadoc @return参数描述了null是一个可能的返回值。

如果一个null返回值不是正常期望的,那么程序将抛出一个合适的异常强迫调用者显式的处理这个问题。调用者不期望检验一个null的返回值,除非文档说明了。

避免传递null给方法

不要传递一个null参数给API方法,除非API引用显式说明了方法支持他们。

小心传递null参数给构造子

当传递null参数给构造子时,为了避免混淆,将null转化为合适的对象:

new someObject ( (someObject)null );

如果一个类有两个或多个构造子,传递null参数可能不会唯一识别哪一个构造子将会使用。结果编译器会报错。在API参考里,并不是所有的构造子都会出现,因为有些构造子仅供内部使用。

通过转化null为合适的对象,你可以明确指明编译器会使用哪一个构造子。如果后续的API发行版本增加了新的构造子,它也可向前兼容。

使用long标记唯一标志符

使用一个long的标志符代替String标志符来标记唯一的常数,如GUID,哈希表键值,以及状态或上下文标志。

对于跨越第三方应用程序的标志符,为了保留其独立性,使用基于string生成的哈希生成的键值。在输入字符串里,包含了足够的信息提供唯一性。例如,使用一个完全信任的包名,如com.rim.samples.docs.helloworld。

转化一个string为long

1.在文本编辑器里,输入一个字符串。

2.选择字符串。

3.右击字符串。

4.选择Convert”String” to Long.

正确退出应用程序

在调用System.exit(int status)之前,你的程序应该完成任何清理,例如移除在运行时存储的程序不在需要的对象。

打印栈跟踪(Stack trace)

当VM发现代码使用catch(Exception e)捕获异常时,VM优化为排除栈跟踪。如果捕获到Throwable,它不会排除栈跟踪。

例如,下面的代码不会排除栈跟踪:

catch(IOException e) {

e.printStackTrace()

}

为了打印栈跟踪,编写类似下面的代码:

catch(Throwable t) {

t.printStackTrace();

}

当你调试时为了查看栈跟踪,捕获一个Throwable实例。

Last Updated:2007-01-05

Last Updated:2006-12-30

Last Updated:2006-03-24

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值